6781363: New I/O: Update socket-channel API to jsr203/nio2-b99
authoralanb
Sun, 15 Feb 2009 12:25:54 +0000
changeset 2057 3acf8e5e2ca0
parent 2056 115e09b7a004
child 2058 577525f89bd4
6781363: New I/O: Update socket-channel API to jsr203/nio2-b99 4313887: New I/O: Improved filesystem interface 4607272: New I/O: Support asynchronous I/O Reviewed-by: sherman, chegar
jdk/make/docs/CORE_PKGS.gmk
jdk/make/docs/NON_CORE_PKGS.gmk
jdk/make/java/nio/Exportedfiles.gmk
jdk/make/java/nio/FILES_c.gmk
jdk/make/java/nio/FILES_java.gmk
jdk/make/java/nio/Makefile
jdk/make/java/nio/mapfile-linux
jdk/make/java/nio/mapfile-solaris
jdk/make/mksample/nio/Makefile
jdk/make/mksample/nio/file/Makefile
jdk/src/share/classes/com/sun/nio/file/ExtendedCopyOption.java
jdk/src/share/classes/com/sun/nio/file/ExtendedOpenOption.java
jdk/src/share/classes/com/sun/nio/file/ExtendedWatchEventModifier.java
jdk/src/share/classes/com/sun/nio/file/SensitivityWatchEventModifier.java
jdk/src/share/classes/java/io/File.java
jdk/src/share/classes/java/io/FilePermission.java
jdk/src/share/classes/java/net/StandardProtocolFamily.java
jdk/src/share/classes/java/net/StandardSocketOption.java
jdk/src/share/classes/java/nio/channels/AsynchronousByteChannel.java
jdk/src/share/classes/java/nio/channels/AsynchronousChannel.java
jdk/src/share/classes/java/nio/channels/AsynchronousChannelGroup.java
jdk/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java
jdk/src/share/classes/java/nio/channels/AsynchronousFileChannel.java
jdk/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java
jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java
jdk/src/share/classes/java/nio/channels/Channels.java
jdk/src/share/classes/java/nio/channels/CompletionHandler.java
jdk/src/share/classes/java/nio/channels/DatagramChannel.java
jdk/src/share/classes/java/nio/channels/FileChannel.java
jdk/src/share/classes/java/nio/channels/FileLock.java
jdk/src/share/classes/java/nio/channels/MembershipKey.java
jdk/src/share/classes/java/nio/channels/MulticastChannel.java
jdk/src/share/classes/java/nio/channels/NetworkChannel.java
jdk/src/share/classes/java/nio/channels/SeekableByteChannel.java
jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java
jdk/src/share/classes/java/nio/channels/SocketChannel.java
jdk/src/share/classes/java/nio/channels/exceptions
jdk/src/share/classes/java/nio/channels/package-info.java
jdk/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java
jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java
jdk/src/share/classes/java/nio/channels/spi/package.html
jdk/src/share/classes/java/nio/file/AccessDeniedException.java
jdk/src/share/classes/java/nio/file/AccessMode.java
jdk/src/share/classes/java/nio/file/AtomicMoveNotSupportedException.java
jdk/src/share/classes/java/nio/file/ClosedDirectoryStreamException.java
jdk/src/share/classes/java/nio/file/ClosedFileSystemException.java
jdk/src/share/classes/java/nio/file/ClosedWatchServiceException.java
jdk/src/share/classes/java/nio/file/CopyOption.java
jdk/src/share/classes/java/nio/file/DirectoryNotEmptyException.java
jdk/src/share/classes/java/nio/file/DirectoryStream.java
jdk/src/share/classes/java/nio/file/DirectoryStreamFilters.java
jdk/src/share/classes/java/nio/file/FileAction.java
jdk/src/share/classes/java/nio/file/FileAlreadyExistsException.java
jdk/src/share/classes/java/nio/file/FileRef.java
jdk/src/share/classes/java/nio/file/FileStore.java
jdk/src/share/classes/java/nio/file/FileSystem.java
jdk/src/share/classes/java/nio/file/FileSystemAlreadyExistsException.java
jdk/src/share/classes/java/nio/file/FileSystemException.java
jdk/src/share/classes/java/nio/file/FileSystemNotFoundException.java
jdk/src/share/classes/java/nio/file/FileSystems.java
jdk/src/share/classes/java/nio/file/FileTreeWalker.java
jdk/src/share/classes/java/nio/file/FileVisitOption.java
jdk/src/share/classes/java/nio/file/FileVisitResult.java
jdk/src/share/classes/java/nio/file/FileVisitor.java
jdk/src/share/classes/java/nio/file/Files.java
jdk/src/share/classes/java/nio/file/InvalidPathException.java
jdk/src/share/classes/java/nio/file/LinkOption.java
jdk/src/share/classes/java/nio/file/LinkPermission.java
jdk/src/share/classes/java/nio/file/NoSuchFileException.java
jdk/src/share/classes/java/nio/file/NotDirectoryException.java
jdk/src/share/classes/java/nio/file/NotLinkException.java
jdk/src/share/classes/java/nio/file/OpenOption.java
jdk/src/share/classes/java/nio/file/Path.java
jdk/src/share/classes/java/nio/file/PathMatcher.java
jdk/src/share/classes/java/nio/file/Paths.java
jdk/src/share/classes/java/nio/file/ProviderMismatchException.java
jdk/src/share/classes/java/nio/file/ProviderNotFoundException.java
jdk/src/share/classes/java/nio/file/ReadOnlyFileSystemException.java
jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java
jdk/src/share/classes/java/nio/file/SimpleFileVisitor.java
jdk/src/share/classes/java/nio/file/StandardCopyOption.java
jdk/src/share/classes/java/nio/file/StandardOpenOption.java
jdk/src/share/classes/java/nio/file/StandardWatchEventKind.java
jdk/src/share/classes/java/nio/file/WatchEvent.java
jdk/src/share/classes/java/nio/file/WatchKey.java
jdk/src/share/classes/java/nio/file/WatchService.java
jdk/src/share/classes/java/nio/file/Watchable.java
jdk/src/share/classes/java/nio/file/attribute/AclEntry.java
jdk/src/share/classes/java/nio/file/attribute/AclEntryFlag.java
jdk/src/share/classes/java/nio/file/attribute/AclEntryPermission.java
jdk/src/share/classes/java/nio/file/attribute/AclEntryType.java
jdk/src/share/classes/java/nio/file/attribute/AclFileAttributeView.java
jdk/src/share/classes/java/nio/file/attribute/AttributeView.java
jdk/src/share/classes/java/nio/file/attribute/Attributes.java
jdk/src/share/classes/java/nio/file/attribute/BasicFileAttributeView.java
jdk/src/share/classes/java/nio/file/attribute/BasicFileAttributes.java
jdk/src/share/classes/java/nio/file/attribute/DosFileAttributeView.java
jdk/src/share/classes/java/nio/file/attribute/DosFileAttributes.java
jdk/src/share/classes/java/nio/file/attribute/FileAttribute.java
jdk/src/share/classes/java/nio/file/attribute/FileAttributeView.java
jdk/src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java
jdk/src/share/classes/java/nio/file/attribute/FileStoreAttributeView.java
jdk/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributeView.java
jdk/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributes.java
jdk/src/share/classes/java/nio/file/attribute/GroupPrincipal.java
jdk/src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java
jdk/src/share/classes/java/nio/file/attribute/PosixFileAttributes.java
jdk/src/share/classes/java/nio/file/attribute/PosixFilePermission.java
jdk/src/share/classes/java/nio/file/attribute/PosixFilePermissions.java
jdk/src/share/classes/java/nio/file/attribute/UserDefinedFileAttributeView.java
jdk/src/share/classes/java/nio/file/attribute/UserPrincipal.java
jdk/src/share/classes/java/nio/file/attribute/UserPrincipalLookupService.java
jdk/src/share/classes/java/nio/file/attribute/UserPrincipalNotFoundException.java
jdk/src/share/classes/java/nio/file/attribute/package-info.java
jdk/src/share/classes/java/nio/file/package-info.java
jdk/src/share/classes/java/nio/file/spi/AbstractPath.java
jdk/src/share/classes/java/nio/file/spi/FileSystemProvider.java
jdk/src/share/classes/java/nio/file/spi/FileTypeDetector.java
jdk/src/share/classes/java/nio/file/spi/package-info.java
jdk/src/share/classes/java/util/Scanner.java
jdk/src/share/classes/sun/nio/ch/AbstractFuture.java
jdk/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java
jdk/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java
jdk/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java
jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java
jdk/src/share/classes/sun/nio/ch/Cancellable.java
jdk/src/share/classes/sun/nio/ch/CompletedFuture.java
jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
jdk/src/share/classes/sun/nio/ch/ExtendedSocketOption.java
jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java
jdk/src/share/classes/sun/nio/ch/FileDispatcher.java
jdk/src/share/classes/sun/nio/ch/FileLockImpl.java
jdk/src/share/classes/sun/nio/ch/FileLockTable.java
jdk/src/share/classes/sun/nio/ch/Groupable.java
jdk/src/share/classes/sun/nio/ch/IOUtil.java
jdk/src/share/classes/sun/nio/ch/Invoker.java
jdk/src/share/classes/sun/nio/ch/MembershipKeyImpl.java
jdk/src/share/classes/sun/nio/ch/MembershipRegistry.java
jdk/src/share/classes/sun/nio/ch/NativeThreadSet.java
jdk/src/share/classes/sun/nio/ch/Net.java
jdk/src/share/classes/sun/nio/ch/OptionKey.java
jdk/src/share/classes/sun/nio/ch/PendingFuture.java
jdk/src/share/classes/sun/nio/ch/Reflect.java
jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java
jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java
jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java
jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java
jdk/src/share/classes/sun/nio/ch/ThreadPool.java
jdk/src/share/classes/sun/nio/ch/Util.java
jdk/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java
jdk/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java
jdk/src/share/classes/sun/nio/fs/AbstractFileStoreSpaceAttributeView.java
jdk/src/share/classes/sun/nio/fs/AbstractFileTypeDetector.java
jdk/src/share/classes/sun/nio/fs/AbstractPoller.java
jdk/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java
jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java
jdk/src/share/classes/sun/nio/fs/AbstractWatchService.java
jdk/src/share/classes/sun/nio/fs/Cancellable.java
jdk/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java
jdk/src/share/classes/sun/nio/fs/Globs.java
jdk/src/share/classes/sun/nio/fs/MimeType.java
jdk/src/share/classes/sun/nio/fs/NativeBuffer.java
jdk/src/share/classes/sun/nio/fs/NativeBuffers.java
jdk/src/share/classes/sun/nio/fs/PollingWatchService.java
jdk/src/share/classes/sun/nio/fs/Reflect.java
jdk/src/share/classes/sun/security/util/SecurityConstants.java
jdk/src/share/native/sun/nio/ch/genSocketOptionRegistry.c
jdk/src/share/sample/nio/file/AclEdit.java
jdk/src/share/sample/nio/file/Chmod.java
jdk/src/share/sample/nio/file/Copy.java
jdk/src/share/sample/nio/file/DiskUsage.java
jdk/src/share/sample/nio/file/FileType.java
jdk/src/share/sample/nio/file/WatchDir.java
jdk/src/share/sample/nio/file/Xdd.java
jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java
jdk/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java
jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java
jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java
jdk/src/solaris/classes/sun/nio/ch/EPoll.java
jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java
jdk/src/solaris/classes/sun/nio/ch/EPollPort.java
jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java
jdk/src/solaris/classes/sun/nio/ch/FileDispatcher.java
jdk/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java
jdk/src/solaris/classes/sun/nio/ch/LinuxAsynchronousChannelProvider.java
jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java
jdk/src/solaris/classes/sun/nio/ch/Port.java
jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java
jdk/src/solaris/classes/sun/nio/ch/SocketDispatcher.java
jdk/src/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java
jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java
jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java
jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java
jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java
jdk/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java
jdk/src/solaris/classes/sun/nio/fs/DefaultFileTypeDetector.java
jdk/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java
jdk/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java
jdk/src/solaris/classes/sun/nio/fs/LinuxFileStore.java
jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java
jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystemProvider.java
jdk/src/solaris/classes/sun/nio/fs/LinuxNativeDispatcher.java
jdk/src/solaris/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java
jdk/src/solaris/classes/sun/nio/fs/LinuxWatchService.java
jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java
jdk/src/solaris/classes/sun/nio/fs/SolarisFileStore.java
jdk/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java
jdk/src/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java
jdk/src/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java
jdk/src/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java
jdk/src/solaris/classes/sun/nio/fs/SolarisWatchService.java
jdk/src/solaris/classes/sun/nio/fs/UnixChannelFactory.java
jdk/src/solaris/classes/sun/nio/fs/UnixCopyFile.java
jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java
jdk/src/solaris/classes/sun/nio/fs/UnixException.java
jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java
jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java
jdk/src/solaris/classes/sun/nio/fs/UnixFileKey.java
jdk/src/solaris/classes/sun/nio/fs/UnixFileModeAttribute.java
jdk/src/solaris/classes/sun/nio/fs/UnixFileStore.java
jdk/src/solaris/classes/sun/nio/fs/UnixFileStoreAttributes.java
jdk/src/solaris/classes/sun/nio/fs/UnixFileSystem.java
jdk/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java
jdk/src/solaris/classes/sun/nio/fs/UnixMountEntry.java
jdk/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java
jdk/src/solaris/classes/sun/nio/fs/UnixPath.java
jdk/src/solaris/classes/sun/nio/fs/UnixSecureDirectoryStream.java
jdk/src/solaris/classes/sun/nio/fs/UnixUriUtils.java
jdk/src/solaris/classes/sun/nio/fs/UnixUserPrincipals.java
jdk/src/solaris/native/sun/nio/ch/EPoll.c
jdk/src/solaris/native/sun/nio/ch/EPollPort.c
jdk/src/solaris/native/sun/nio/ch/FileChannelImpl.c
jdk/src/solaris/native/sun/nio/ch/FileDispatcher.c
jdk/src/solaris/native/sun/nio/ch/FileDispatcherImpl.c
jdk/src/solaris/native/sun/nio/ch/SocketDispatcher.c
jdk/src/solaris/native/sun/nio/ch/SolarisEventPort.c
jdk/src/solaris/native/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.c
jdk/src/solaris/native/sun/nio/ch/UnixAsynchronousSocketChannelImpl.c
jdk/src/solaris/native/sun/nio/fs/GnomeFileTypeDetector.c
jdk/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c
jdk/src/solaris/native/sun/nio/fs/LinuxWatchService.c
jdk/src/solaris/native/sun/nio/fs/SolarisNativeDispatcher.c
jdk/src/solaris/native/sun/nio/fs/SolarisWatchService.c
jdk/src/solaris/native/sun/nio/fs/UnixCopyFile.c
jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c
jdk/src/solaris/native/sun/nio/fs/genSolarisConstants.c
jdk/src/solaris/native/sun/nio/fs/genUnixConstants.c
jdk/src/windows/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java
jdk/src/windows/classes/sun/nio/ch/FileDispatcher.java
jdk/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java
jdk/src/windows/classes/sun/nio/ch/Iocp.java
jdk/src/windows/classes/sun/nio/ch/PendingIoCache.java
jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousChannelProvider.java
jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java
jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java
jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java
jdk/src/windows/classes/sun/nio/fs/DefaultFileSystemProvider.java
jdk/src/windows/classes/sun/nio/fs/DefaultFileTypeDetector.java
jdk/src/windows/classes/sun/nio/fs/RegistryFileTypeDetector.java
jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java
jdk/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java
jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java
jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java
jdk/src/windows/classes/sun/nio/fs/WindowsException.java
jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java
jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java
jdk/src/windows/classes/sun/nio/fs/WindowsFileCopy.java
jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java
jdk/src/windows/classes/sun/nio/fs/WindowsFileSystem.java
jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java
jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java
jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java
jdk/src/windows/classes/sun/nio/fs/WindowsPath.java
jdk/src/windows/classes/sun/nio/fs/WindowsPathParser.java
jdk/src/windows/classes/sun/nio/fs/WindowsPathType.java
jdk/src/windows/classes/sun/nio/fs/WindowsSecurity.java
jdk/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java
jdk/src/windows/classes/sun/nio/fs/WindowsUriSupport.java
jdk/src/windows/classes/sun/nio/fs/WindowsUserDefinedFileAttributeView.java
jdk/src/windows/classes/sun/nio/fs/WindowsUserPrincipals.java
jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java
jdk/src/windows/native/sun/nio/ch/FileChannelImpl.c
jdk/src/windows/native/sun/nio/ch/FileDispatcher.c
jdk/src/windows/native/sun/nio/ch/FileDispatcherImpl.c
jdk/src/windows/native/sun/nio/ch/Iocp.c
jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousFileChannelImpl.c
jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.c
jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c
jdk/src/windows/native/sun/nio/fs/RegistryFileTypeDetector.c
jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c
jdk/test/java/nio/channels/AsynchronousChannelGroup/AsExecutor.java
jdk/test/java/nio/channels/AsynchronousChannelGroup/Attack.java
jdk/test/java/nio/channels/AsynchronousChannelGroup/BadProperties.java
jdk/test/java/nio/channels/AsynchronousChannelGroup/Basic.java
jdk/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java
jdk/test/java/nio/channels/AsynchronousChannelGroup/Identity.java
jdk/test/java/nio/channels/AsynchronousChannelGroup/PrivilegedThreadFactory.java
jdk/test/java/nio/channels/AsynchronousChannelGroup/Restart.java
jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java
jdk/test/java/nio/channels/AsynchronousChannelGroup/run_any_task.sh
jdk/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java
jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java
jdk/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java
jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java
jdk/test/java/nio/channels/AsynchronousFileChannel/MyThreadFactory.java
jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java
jdk/test/java/nio/channels/AsynchronousServerSocketChannel/WithSecurityManager.java
jdk/test/java/nio/channels/AsynchronousServerSocketChannel/java.policy.allow
jdk/test/java/nio/channels/AsynchronousServerSocketChannel/java.policy.deny
jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java
jdk/test/java/nio/channels/AsynchronousSocketChannel/Leaky.java
jdk/test/java/nio/channels/Channels/Basic2.java
jdk/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java
jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java
jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java
jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java
jdk/test/java/nio/channels/etc/NetworkChannelTests.java
jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/CheckProvider.java
jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/META-INF/services/java.nio.channels.spi.AsynchronousChannelProvider
jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider1.java
jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider2.java
jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/custom_provider.sh
jdk/test/java/nio/file/DirectoryStream/Basic.java
jdk/test/java/nio/file/DirectoryStream/Filters.java
jdk/test/java/nio/file/DirectoryStream/SecureDS.java
jdk/test/java/nio/file/FileStore/Basic.java
jdk/test/java/nio/file/FileSystem/Basic.java
jdk/test/java/nio/file/Files/ContentType.java
jdk/test/java/nio/file/Files/CreateFileTree.java
jdk/test/java/nio/file/Files/ForceLoad.java
jdk/test/java/nio/file/Files/META-INF/services/java.nio.file.spi.FileTypeDetector
jdk/test/java/nio/file/Files/Misc.java
jdk/test/java/nio/file/Files/PrintFileTree.java
jdk/test/java/nio/file/Files/SimpleFileTypeDetector.java
jdk/test/java/nio/file/Files/SkipSiblings.java
jdk/test/java/nio/file/Files/TerminateWalk.java
jdk/test/java/nio/file/Files/content_type.sh
jdk/test/java/nio/file/Files/walk_file_tree.sh
jdk/test/java/nio/file/Path/CopyAndMove.java
jdk/test/java/nio/file/Path/DeleteOnClose.java
jdk/test/java/nio/file/Path/InterruptCopy.java
jdk/test/java/nio/file/Path/Links.java
jdk/test/java/nio/file/Path/Misc.java
jdk/test/java/nio/file/Path/PathOps.java
jdk/test/java/nio/file/Path/SBC.java
jdk/test/java/nio/file/Path/TemporaryFiles.java
jdk/test/java/nio/file/Path/UriImportExport.java
jdk/test/java/nio/file/Path/delete_on_close.sh
jdk/test/java/nio/file/Path/temporary_files.sh
jdk/test/java/nio/file/PathMatcher/Basic.java
jdk/test/java/nio/file/TestUtil.java
jdk/test/java/nio/file/WatchService/Basic.java
jdk/test/java/nio/file/WatchService/FileTreeModifier.java
jdk/test/java/nio/file/WatchService/SensitivityModifier.java
jdk/test/java/nio/file/WatchService/WithSecurityManager.java
jdk/test/java/nio/file/WatchService/denyAll.policy
jdk/test/java/nio/file/WatchService/grantDirAndOneLevel.policy
jdk/test/java/nio/file/WatchService/grantDirAndTree.policy
jdk/test/java/nio/file/WatchService/grantDirOnly.policy
jdk/test/java/nio/file/attribute/AclFileAttributeView/Basic.java
jdk/test/java/nio/file/attribute/Attributes/Basic.java
jdk/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java
jdk/test/java/nio/file/attribute/DosFileAttributeView/Basic.java
jdk/test/java/nio/file/attribute/FileStoreAttributeView/Basic.java
jdk/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java
jdk/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java
jdk/test/java/nio/file/spi/SetDefaultProvider.java
jdk/test/java/nio/file/spi/TestProvider.java
--- a/jdk/make/docs/CORE_PKGS.gmk	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/make/docs/CORE_PKGS.gmk	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright 2001-2008 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2001-2009 Sun Microsystems, Inc.  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
@@ -110,6 +110,9 @@
   java.nio.channels.spi                          \
   java.nio.charset                               \
   java.nio.charset.spi                           \
+  java.nio.file					 \
+  java.nio.file.attribute			 \
+  java.nio.file.spi				 \
   java.rmi                                       \
   java.rmi.activation                            \
   java.rmi.dgc                                   \
--- a/jdk/make/docs/NON_CORE_PKGS.gmk	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/make/docs/NON_CORE_PKGS.gmk	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright 2002-2008 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2002-2009 Sun Microsystems, Inc.  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
@@ -65,6 +65,8 @@
 HTTPSERVER_PKGS  = com.sun.net.httpserver       \
                    com.sun.net.httpserver.spi 
 
+NIO_PKGS         = com.sun.nio.file
+
 DOCLETAPI_PKGS   = com.sun.javadoc
 
 TAGLETAPI_FILE   = com/sun/tools/doclets/Taglet.java
@@ -92,6 +94,7 @@
                    $(MGMT_PKGS) \
                    $(JAAS_PKGS) \
                    $(JGSS_PKGS) \
+                   $(NIO_PKGS) \
                    $(OLD_JSSE_PKGS) \
                    $(HTTPSERVER_PKGS) \
                    $(SMARTCARDIO_PKGS) \
--- a/jdk/make/java/nio/Exportedfiles.gmk	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/make/java/nio/Exportedfiles.gmk	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright 2000-2005 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -33,7 +33,7 @@
     sun/nio/ch/DatagramChannelImpl.java \
     sun/nio/ch/DatagramDispatcher.java \
     sun/nio/ch/FileChannelImpl.java \
-    sun/nio/ch/FileDispatcher.java \
+    sun/nio/ch/FileDispatcherImpl.java \
     sun/nio/ch/FileKey.java \
     sun/nio/ch/FileLockImpl.java \
     sun/nio/ch/IOStatus.java \
--- a/jdk/make/java/nio/FILES_c.gmk	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/make/java/nio/FILES_c.gmk	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright 2000-2005 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -27,7 +27,7 @@
         DatagramChannelImpl.c \
         DatagramDispatcher.c \
 	FileChannelImpl.c \
-	FileDispatcher.c \
+	FileDispatcherImpl.c \
 	FileKey.c \
 	IOUtil.c \
         MappedByteBuffer.c \
--- a/jdk/make/java/nio/FILES_java.gmk	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/make/java/nio/FILES_java.gmk	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -31,19 +31,29 @@
 	java/nio/MappedByteBuffer.java \
 	java/nio/StringCharBuffer.java \
 	\
+	java/nio/channels/AsynchronousByteChannel.java \
+	java/nio/channels/AsynchronousChannel.java \
+	java/nio/channels/AsynchronousChannelGroup.java \
+	java/nio/channels/AsynchronousDatagramChannel.java \
+	java/nio/channels/AsynchronousFileChannel.java \
+	java/nio/channels/AsynchronousServerSocketChannel.java \
+	java/nio/channels/AsynchronousSocketChannel.java \
 	java/nio/channels/ByteChannel.java \
 	java/nio/channels/Channel.java \
 	java/nio/channels/Channels.java \
+	java/nio/channels/CompletionHandler.java \
 	java/nio/channels/DatagramChannel.java \
 	java/nio/channels/FileChannel.java \
 	java/nio/channels/FileLock.java \
 	java/nio/channels/GatheringByteChannel.java \
 	java/nio/channels/InterruptibleChannel.java \
+	java/nio/channels/Pipe.java \
 	java/nio/channels/MembershipKey.java \
 	java/nio/channels/MulticastChannel.java \
 	java/nio/channels/NetworkChannel.java \
 	java/nio/channels/ReadableByteChannel.java \
 	java/nio/channels/ScatteringByteChannel.java \
+	java/nio/channels/SeekableByteChannel.java \
 	java/nio/channels/SelectableChannel.java \
 	java/nio/channels/Selector.java \
 	java/nio/channels/SelectionKey.java \
@@ -55,6 +65,7 @@
 	java/nio/channels/spi/AbstractSelectableChannel.java \
 	java/nio/channels/spi/AbstractSelectionKey.java \
 	java/nio/channels/spi/AbstractSelector.java \
+	java/nio/channels/spi/AsynchronousChannelProvider.java \
 	java/nio/channels/spi/SelectorProvider.java \
 	\
 	java/nio/charset/Charset.java \
@@ -66,21 +77,117 @@
 	\
 	java/nio/charset/spi/CharsetProvider.java \
 	\
+	java/nio/file/AccessDeniedException.java \
+	java/nio/file/AccessMode.java \
+	java/nio/file/AtomicMoveNotSupportedException.java \
+	java/nio/file/ClosedDirectoryStreamException.java \
+	java/nio/file/ClosedFileSystemException.java \
+	java/nio/file/ClosedWatchServiceException.java \
+	java/nio/file/CopyOption.java \
+	java/nio/file/DirectoryNotEmptyException.java \
+	java/nio/file/DirectoryStream.java \
+	java/nio/file/DirectoryStreamFilters.java \
+	java/nio/file/FileAction.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 \
+	java/nio/file/FileSystemException.java \
+	java/nio/file/FileSystemNotFoundException.java \
+	java/nio/file/FileSystems.java \
+	java/nio/file/FileTreeWalker.java \
+	java/nio/file/FileVisitOption.java \
+	java/nio/file/FileVisitResult.java \
+	java/nio/file/FileVisitor.java \
+	java/nio/file/Files.java \
+	java/nio/file/InvalidPathException.java \
+	java/nio/file/LinkOption.java \
+	java/nio/file/LinkPermission.java \
+	java/nio/file/NoSuchFileException.java \
+	java/nio/file/NotDirectoryException.java \
+	java/nio/file/NotLinkException.java \
+	java/nio/file/OpenOption.java \
+	java/nio/file/Path.java \
+	java/nio/file/PathMatcher.java \
+	java/nio/file/Paths.java \
+	java/nio/file/ProviderMismatchException.java \
+	java/nio/file/ProviderNotFoundException.java \
+	java/nio/file/ReadOnlyFileSystemException.java \
+	java/nio/file/SecureDirectoryStream.java \
+	java/nio/file/SimpleFileVisitor.java \
+	java/nio/file/StandardCopyOption.java \
+	java/nio/file/StandardOpenOption.java \
+	java/nio/file/StandardWatchEventKind.java \
+	java/nio/file/WatchEvent.java \
+	java/nio/file/WatchKey.java \
+	java/nio/file/WatchService.java \
+	java/nio/file/Watchable.java \
+	\
+	java/nio/file/attribute/AclEntry.java \
+	java/nio/file/attribute/AclEntryFlag.java \
+	java/nio/file/attribute/AclEntryPermission.java \
+	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 \
+	java/nio/file/attribute/DosFileAttributes.java \
+	java/nio/file/attribute/FileAttribute.java \
+	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/GroupPrincipal.java \
+	java/nio/file/attribute/UserDefinedFileAttributeView.java \
+	java/nio/file/attribute/PosixFileAttributeView.java \
+	java/nio/file/attribute/PosixFileAttributes.java \
+	java/nio/file/attribute/PosixFilePermission.java \
+	java/nio/file/attribute/PosixFilePermissions.java \
+	java/nio/file/attribute/UserPrincipal.java \
+	java/nio/file/attribute/UserPrincipalLookupService.java \
+	java/nio/file/attribute/UserPrincipalNotFoundException.java \
+	\
+	java/nio/file/spi/AbstractPath.java \
+	java/nio/file/spi/FileSystemProvider.java \
+	java/nio/file/spi/FileTypeDetector.java \
+	\
+	com/sun/nio/file/ExtendedCopyOption.java \
+	com/sun/nio/file/ExtendedOpenOption.java \
+	com/sun/nio/file/ExtendedWatchEventModifier.java \
+	com/sun/nio/file/SensitivityWatchEventModifier.java \
+	\
 	sun/nio/ByteBuffered.java \
 	\
+	sun/nio/ch/AbstractFuture.java \
         sun/nio/ch/AbstractPollArrayWrapper.java \
 	sun/nio/ch/AllocatedNativeObject.java \
+	sun/nio/ch/AsynchronousChannelGroupImpl.java \
+	sun/nio/ch/AsynchronousFileChannelImpl.java \
+	sun/nio/ch/AsynchronousServerSocketChannelImpl.java \
+	sun/nio/ch/AsynchronousSocketChannelImpl.java \
+	sun/nio/ch/Cancellable.java \
 	sun/nio/ch/ChannelInputStream.java \
+	sun/nio/ch/CompletedFuture.java \
         sun/nio/ch/DatagramChannelImpl.java \
         sun/nio/ch/DatagramDispatcher.java \
 	sun/nio/ch/DatagramSocketAdaptor.java \
+	sun/nio/ch/DefaultAsynchronousChannelProvider.java \
         sun/nio/ch/DefaultSelectorProvider.java \
 	sun/nio/ch/DirectBuffer.java \
 	sun/nio/ch/ExtendedSocketOption.java \
 	sun/nio/ch/FileChannelImpl.java \
 	sun/nio/ch/FileDispatcher.java \
+	sun/nio/ch/FileDispatcherImpl.java \
 	sun/nio/ch/FileKey.java \
+	sun/nio/ch/FileLockImpl.java \
+	sun/nio/ch/FileLockTable.java \
+	sun/nio/ch/Groupable.java \
 	sun/nio/ch/Interruptible.java \
+	sun/nio/ch/Invoker.java \
 	sun/nio/ch/IOUtil.java \
 	sun/nio/ch/IOStatus.java \
 	sun/nio/ch/IOVecWrapper.java \
@@ -92,6 +199,7 @@
 	sun/nio/ch/NativeThreadSet.java \
 	sun/nio/ch/Net.java \
 	sun/nio/ch/OptionKey.java \
+	sun/nio/ch/PendingFuture.java \
 	sun/nio/ch/PipeImpl.java \
 	sun/nio/ch/PollArrayWrapper.java \
 	sun/nio/ch/Reflect.java \
@@ -101,12 +209,14 @@
 	sun/nio/ch/SelChImpl.java \
 	sun/nio/ch/ServerSocketAdaptor.java \
 	sun/nio/ch/ServerSocketChannelImpl.java \
+	sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java \
         sun/nio/ch/SinkChannelImpl.java \
 	sun/nio/ch/SocketAdaptor.java \
 	sun/nio/ch/SocketChannelImpl.java \
 	sun/nio/ch/SocketDispatcher.java \
 	sun/nio/ch/SocketOptionRegistry.java \
         sun/nio/ch/SourceChannelImpl.java \
+	sun/nio/ch/ThreadPool.java \
 	sun/nio/ch/Util.java \
 	\
 	sun/nio/cs/AbstractCharsetProvider.java \
@@ -134,6 +244,24 @@
 	sun/nio/cs/UTF_32LE_BOM.java \
 	sun/nio/cs/UTF_32Coder.java \
 	\
+	sun/nio/fs/AbstractAclFileAttributeView.java \
+	sun/nio/fs/AbstractBasicFileAttributeView.java \
+	sun/nio/fs/AbstractFileStoreSpaceAttributeView.java \
+	sun/nio/fs/AbstractFileTypeDetector.java \
+	sun/nio/fs/AbstractPoller.java \
+	sun/nio/fs/AbstractUserDefinedFileAttributeView.java \
+	sun/nio/fs/AbstractWatchKey.java \
+	sun/nio/fs/AbstractWatchService.java \
+	sun/nio/fs/Cancellable.java \
+	sun/nio/fs/DefaultFileSystemProvider.java \
+	sun/nio/fs/DefaultFileTypeDetector.java \
+	sun/nio/fs/FileOwnerAttributeViewImpl.java \
+	sun/nio/fs/Globs.java \
+	sun/nio/fs/MimeType.java \
+	sun/nio/fs/NativeBuffer.java \
+	sun/nio/fs/NativeBuffers.java \
+	sun/nio/fs/Reflect.java \
+	\
 	java/net/DatagramSocket.java \
 	java/net/DatagramSocketImpl.java \
 	java/net/PlainSocketImpl.java \
@@ -244,24 +372,31 @@
 	java/nio/InvalidMarkException.java \
 	java/nio/ReadOnlyBufferException.java \
 	\
+	java/nio/channels/AcceptPendingException.java \
 	java/nio/channels/AlreadyBoundException.java \
 	java/nio/channels/AlreadyConnectedException.java \
 	java/nio/channels/AsynchronousCloseException.java \
+	java/nio/channels/CancelledKeyException.java \
 	java/nio/channels/ClosedByInterruptException.java \
 	java/nio/channels/ClosedChannelException.java \
 	java/nio/channels/ClosedSelectorException.java \
 	java/nio/channels/ConnectionPendingException.java \
 	java/nio/channels/FileLockInterruptionException.java \
 	java/nio/channels/IllegalBlockingModeException.java \
+	java/nio/channels/IllegalChannelGroupException.java \
 	java/nio/channels/IllegalSelectorException.java \
+	java/nio/channels/InterruptedByTimeoutException.java \
 	java/nio/channels/NoConnectionPendingException.java \
 	java/nio/channels/NonReadableChannelException.java \
 	java/nio/channels/NonWritableChannelException.java \
 	java/nio/channels/NotYetBoundException.java \
 	java/nio/channels/NotYetConnectedException.java \
 	java/nio/channels/OverlappingFileLockException.java \
+	java/nio/channels/ReadPendingException.java \
+	java/nio/channels/ShutdownChannelGroupException.java \
 	java/nio/channels/UnresolvedAddressException.java \
 	java/nio/channels/UnsupportedAddressTypeException.java \
+	java/nio/channels/WritePendingException.java \
 	\
 	java/nio/charset/CharacterCodingException.java \
 	java/nio/charset/IllegalCharsetNameException.java \
--- a/jdk/make/java/nio/Makefile	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/make/java/nio/Makefile	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -56,56 +56,214 @@
         sun/nio/ch/DevPollSelectorProvider.java \
 	sun/nio/ch/InheritedChannel.java \
         sun/nio/ch/PollSelectorProvider.java \
-        sun/nio/ch/PollSelectorImpl.java
+        sun/nio/ch/PollSelectorImpl.java \
+	sun/nio/ch/Port.java \
+	sun/nio/ch/SimpleAsynchronousFileChannelImpl.java \
+	sun/nio/ch/SolarisAsynchronousChannelProvider.java \
+	sun/nio/ch/SolarisEventPort.java \
+	sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java \
+	sun/nio/ch/UnixAsynchronousSocketChannelImpl.java \
+	\
+	sun/nio/fs/GnomeFileTypeDetector.java \
+	sun/nio/fs/PollingWatchService.java \
+	sun/nio/fs/SolarisAclFileAttributeView.java \
+	sun/nio/fs/SolarisFileStore.java \
+	sun/nio/fs/SolarisFileSystem.java \
+	sun/nio/fs/SolarisFileSystemProvider.java \
+	sun/nio/fs/SolarisUserDefinedFileAttributeView.java \
+	sun/nio/fs/SolarisNativeDispatcher.java \
+	sun/nio/fs/SolarisWatchService.java \
+	sun/nio/fs/UnixChannelFactory.java \
+	sun/nio/fs/UnixCopyFile.java \
+	sun/nio/fs/UnixDirectoryStream.java \
+	sun/nio/fs/UnixException.java \
+	sun/nio/fs/UnixFileAttributeViews.java \
+	sun/nio/fs/UnixFileAttributes.java \
+	sun/nio/fs/UnixFileKey.java \
+	sun/nio/fs/UnixFileModeAttribute.java \
+	sun/nio/fs/UnixFileStore.java \
+	sun/nio/fs/UnixFileStoreAttributes.java \
+	sun/nio/fs/UnixFileSystem.java \
+	sun/nio/fs/UnixFileSystemProvider.java \
+	sun/nio/fs/UnixMountEntry.java \
+	sun/nio/fs/UnixNativeDispatcher.java \
+	sun/nio/fs/UnixPath.java \
+	sun/nio/fs/UnixSecureDirectoryStream.java \
+	sun/nio/fs/UnixUriUtils.java \
+	sun/nio/fs/UnixUserPrincipals.java
 
 FILES_c += \
         DevPollArrayWrapper.c \
 	InheritedChannel.c \
 	NativeThread.c \
-        PollArrayWrapper.c
+        PollArrayWrapper.c \
+	SolarisEventPort.c \
+	UnixAsynchronousServerSocketChannelImpl.c \
+	UnixAsynchronousSocketChannelImpl.c \
+	\
+	GnomeFileTypeDetector.c \
+	SolarisNativeDispatcher.c \
+	SolarisWatchService.c \
+	UnixCopyFile.c \
+	UnixNativeDispatcher.c
 
 FILES_export += \
 	sun/nio/ch/DevPollArrayWrapper.java \
 	sun/nio/ch/InheritedChannel.java \
-	sun/nio/ch/NativeThread.java
+	sun/nio/ch/NativeThread.java \
+	sun/nio/ch/SolarisEventPort.java \
+	sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java \
+	sun/nio/ch/UnixAsynchronousSocketChannelImpl.java \
+	\
+	sun/nio/fs/GnomeFileTypeDetector.java \
+	sun/nio/fs/SolarisNativeDispatcher.java \
+	sun/nio/fs/SolarisWatchService.java \
+	sun/nio/fs/UnixCopyFile.java \
+	sun/nio/fs/UnixNativeDispatcher.java
+
+FILES_gen += \
+	sun/nio/fs/SolarisConstants.java \
+	sun/nio/fs/UnixConstants.java
 endif # PLATFORM = solaris
 
 ifeq ($(PLATFORM), windows)
 FILES_java += \
+	sun/nio/ch/Iocp.java \
+	sun/nio/ch/PendingIoCache.java \
+	sun/nio/ch/WindowsAsynchronousChannelProvider.java \
+	sun/nio/ch/WindowsAsynchronousFileChannelImpl.java \
+	sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java \
+	sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java \
         sun/nio/ch/WindowsSelectorImpl.java \
-        sun/nio/ch/WindowsSelectorProvider.java
+        sun/nio/ch/WindowsSelectorProvider.java \
+	\
+	sun/nio/fs/RegistryFileTypeDetector.java \
+	sun/nio/fs/WindowsAclFileAttributeView.java \
+	sun/nio/fs/WindowsChannelFactory.java \
+	sun/nio/fs/WindowsConstants.java \
+	sun/nio/fs/WindowsDirectoryStream.java \
+	sun/nio/fs/WindowsException.java \
+	sun/nio/fs/WindowsFileAttributeViews.java \
+	sun/nio/fs/WindowsFileAttributes.java \
+	sun/nio/fs/WindowsFileCopy.java \
+	sun/nio/fs/WindowsFileStore.java \
+	sun/nio/fs/WindowsFileSystem.java \
+	sun/nio/fs/WindowsFileSystemProvider.java \
+	sun/nio/fs/WindowsLinkSupport.java \
+	sun/nio/fs/WindowsUserDefinedFileAttributeView.java \
+	sun/nio/fs/WindowsNativeDispatcher.java \
+	sun/nio/fs/WindowsPath.java \
+	sun/nio/fs/WindowsPathParser.java \
+	sun/nio/fs/WindowsPathType.java \
+	sun/nio/fs/WindowsSecurity.java \
+	sun/nio/fs/WindowsSecurityDescriptor.java \
+	sun/nio/fs/WindowsUriSupport.java \
+	sun/nio/fs/WindowsUserPrincipals.java \
+	sun/nio/fs/WindowsWatchService.java
 
 FILES_c += \
+	Iocp.c \
+	RegistryFileTypeDetector.c \
+	WindowsAsynchronousFileChannelImpl.c \
+	WindowsAsynchronousServerSocketChannelImpl.c \
+	WindowsAsynchronousSocketChannelImpl.c \
+	WindowsNativeDispatcher.c \
         WindowsSelectorImpl.c
 
 FILES_export += \
-	sun/nio/ch/WindowsSelectorImpl.java
+	sun/nio/ch/Iocp.java \
+	sun/nio/ch/WindowsAsynchronousFileChannelImpl.java \
+	sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java \
+	sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java \
+	sun/nio/ch/WindowsSelectorImpl.java \
+	sun/nio/fs/WindowsNativeDispatcher.java \
+	sun/nio/fs/RegistryFileTypeDetector.java
 endif # PLATFORM = windows
 
 ifeq ($(PLATFORM), linux)
 FILES_java += \
         sun/nio/ch/AbstractPollSelectorImpl.java \
+	sun/nio/ch/EPoll.java \
 	sun/nio/ch/EPollArrayWrapper.java \
+	sun/nio/ch/EPollPort.java \
 	sun/nio/ch/EPollSelectorProvider.java \
 	sun/nio/ch/EPollSelectorImpl.java \
 	sun/nio/ch/InheritedChannel.java \
+	sun/nio/ch/LinuxAsynchronousChannelProvider.java \
         sun/nio/ch/PollSelectorProvider.java \
-        sun/nio/ch/PollSelectorImpl.java
+        sun/nio/ch/PollSelectorImpl.java \
+	sun/nio/ch/Port.java \
+	sun/nio/ch/SimpleAsynchronousFileChannelImpl.java \
+	sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java \
+	sun/nio/ch/UnixAsynchronousSocketChannelImpl.java \
+	\
+	sun/nio/fs/GnomeFileTypeDetector.java \
+	sun/nio/fs/LinuxDosFileAttributeView.java \
+	sun/nio/fs/LinuxFileStore.java \
+	sun/nio/fs/LinuxFileSystem.java \
+	sun/nio/fs/LinuxFileSystemProvider.java \
+	sun/nio/fs/LinuxUserDefinedFileAttributeView.java \
+	sun/nio/fs/LinuxNativeDispatcher.java \
+	sun/nio/fs/LinuxWatchService.java \
+	sun/nio/fs/PollingWatchService.java \
+	sun/nio/fs/UnixChannelFactory.java \
+	sun/nio/fs/UnixCopyFile.java \
+	sun/nio/fs/UnixDirectoryStream.java \
+	sun/nio/fs/UnixException.java \
+	sun/nio/fs/UnixFileAttributeViews.java \
+	sun/nio/fs/UnixFileAttributes.java \
+	sun/nio/fs/UnixFileKey.java \
+	sun/nio/fs/UnixFileModeAttribute.java \
+	sun/nio/fs/UnixFileStore.java \
+	sun/nio/fs/UnixFileStoreAttributes.java \
+	sun/nio/fs/UnixFileSystem.java \
+	sun/nio/fs/UnixFileSystemProvider.java \
+	sun/nio/fs/UnixMountEntry.java \
+	sun/nio/fs/UnixNativeDispatcher.java \
+	sun/nio/fs/UnixPath.java \
+	sun/nio/fs/UnixSecureDirectoryStream.java \
+	sun/nio/fs/UnixUriUtils.java \
+	sun/nio/fs/UnixUserPrincipals.java
 
 FILES_c += \
+	EPoll.c \
 	EPollArrayWrapper.c \
+	EPollPort.c \
 	InheritedChannel.c \
 	NativeThread.c \
-        PollArrayWrapper.c
+        PollArrayWrapper.c \
+	UnixAsynchronousServerSocketChannelImpl.c \
+	UnixAsynchronousSocketChannelImpl.c \
+	\
+	GnomeFileTypeDetector.c \
+	LinuxNativeDispatcher.c \
+	LinuxWatchService.c \
+	UnixCopyFile.c \
+	UnixNativeDispatcher.c
 
 FILES_export += \
+	sun/nio/ch/EPoll.java \
         sun/nio/ch/EPollArrayWrapper.java \
+	sun/nio/ch/EPollPort.java \
 	sun/nio/ch/InheritedChannel.java \
-	sun/nio/ch/NativeThread.java
+	sun/nio/ch/NativeThread.java \
+	sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java \
+	sun/nio/ch/UnixAsynchronousSocketChannelImpl.java \
+	\
+	sun/nio/fs/GnomeFileTypeDetector.java \
+	sun/nio/fs/LinuxNativeDispatcher.java \
+	sun/nio/fs/LinuxWatchService.java \
+	sun/nio/fs/UnixCopyFile.java \
+	sun/nio/fs/UnixNativeDispatcher.java
+	
+FILES_gen += \
+	sun/nio/fs/UnixConstants.java
 endif # PLATFORM = linux
 
+#
 # Find platform-specific C source files
 #
+vpath %.c $(PLATFORM_SRC)/native/sun/nio/fs
 vpath %.c $(PLATFORM_SRC)/native/sun/nio/ch
 vpath %.c $(SHARE_SRC)/native/sun/nio/ch
 
@@ -175,12 +333,14 @@
 CS_SRC=$(NIO_SRC)/charset
 SCH_SRC=$(SNIO_SRC)/ch
 SCS_SRC=$(SNIO_SRC)/cs
+SFS_SRC=$(SNIO_SRC)/fs
 
 BUF_GEN=$(NIO_GEN)
 CH_GEN=$(NIO_GEN)/channels
 CS_GEN=$(NIO_GEN)/charset
 SCH_GEN=$(SNIO_GEN)/ch
 SCS_GEN=$(SNIO_GEN)/cs
+SFS_GEN=$(SNIO_GEN)/fs
 
 FILES_gensbcs_out = $(FILES_gen_sbcs:%.java=$(GENSRCDIR)/%.java)
 
@@ -670,4 +830,40 @@
 	$(BOOT_JAVA_CMD) -cp $(CHARSETMAPPING_JARFILE) build.tools.charsetmapping.GenerateSBCS \
 		$(GENCSSRC) $(SCS_GEN) sbcs
 
+# 
+# Generated file system implementation classes (Unix only)
+#
+
+GENUC_SRC = $(PLATFORM_SRC)/native/sun/nio/fs/genUnixConstants.c
+
+GENUC_EXE = $(TEMPDIR)/genUnixConstants
+
+GENUC_COPYRIGHT_YEARS = $(shell $(CAT) $(GENUC_SRC) | \
+	$(NAWK) '/^.*Copyright.*Sun/ { print $$3 }')
+
+$(GENUC_EXE) : $(GENUC_SRC)
+	$(prep-target)
+	$(CC) $(CPPFLAGS) -o $@ $(GENUC_SRC)
+
+$(SFS_GEN)/UnixConstants.java: $(GENUC_EXE)
+	$(prep-target)
+	NAWK="$(NAWK)" SH="$(SH)" $(SH) -e addNotices.sh $(GENUC_COPYRIGHT_YEARS) > $@
+	$(GENUC_EXE) >> $@
+
+GENSC_SRC = $(PLATFORM_SRC)/native/sun/nio/fs/genSolarisConstants.c
+
+GENSC_EXE = $(TEMPDIR)/genSolarisConstants
+
+GENSC_COPYRIGHT_YEARS = $(shell $(CAT) $(GENSC_SRC) | \
+	$(NAWK) '/^.*Copyright.*Sun/ { print $$3 }')
+
+$(GENSC_EXE) : $(GENSC_SRC)
+	$(prep-target)
+	$(CC) $(CPPFLAGS) -o $@ $(GENSC_SRC)
+
+$(SFS_GEN)/SolarisConstants.java: $(GENSC_EXE)
+	$(prep-target)
+	NAWK="$(NAWK)" SH="$(SH)" $(SH) -e addNotices.sh $(GENSC_COPYRIGHT_YEARS) > $@
+	$(GENSC_EXE) >> $@
+
 .PHONY: sources 
--- a/jdk/make/java/nio/mapfile-linux	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/make/java/nio/mapfile-linux	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright 2001-2008 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2001-2009 Sun Microsystems, Inc.  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
@@ -44,27 +44,38 @@
 		Java_sun_nio_ch_EPollArrayWrapper_interrupt;
 		Java_sun_nio_ch_EPollArrayWrapper_offsetofData;
 		Java_sun_nio_ch_EPollArrayWrapper_sizeofEPollEvent;
+		Java_sun_nio_ch_EPoll_init;
+		Java_sun_nio_ch_EPoll_eventSize;
+		Java_sun_nio_ch_EPoll_eventsOffset;
+		Java_sun_nio_ch_EPoll_dataOffset;
+		Java_sun_nio_ch_EPoll_epollCreate;
+		Java_sun_nio_ch_EPoll_epollCtl;
+		Java_sun_nio_ch_EPoll_epollWait;
+		Java_sun_nio_ch_EPollPort_close0;
+		Java_sun_nio_ch_EPollPort_drain1;
+		Java_sun_nio_ch_EPollPort_interrupt;
+		Java_sun_nio_ch_EPollPort_socketpair;
                 Java_sun_nio_ch_FileChannelImpl_close0;
-                Java_sun_nio_ch_FileChannelImpl_force0;
                 Java_sun_nio_ch_FileChannelImpl_initIDs;
-                Java_sun_nio_ch_FileChannelImpl_lock0;
                 Java_sun_nio_ch_FileChannelImpl_map0;
                 Java_sun_nio_ch_FileChannelImpl_position0;
-                Java_sun_nio_ch_FileChannelImpl_release0;
-                Java_sun_nio_ch_FileChannelImpl_size0;
                 Java_sun_nio_ch_FileChannelImpl_transferTo0;
-                Java_sun_nio_ch_FileChannelImpl_truncate0;
                 Java_sun_nio_ch_FileChannelImpl_unmap0;
-                Java_sun_nio_ch_FileDispatcher_close0;
-                Java_sun_nio_ch_FileDispatcher_closeIntFD;
-                Java_sun_nio_ch_FileDispatcher_init;
-                Java_sun_nio_ch_FileDispatcher_preClose0;
-                Java_sun_nio_ch_FileDispatcher_pread0;
-                Java_sun_nio_ch_FileDispatcher_pwrite0;
-                Java_sun_nio_ch_FileDispatcher_read0;
-                Java_sun_nio_ch_FileDispatcher_readv0;
-                Java_sun_nio_ch_FileDispatcher_write0;
-                Java_sun_nio_ch_FileDispatcher_writev0;
+                Java_sun_nio_ch_FileDispatcherImpl_close0;
+                Java_sun_nio_ch_FileDispatcherImpl_closeIntFD;
+		Java_sun_nio_ch_FileDispatcherImpl_force0;
+                Java_sun_nio_ch_FileDispatcherImpl_init;
+		Java_sun_nio_ch_FileDispatcherImpl_lock0;
+                Java_sun_nio_ch_FileDispatcherImpl_preClose0;
+                Java_sun_nio_ch_FileDispatcherImpl_pread0;
+                Java_sun_nio_ch_FileDispatcherImpl_pwrite0;
+                Java_sun_nio_ch_FileDispatcherImpl_read0;
+                Java_sun_nio_ch_FileDispatcherImpl_readv0;
+		Java_sun_nio_ch_FileDispatcherImpl_release0;
+		Java_sun_nio_ch_FileDispatcherImpl_size0;
+		Java_sun_nio_ch_FileDispatcherImpl_truncate0;
+                Java_sun_nio_ch_FileDispatcherImpl_write0;
+                Java_sun_nio_ch_FileDispatcherImpl_writev0;
                 Java_sun_nio_ch_FileKey_init;
                 Java_sun_nio_ch_FileKey_initIDs;
 		Java_sun_nio_ch_InheritedChannel_close0;
@@ -108,6 +119,76 @@
                 Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
                 Java_sun_nio_ch_ServerSocketChannelImpl_initIDs;
                 Java_sun_nio_ch_SocketChannelImpl_checkConnect;
+		Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_accept0;
+		Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_initIDs;
+		Java_sun_nio_ch_UnixAsynchronousSocketChannelImpl_checkConnect;
+		Java_sun_nio_fs_GnomeFileTypeDetector_initializeGio;
+		Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGio;
+		Java_sun_nio_fs_GnomeFileTypeDetector_initializeGnomeVfs;
+		Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGnomeVfs;
+		Java_sun_nio_fs_LinuxWatchService_init;
+		Java_sun_nio_fs_LinuxWatchService_eventSize;
+		Java_sun_nio_fs_LinuxWatchService_eventOffsets;
+		Java_sun_nio_fs_LinuxWatchService_inotifyInit;
+		Java_sun_nio_fs_LinuxWatchService_inotifyAddWatch;
+		Java_sun_nio_fs_LinuxWatchService_inotifyRmWatch;
+		Java_sun_nio_fs_LinuxWatchService_configureBlocking;
+		Java_sun_nio_fs_LinuxWatchService_socketpair;
+		Java_sun_nio_fs_LinuxWatchService_poll;
+		Java_sun_nio_fs_LinuxNativeDispatcher_init;
+		Java_sun_nio_fs_LinuxNativeDispatcher_fgetxattr0;
+		Java_sun_nio_fs_LinuxNativeDispatcher_flistxattr;
+		Java_sun_nio_fs_LinuxNativeDispatcher_fsetxattr0;
+		Java_sun_nio_fs_LinuxNativeDispatcher_fremovexattr0;
+		Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0;
+		Java_sun_nio_fs_LinuxNativeDispatcher_endmntent;
+		Java_sun_nio_fs_UnixNativeDispatcher_initIDs;
+		Java_sun_nio_fs_UnixNativeDispatcher_getcwd;
+		Java_sun_nio_fs_UnixNativeDispatcher_strerror;
+		Java_sun_nio_fs_UnixNativeDispatcher_dup;
+		Java_sun_nio_fs_UnixNativeDispatcher_access0;
+		Java_sun_nio_fs_UnixNativeDispatcher_stat0;
+		Java_sun_nio_fs_UnixNativeDispatcher_lstat0;
+		Java_sun_nio_fs_UnixNativeDispatcher_fstat;
+		Java_sun_nio_fs_UnixNativeDispatcher_fstatat0;
+		Java_sun_nio_fs_UnixNativeDispatcher_chmod0;
+		Java_sun_nio_fs_UnixNativeDispatcher_fchmod;
+		Java_sun_nio_fs_UnixNativeDispatcher_chown0;
+		Java_sun_nio_fs_UnixNativeDispatcher_lchown0;
+		Java_sun_nio_fs_UnixNativeDispatcher_fchown;
+		Java_sun_nio_fs_UnixNativeDispatcher_utimes0;
+		Java_sun_nio_fs_UnixNativeDispatcher_futimes;
+		Java_sun_nio_fs_UnixNativeDispatcher_open0;
+		Java_sun_nio_fs_UnixNativeDispatcher_openat0;
+		Java_sun_nio_fs_UnixNativeDispatcher_close;
+		Java_sun_nio_fs_UnixNativeDispatcher_read;
+		Java_sun_nio_fs_UnixNativeDispatcher_write;
+		Java_sun_nio_fs_UnixNativeDispatcher_fopen0;
+		Java_sun_nio_fs_UnixNativeDispatcher_fclose;
+		Java_sun_nio_fs_UnixNativeDispatcher_opendir0;
+		Java_sun_nio_fs_UnixNativeDispatcher_fdopendir;
+		Java_sun_nio_fs_UnixNativeDispatcher_readdir;
+		Java_sun_nio_fs_UnixNativeDispatcher_closedir;
+		Java_sun_nio_fs_UnixNativeDispatcher_link0;
+		Java_sun_nio_fs_UnixNativeDispatcher_unlink0;
+		Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0;
+		Java_sun_nio_fs_UnixNativeDispatcher_rename0;
+		Java_sun_nio_fs_UnixNativeDispatcher_renameat0;
+		Java_sun_nio_fs_UnixNativeDispatcher_mkdir0;
+		Java_sun_nio_fs_UnixNativeDispatcher_rmdir0;
+		Java_sun_nio_fs_UnixNativeDispatcher_symlink0;
+		Java_sun_nio_fs_UnixNativeDispatcher_readlink0;
+		Java_sun_nio_fs_UnixNativeDispatcher_realpath0;
+		Java_sun_nio_fs_UnixNativeDispatcher_statvfs0;
+		Java_sun_nio_fs_UnixNativeDispatcher_pathconf0;
+		Java_sun_nio_fs_UnixNativeDispatcher_fpathconf;
+		Java_sun_nio_fs_UnixNativeDispatcher_mknod0;
+		Java_sun_nio_fs_UnixNativeDispatcher_getpwuid;
+		Java_sun_nio_fs_UnixNativeDispatcher_getgrgid;
+		Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0;
+		Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0;
+		Java_sun_nio_fs_UnixNativeDispatcher_getextmntent;
+		Java_sun_nio_fs_UnixCopyFile_transfer;
 
 	local:
 		*;
--- a/jdk/make/java/nio/mapfile-solaris	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/make/java/nio/mapfile-solaris	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright 2001-2008 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2001-2009 Sun Microsystems, Inc.  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
@@ -43,26 +43,26 @@
                 Java_sun_nio_ch_DevPollArrayWrapper_register;
                 Java_sun_nio_ch_DevPollArrayWrapper_registerMultiple;
                 Java_sun_nio_ch_FileChannelImpl_close0;
-                Java_sun_nio_ch_FileChannelImpl_force0;
                 Java_sun_nio_ch_FileChannelImpl_initIDs;
-                Java_sun_nio_ch_FileChannelImpl_lock0;
                 Java_sun_nio_ch_FileChannelImpl_map0;
                 Java_sun_nio_ch_FileChannelImpl_position0;
-                Java_sun_nio_ch_FileChannelImpl_release0;
-                Java_sun_nio_ch_FileChannelImpl_size0;
                 Java_sun_nio_ch_FileChannelImpl_transferTo0;
-                Java_sun_nio_ch_FileChannelImpl_truncate0;
                 Java_sun_nio_ch_FileChannelImpl_unmap0;
-                Java_sun_nio_ch_FileDispatcher_close0;
-                Java_sun_nio_ch_FileDispatcher_closeIntFD;
-                Java_sun_nio_ch_FileDispatcher_init;
-                Java_sun_nio_ch_FileDispatcher_preClose0;
-                Java_sun_nio_ch_FileDispatcher_pread0;
-                Java_sun_nio_ch_FileDispatcher_pwrite0;
-                Java_sun_nio_ch_FileDispatcher_read0;
-                Java_sun_nio_ch_FileDispatcher_readv0;
-                Java_sun_nio_ch_FileDispatcher_write0;
-                Java_sun_nio_ch_FileDispatcher_writev0;
+                Java_sun_nio_ch_FileDispatcherImpl_close0;
+                Java_sun_nio_ch_FileDispatcherImpl_closeIntFD;
+		Java_sun_nio_ch_FileDispatcherImpl_force0;
+                Java_sun_nio_ch_FileDispatcherImpl_init;
+		Java_sun_nio_ch_FileDispatcherImpl_lock0;
+                Java_sun_nio_ch_FileDispatcherImpl_preClose0;
+                Java_sun_nio_ch_FileDispatcherImpl_pread0;
+                Java_sun_nio_ch_FileDispatcherImpl_pwrite0;
+                Java_sun_nio_ch_FileDispatcherImpl_read0;
+                Java_sun_nio_ch_FileDispatcherImpl_readv0;
+		Java_sun_nio_ch_FileDispatcherImpl_release0;
+		Java_sun_nio_ch_FileDispatcherImpl_size0;
+		Java_sun_nio_ch_FileDispatcherImpl_truncate0;
+                Java_sun_nio_ch_FileDispatcherImpl_write0;
+                Java_sun_nio_ch_FileDispatcherImpl_writev0;
                 Java_sun_nio_ch_FileKey_init;
                 Java_sun_nio_ch_FileKey_initIDs;
 		Java_sun_nio_ch_InheritedChannel_close0;
@@ -106,6 +106,75 @@
                 Java_sun_nio_ch_ServerSocketChannelImpl_accept0;
                 Java_sun_nio_ch_ServerSocketChannelImpl_initIDs;
                 Java_sun_nio_ch_SocketChannelImpl_checkConnect;
+		Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_accept0;
+		Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_initIDs;
+		Java_sun_nio_ch_UnixAsynchronousSocketChannelImpl_checkConnect;
+		Java_sun_nio_ch_SolarisEventPort_init;
+		Java_sun_nio_ch_SolarisEventPort_portCreate;
+		Java_sun_nio_ch_SolarisEventPort_portClose;
+		Java_sun_nio_ch_SolarisEventPort_portAssociate;
+		Java_sun_nio_ch_SolarisEventPort_portGet;
+		Java_sun_nio_ch_SolarisEventPort_portGetn;
+		Java_sun_nio_ch_SolarisEventPort_portSend;
+		Java_sun_nio_fs_GnomeFileTypeDetector_initializeGio;
+		Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGio;
+		Java_sun_nio_fs_GnomeFileTypeDetector_initializeGnomeVfs;
+		Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGnomeVfs;
+		Java_sun_nio_fs_UnixNativeDispatcher_initIDs;
+		Java_sun_nio_fs_UnixNativeDispatcher_getcwd;
+		Java_sun_nio_fs_UnixNativeDispatcher_strerror;
+		Java_sun_nio_fs_UnixNativeDispatcher_dup;
+		Java_sun_nio_fs_UnixNativeDispatcher_access0;
+		Java_sun_nio_fs_UnixNativeDispatcher_stat0;
+		Java_sun_nio_fs_UnixNativeDispatcher_lstat0;
+		Java_sun_nio_fs_UnixNativeDispatcher_fstat;
+		Java_sun_nio_fs_UnixNativeDispatcher_fstatat0;
+		Java_sun_nio_fs_UnixNativeDispatcher_chmod0;
+		Java_sun_nio_fs_UnixNativeDispatcher_fchmod;
+		Java_sun_nio_fs_UnixNativeDispatcher_chown0;
+		Java_sun_nio_fs_UnixNativeDispatcher_lchown0;
+		Java_sun_nio_fs_UnixNativeDispatcher_fchown;
+		Java_sun_nio_fs_UnixNativeDispatcher_utimes0;
+		Java_sun_nio_fs_UnixNativeDispatcher_futimes;
+		Java_sun_nio_fs_UnixNativeDispatcher_open0;
+		Java_sun_nio_fs_UnixNativeDispatcher_openat0;
+		Java_sun_nio_fs_UnixNativeDispatcher_close;
+		Java_sun_nio_fs_UnixNativeDispatcher_read;
+		Java_sun_nio_fs_UnixNativeDispatcher_write;
+		Java_sun_nio_fs_UnixNativeDispatcher_fopen0;
+		Java_sun_nio_fs_UnixNativeDispatcher_fclose;
+		Java_sun_nio_fs_UnixNativeDispatcher_opendir0;
+		Java_sun_nio_fs_UnixNativeDispatcher_fdopendir;
+		Java_sun_nio_fs_UnixNativeDispatcher_readdir;
+		Java_sun_nio_fs_UnixNativeDispatcher_closedir;
+		Java_sun_nio_fs_UnixNativeDispatcher_link0;
+		Java_sun_nio_fs_UnixNativeDispatcher_unlink0;
+		Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0;
+		Java_sun_nio_fs_UnixNativeDispatcher_rename0;
+		Java_sun_nio_fs_UnixNativeDispatcher_renameat0;
+		Java_sun_nio_fs_UnixNativeDispatcher_mkdir0;
+		Java_sun_nio_fs_UnixNativeDispatcher_rmdir0;
+		Java_sun_nio_fs_UnixNativeDispatcher_symlink0;
+		Java_sun_nio_fs_UnixNativeDispatcher_readlink0;
+		Java_sun_nio_fs_UnixNativeDispatcher_realpath0;
+		Java_sun_nio_fs_UnixNativeDispatcher_statvfs0;
+		Java_sun_nio_fs_UnixNativeDispatcher_pathconf0;
+		Java_sun_nio_fs_UnixNativeDispatcher_fpathconf;
+		Java_sun_nio_fs_UnixNativeDispatcher_mknod0;
+		Java_sun_nio_fs_UnixNativeDispatcher_getpwuid;
+		Java_sun_nio_fs_UnixNativeDispatcher_getgrgid;
+		Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0;
+		Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0;
+		Java_sun_nio_fs_UnixNativeDispatcher_getextmntent;
+		Java_sun_nio_fs_UnixCopyFile_transfer;
+		Java_sun_nio_fs_SolarisNativeDispatcher_init;
+		Java_sun_nio_fs_SolarisNativeDispatcher_facl;
+		Java_sun_nio_fs_SolarisWatchService_init;
+		Java_sun_nio_fs_SolarisWatchService_portCreate;
+		Java_sun_nio_fs_SolarisWatchService_portAssociate;
+		Java_sun_nio_fs_SolarisWatchService_portDissociate;
+		Java_sun_nio_fs_SolarisWatchService_portSend;
+		Java_sun_nio_fs_SolarisWatchService_portGetn;
 
 	local:
 		*;
--- a/jdk/make/mksample/nio/Makefile	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/make/mksample/nio/Makefile	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright 2004-2008 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2004-2009 Sun Microsystems, Inc.  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
@@ -31,7 +31,7 @@
 PRODUCT = java
 include $(BUILDDIR)/common/Defs.gmk
 
-SUBDIRS = multicast server
+SUBDIRS = file multicast server
 all build clean clobber::
 	$(SUBDIRS-loop)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/mksample/nio/file/Makefile	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,56 @@
+#
+# Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+#
+# Makefile for the nio/file sample code
+#
+
+BUILDDIR = ../../..
+
+PRODUCT = java
+
+include $(BUILDDIR)/common/Defs.gmk
+
+SAMPLE_SRC_DIR = $(SHARE_SRC)/sample/nio/file
+SAMPLE_DST_DIR = $(SAMPLEDIR)/nio/file
+
+SAMPLE_FILES =							\
+	$(SAMPLE_DST_DIR)/AclEdit.java				\
+	$(SAMPLE_DST_DIR)/Chmod.java				\
+	$(SAMPLE_DST_DIR)/Copy.java				\
+	$(SAMPLE_DST_DIR)/DiskUsage.java			\
+	$(SAMPLE_DST_DIR)/FileType.java				\
+	$(SAMPLE_DST_DIR)/WatchDir.java				\
+	$(SAMPLE_DST_DIR)/Xdd.java
+
+all build: $(SAMPLE_FILES)
+
+$(SAMPLE_DST_DIR)/%: $(SAMPLE_SRC_DIR)/%
+	$(install-file)
+
+clean clobber:
+	$(RM) -r $(SAMPLE_DST_DIR)
+
+.PHONY: all build clean clobber
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/file/ExtendedCopyOption.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.nio.file;
+
+import java.nio.file.CopyOption;
+
+/**
+ * Defines <em>extended</em> copy options supported on some platforms
+ * by Sun's provider implementation.
+ *
+ * @since 1.7
+ */
+
+public enum ExtendedCopyOption implements CopyOption {
+    /**
+     * The copy may be interrupted by the {@link Thread#interrupt interrupt}
+     * method.
+     */
+    INTERRUPTIBLE,
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/file/ExtendedOpenOption.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.nio.file;
+
+import java.nio.file.OpenOption;
+
+/**
+ * Defines <em>extended</em> open options supported on some platforms
+ * by Sun's provider implementation.
+ *
+ * @since 1.7
+ */
+
+public enum ExtendedOpenOption implements OpenOption {
+    /**
+     * Prevent operations on the file that request read access.
+     */
+    NOSHARE_READ,
+    /**
+     * Prevent operations on the file that request write access.
+     */
+    NOSHARE_WRITE,
+    /**
+     * Prevent operations on the file that request delete access.
+     */
+    NOSHARE_DELETE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/file/ExtendedWatchEventModifier.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.nio.file;
+
+import java.nio.file.WatchEvent.Modifier;
+
+/**
+ * Defines <em>extended</em> watch event modifiers supported on some platforms
+ * by Sun's provider implementation.
+ *
+ * @since 1.7
+ */
+
+public enum ExtendedWatchEventModifier implements Modifier {
+
+    /**
+     * Register a file tree instead of a single directory.
+     */
+    FILE_TREE,
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/file/SensitivityWatchEventModifier.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.nio.file;
+
+import java.nio.file.WatchEvent.Modifier;
+
+/**
+ * Defines the <em>sensitivity levels</em> when registering objects with a
+ * watch service implementation that polls the file system.
+ *
+ * @since 1.7
+ */
+
+public enum SensitivityWatchEventModifier implements Modifier {
+    /**
+     * High sensitivity.
+     */
+    HIGH(2),
+    /**
+     * Medium sensitivity.
+     */
+    MEDIUM(10),
+    /**
+     * Low sensitivity.
+     */
+    LOW(30);
+
+    /**
+     * Returns the sensitivity in seconds.
+     */
+    public int sensitivityValueInSeconds() {
+        return sensitivity;
+    }
+
+    private final int sensitivity;
+    private SensitivityWatchEventModifier(int sensitivity) {
+        this.sensitivity = sensitivity;
+    }
+}
--- a/jdk/src/share/classes/java/io/File.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/io/File.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 1994-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1994-2009 Sun Microsystems, Inc.  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
@@ -30,12 +30,12 @@
 import java.net.URL;
 import java.net.MalformedURLException;
 import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.Hashtable;
-import java.util.Random;
+import java.util.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
 import java.security.AccessController;
-import java.security.AccessControlException;
+import java.security.PrivilegedAction;
+import java.security.SecureRandom;
 import sun.security.action.GetPropertyAction;
 
 
@@ -131,6 +131,18 @@
  * created, the abstract pathname represented by a <code>File</code> object
  * will never change.
  *
+ * <h4>Interoperability with {@code java.nio.file} package</h4>
+ *
+ * <p> The <a href="../../java/nio/file/package-summary.html">{@code java.nio.file}</a>
+ * package defines interfaces and classes for the Java virtual machine to access
+ * files, file attributes, and file systems. This API may be used to overcome
+ * 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.
+ *
  * @author  unascribed
  * @since   JDK1.0
  */
@@ -573,6 +585,7 @@
      *          read access to the file
      *
      * @since   JDK1.1
+     * @see     Path#toRealPath
      */
     public String getCanonicalPath() throws IOException {
         return fs.canonicalize(fs.resolve(this));
@@ -597,6 +610,7 @@
      *          read access to the file
      *
      * @since 1.2
+     * @see     Path#toRealPath
      */
     public File getCanonicalFile() throws IOException {
         String canonPath = getCanonicalPath();
@@ -663,6 +677,14 @@
      * system is converted into an abstract pathname in a virtual machine on a
      * different operating system.
      *
+     * <p> Note that when this abstract pathname represents a UNC pathname then
+     * all components of the UNC (including the server name component) are encoded
+     * in the {@code URI} path. The authority component is undefined, meaning
+     * that it is represented as {@code null}. The {@link Path} class defines the
+     * {@link Path#toUri toUri} method to encode the server name in the authority
+     * component of the resulting {@code URI}. The {@link #toPath toPath} method
+     * may be used to obtain a {@code Path} representing this abstract pathname.
+     *
      * @return  An absolute, hierarchical URI with a scheme equal to
      *          <tt>"file"</tt>, a path representing this abstract pathname,
      *          and undefined authority, query, and fragment components
@@ -764,6 +786,8 @@
      *          If a security manager exists and its <code>{@link
      *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
      *          method denies read access to the file
+     *
+     * @see Attributes#readBasicFileAttributes
      */
     public boolean isDirectory() {
         SecurityManager security = System.getSecurityManager();
@@ -788,6 +812,8 @@
      *          If a security manager exists and its <code>{@link
      *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
      *          method denies read access to the file
+     *
+     * @see Attributes#readBasicFileAttributes
      */
     public boolean isFile() {
         SecurityManager security = System.getSecurityManager();
@@ -836,6 +862,8 @@
      *          If a security manager exists and its <code>{@link
      *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
      *          method denies read access to the file
+     *
+     * @see Attributes#readBasicFileAttributes
      */
     public long lastModified() {
         SecurityManager security = System.getSecurityManager();
@@ -858,6 +886,8 @@
      *          If a security manager exists and its <code>{@link
      *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
      *          method denies read access to the file
+     *
+     * @see Attributes#readBasicFileAttributes
      */
     public long length() {
         SecurityManager security = System.getSecurityManager();
@@ -907,6 +937,12 @@
      * this pathname denotes a directory, then the directory must be empty in
      * order to be deleted.
      *
+     * <p> 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.
+     *
      * @return  <code>true</code> if and only if the file or directory is
      *          successfully deleted; <code>false</code> otherwise
      *
@@ -973,6 +1009,13 @@
      * will appear in any specific order; they are not, in particular,
      * guaranteed to appear in alphabetical order.
      *
+     * <p> 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.
+     *
      * @return  An array of strings naming the files and directories in the
      *          directory denoted by this abstract pathname.  The array will be
      *          empty if the directory is empty.  Returns {@code null} if
@@ -1024,13 +1067,13 @@
         if ((names == null) || (filter == null)) {
             return names;
         }
-        ArrayList v = new ArrayList();
+        List<String> v = new ArrayList<String>();
         for (int i = 0 ; i < names.length ; i++) {
             if (filter.accept(this, names[i])) {
                 v.add(names[i]);
             }
         }
-        return (String[])(v.toArray(new String[v.size()]));
+        return v.toArray(new String[v.size()]);
     }
 
     /**
@@ -1052,6 +1095,13 @@
      * will appear in any specific order; they are not, in particular,
      * guaranteed to appear in alphabetical order.
      *
+     * <p> 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.
+     *
      * @return  An array of abstract pathnames denoting the files and
      *          directories in the directory denoted by this abstract pathname.
      *          The array will be empty if the directory is empty.  Returns
@@ -1157,6 +1207,12 @@
     /**
      * Creates the directory named by this abstract pathname.
      *
+     * <p> 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  <code>true</code> if and only if the directory was
      *          created; <code>false</code> otherwise
      *
@@ -1222,6 +1278,11 @@
      * already exists.  The return value should always be checked to make sure
      * that the rename operation was successful.
      *
+     * <p> 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.
+     *
      * @param  dest  The new abstract pathname for the named file
      *
      * @return  <code>true</code> if and only if the renaming succeeded;
@@ -1304,10 +1365,14 @@
         return fs.setReadOnly(this);
     }
 
-   /**
+    /**
      * Sets the owner's or everybody's write permission for this abstract
      * pathname.
      *
+     * <p> The {@link 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.
+     *
      * @param   writable
      *          If <code>true</code>, sets the access permission to allow write
      *          operations; if <code>false</code> to disallow write operations
@@ -1371,6 +1436,10 @@
      * Sets the owner's or everybody's read permission for this abstract
      * pathname.
      *
+     * <p> The {@link 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.
+     *
      * @param   readable
      *          If <code>true</code>, sets the access permission to allow read
      *          operations; if <code>false</code> to disallow read operations
@@ -1440,6 +1509,10 @@
      * Sets the owner's or everybody's execute permission for this abstract
      * pathname.
      *
+     * <p> The {@link 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.
+     *
      * @param   executable
      *          If <code>true</code>, sets the access permission to allow execute
      *          operations; if <code>false</code> to disallow execute operations
@@ -1678,44 +1751,44 @@
 
     /* -- Temporary files -- */
 
-    private static final Object tmpFileLock = new Object();
-
-    private static int counter = -1; /* Protected by tmpFileLock */
+    private static class TemporaryDirectory {
+        private TemporaryDirectory() { }
 
-    private static File generateFile(String prefix, String suffix, File dir)
-        throws IOException
-    {
-        if (counter == -1) {
-            counter = new Random().nextInt() & 0xffff;
-        }
-        counter++;
-        return new File(dir, prefix + Integer.toString(counter) + suffix);
-    }
-
-    private static String tmpdir; /* Protected by tmpFileLock */
+        static final String valueAsString = fs.normalize(
+            AccessController.doPrivileged(new GetPropertyAction("java.io.tmpdir")));
+        static final File valueAsFile =
+            new File(valueAsString, fs.prefixLength(valueAsString));
 
-    private static String getTempDir() {
-        if (tmpdir == null)
-            tmpdir = fs.normalize(
-                AccessController.doPrivileged(
-                    new GetPropertyAction("java.io.tmpdir")));
-        return tmpdir;
-    }
+        // file name generation
+        private static final SecureRandom random = new SecureRandom();
+        static File generateFile(String prefix, String suffix, File dir) {
+            long n = random.nextLong();
+            if (n == Long.MIN_VALUE) {
+                n = 0;      // corner case
+            } else {
+                n = Math.abs(n);
+            }
+            return new File(dir, prefix + Long.toString(n) + suffix);
+        }
 
-    private static boolean checkAndCreate(String filename, SecurityManager sm)
-        throws IOException
-    {
-        if (sm != null) {
-            try {
-                sm.checkWrite(filename);
-            } catch (AccessControlException x) {
-                /* Throwing the original AccessControlException could disclose
-                   the location of the default temporary directory, so we
-                   re-throw a more innocuous SecurityException */
-                throw new SecurityException("Unable to create temporary file");
-            }
+        // default file permissions
+        static final FileAttribute<Set<PosixFilePermission>> defaultPosixFilePermissions =
+            PosixFilePermissions.asFileAttribute(EnumSet
+                .of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE));
+        static final boolean isPosix = isPosix();
+        static boolean isPosix() {
+            return AccessController.doPrivileged(
+                new PrivilegedAction<Boolean>() {
+                    public Boolean run() {
+                        try {
+                            return FileSystems.getDefault().getPath(valueAsString)
+                                .getFileStore().supportsFileAttributeView("posix");
+                        } catch (IOException e) {
+                            throw new IOError(e);
+                        }
+                    }
+                });
         }
-        return fs.createFileExclusively(filename);
     }
 
     /**
@@ -1791,22 +1864,29 @@
                                       File directory)
         throws IOException
     {
-        if (prefix == null) throw new NullPointerException();
         if (prefix.length() < 3)
             throw new IllegalArgumentException("Prefix string too short");
-        String s = (suffix == null) ? ".tmp" : suffix;
-        synchronized (tmpFileLock) {
-            if (directory == null) {
-                String tmpDir = getTempDir();
-                directory = new File(tmpDir, fs.prefixLength(tmpDir));
+        if (suffix == null)
+            suffix = ".tmp";
+
+        File tmpdir = (directory != null) ?
+            directory : TemporaryDirectory.valueAsFile;
+        SecurityManager sm = System.getSecurityManager();
+        File f;
+        do {
+            f = TemporaryDirectory.generateFile(prefix, suffix, tmpdir);
+            if (sm != null) {
+                try {
+                    sm.checkWrite(f.getPath());
+                } catch (SecurityException se) {
+                    // don't reveal temporary directory location
+                    if (directory == null)
+                        throw new SecurityException("Unable to create temporary file");
+                    throw se;
+                }
             }
-            SecurityManager sm = System.getSecurityManager();
-            File f;
-            do {
-                f = generateFile(prefix, s, directory);
-            } while (!checkAndCreate(f.getPath(), sm));
-            return f;
-        }
+        } while (!fs.createFileExclusively(f.getPath()));
+        return f;
     }
 
     /**
@@ -1844,6 +1924,122 @@
         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. This method is
+     * equivalent to invoking the {@link #createTempFile(String,String)
+     * createTempFile(prefix,&nbsp;suffix)} method with the addition that the
+     * resulting pathname may be requested to be deleted when the Java virtual
+     * machine terminates, and the initial file attributes to set atomically
+     * when creating the file may be specified.
+     *
+     * <p> When the value of the {@code deleteOnExit} method is {@code true}
+     * then the resulting file is requested to be deleted when the Java virtual
+     * machine terminates as if by invoking the {@link #deleteOnExit deleteOnExit}
+     * method.
+     *
+     * <p> 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.
+     *
+     * @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   deleteOnExit
+     *          {@code true} if the file denoted by resulting pathname be
+     *          deleted when the Java virtual machine terminates
+     * @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</code> 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 <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method does not allow a file to be created. When the {@code
+     *          deleteOnExit} parameter has the value {@code true} then the
+     *          security manager's {@link
+     *          java.lang.SecurityManager#checkDelete(java.lang.String)} is
+     *          invoked to check delete access to the file.
+     * @since 1.7
+     */
+    public static File createTempFile(String prefix,
+                                      String suffix,
+                                      boolean deleteOnExit,
+                                      FileAttribute<?>... attrs)
+        throws IOException
+    {
+        if (prefix.length() < 3)
+            throw new IllegalArgumentException("Prefix string too short");
+        suffix = (suffix == null) ? ".tmp" : suffix;
+
+        // special case POSIX environments so that 0600 is used as the file mode
+        if (TemporaryDirectory.isPosix) {
+            if (attrs.length == 0) {
+                // no attributes so use default permissions
+                attrs = new FileAttribute<?>[1];
+                attrs[0] = TemporaryDirectory.defaultPosixFilePermissions;
+            } else {
+                // check if posix permissions given; if not use default
+                boolean hasPermissions = false;
+                for (int i=0; i<attrs.length; i++) {
+                    if (attrs[i].name().equals("posix:permissions")) {
+                        hasPermissions = true;
+                        break;
+                    }
+                }
+                if (!hasPermissions) {
+                    FileAttribute<?>[] copy = new FileAttribute<?>[attrs.length+1];
+                    System.arraycopy(attrs, 0, copy, 0, attrs.length);
+                    attrs = copy;
+                    attrs[attrs.length-1] =
+                        TemporaryDirectory.defaultPosixFilePermissions;
+                }
+            }
+        }
+
+        // use Path#createFile to create file
+        SecurityManager sm = System.getSecurityManager();
+        for (;;) {
+            File f = TemporaryDirectory
+                .generateFile(prefix, suffix, TemporaryDirectory.valueAsFile);
+            if (sm != null && deleteOnExit)
+                sm.checkDelete(f.getPath());
+            try {
+                f.toPath().createFile(attrs);
+                if (deleteOnExit)
+                    DeleteOnExitHook.add(f.getPath());
+                return f;
+            } catch (InvalidPathException e) {
+                // don't reveal temporary directory location
+                if (sm != null)
+                    throw new IllegalArgumentException("Invalid prefix or suffix");
+                throw e;
+            } catch (SecurityException e) {
+                // don't reveal temporary directory location
+                if (sm != null)
+                    throw new SecurityException("Unable to create temporary file");
+                throw e;
+            } catch (FileAlreadyExistsException e) {
+                // ignore
+            }
+        }
+    }
 
     /* -- Basic infrastructure -- */
 
@@ -1963,5 +2159,46 @@
         );
     }
 
+    // -- Integration with java.nio.file --
 
+    private volatile transient Path filePath;
+
+    /**
+     * Returns a {@link Path java.nio.file.Path} object constructed from the
+     * this abstract path. The first invocation of this method works as if
+     * invoking it were equivalent to evaluating the expression:
+     * <blockquote><pre>
+     * {@link FileSystems#getDefault FileSystems.getDefault}().{@link FileSystem#getPath getPath}(this.{@link #getPath getPath}());
+     * </pre></blockquote>
+     * Subsequent invocations of this method return the same {@code Path}.
+     *
+     * <p> If this abstract pathname is the empty abstract pathname then this
+     * method returns a {@code Path} that may be used to access to the current
+     * user directory.
+     *
+     * @return  A {@code Path} constructed from this abstract path. The resulting
+     *          {@code Path} is associated with the {@link FileSystems#getDefault
+     *          default-filesystem}.
+     *
+     * @throws  InvalidPathException
+     *          If a {@code Path} object cannot be constructed from the abstract
+     *          path (see {@link java.nio.file.FileSystem#getPath FileSystem.getPath})
+     *
+     * @since   1.7
+     */
+    public Path toPath() {
+        if (filePath == null) {
+            synchronized (this) {
+                if (filePath == null) {
+                    if (path.length() == 0) {
+                        // assume default file system treats "." as current directory
+                        filePath = Paths.get(".");
+                    } else {
+                        filePath = Paths.get(path);
+                    }
+                }
+            }
+        }
+        return filePath;
+    }
 }
--- a/jdk/src/share/classes/java/io/FilePermission.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/io/FilePermission.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -29,7 +29,6 @@
 import java.util.Enumeration;
 import java.util.List;
 import java.util.ArrayList;
-import java.util.StringTokenizer;
 import java.util.Vector;
 import java.util.Collections;
 import java.io.ObjectStreamField;
@@ -58,7 +57,8 @@
  * <P>
  * The actions to be granted are passed to the constructor in a string containing
  * a list of one or more comma-separated keywords. The possible keywords are
- * "read", "write", "execute", and "delete". Their meaning is defined as follows:
+ * "read", "write", "execute", "delete", and "readlink". Their meaning is
+ * defined as follows:
  * <P>
  * <DL>
  *    <DT> read <DD> read permission
@@ -69,6 +69,11 @@
  *    <DT> delete
  *    <DD> delete permission. Allows <code>File.delete</code> to
  *         be called. Corresponds to <code>SecurityManager.checkDelete</code>.
+ *    <DT> readlink
+ *    <DD> read link permission. Allows the target of a
+ *         <a href="../nio/file/package-summary.html#links">symbolic link</a>
+ *         to be read by invoking the {@link java.nio.file.Path#readSymbolicLink
+ *         readSymbolicLink } method.
  * </DL>
  * <P>
  * The actions string is converted to lowercase before processing.
@@ -114,11 +119,15 @@
      * Delete action.
      */
     private final static int DELETE  = 0x8;
+    /**
+     * Read link action.
+     */
+    private final static int READLINK    = 0x10;
 
     /**
-     * All actions (read,write,execute,delete)
+     * All actions (read,write,execute,delete,readlink)
      */
-    private final static int ALL     = READ|WRITE|EXECUTE|DELETE;
+    private final static int ALL     = READ|WRITE|EXECUTE|DELETE|READLINK;
     /**
      * No actions.
      */
@@ -235,7 +244,7 @@
      * <i>path</i> is the pathname of a file or directory, and <i>actions</i>
      * contains a comma-separated list of the desired actions granted on the
      * file or directory. Possible actions are
-     * "read", "write", "execute", and "delete".
+     * "read", "write", "execute", "delete", and "readlink".
      *
      * <p>A pathname that ends in "/*" (where "/" is
      * the file separator character, <code>File.separatorChar</code>)
@@ -425,6 +434,8 @@
             return EXECUTE;
         } else if (actions == SecurityConstants.FILE_DELETE_ACTION) {
             return DELETE;
+        } else if (actions == SecurityConstants.FILE_READLINK_ACTION) {
+            return READLINK;
         }
 
         char[] a = actions.toCharArray();
@@ -485,6 +496,18 @@
                 matchlen = 6;
                 mask |= DELETE;
 
+            } else if (i >= 7 && (a[i-7] == 'r' || a[i-7] == 'R') &&
+                                 (a[i-6] == 'e' || a[i-6] == 'E') &&
+                                 (a[i-5] == 'a' || a[i-5] == 'A') &&
+                                 (a[i-4] == 'd' || a[i-4] == 'D') &&
+                                 (a[i-3] == 'l' || a[i-3] == 'L') &&
+                                 (a[i-2] == 'i' || a[i-2] == 'I') &&
+                                 (a[i-1] == 'n' || a[i-1] == 'N') &&
+                                 (a[i] == 'k' || a[i] == 'K'))
+            {
+                matchlen = 8;
+                mask |= READLINK;
+
             } else {
                 // parse error
                 throw new IllegalArgumentException(
@@ -529,7 +552,7 @@
     /**
      * Return the canonical string representation of the actions.
      * Always returns present actions in the following order:
-     * read, write, execute, delete.
+     * read, write, execute, delete, readlink.
      *
      * @return the canonical string representation of the actions.
      */
@@ -561,14 +584,20 @@
             sb.append("delete");
         }
 
+        if ((mask & READLINK) == READLINK) {
+            if (comma) sb.append(',');
+            else comma = true;
+            sb.append("readlink");
+        }
+
         return sb.toString();
     }
 
     /**
      * Returns the "canonical string representation" of the actions.
      * That is, this method always returns present actions in the following order:
-     * read, write, execute, delete. For example, if this FilePermission object
-     * allows both write and read actions, a call to <code>getActions</code>
+     * read, write, execute, delete, readlink. For example, if this FilePermission
+     * object allows both write and read actions, a call to <code>getActions</code>
      * will return the string "read,write".
      *
      * @return the canonical string representation of the actions.
@@ -678,7 +707,7 @@
 implements Serializable {
 
     // Not serialized; see serialization section at end of class
-    private transient List perms;
+    private transient List<Permission> perms;
 
     /**
      * Create an empty FilePermissions object.
@@ -686,7 +715,7 @@
      */
 
     public FilePermissionCollection() {
-        perms = new ArrayList();
+        perms = new ArrayList<Permission>();
     }
 
     /**
@@ -791,7 +820,7 @@
         // Don't call out.defaultWriteObject()
 
         // Write out Vector
-        Vector permissions = new Vector(perms.size());
+        Vector<Permission> permissions = new Vector<Permission>(perms.size());
         synchronized (this) {
             permissions.addAll(perms);
         }
@@ -804,6 +833,7 @@
     /*
      * Reads in a Vector of FilePermissions and saves them in the perms field.
      */
+    @SuppressWarnings("unchecked")
     private void readObject(ObjectInputStream in) throws IOException,
     ClassNotFoundException {
         // Don't call defaultReadObject()
@@ -812,8 +842,8 @@
         ObjectInputStream.GetField gfields = in.readFields();
 
         // Get the one we want
-        Vector permissions = (Vector)gfields.get("permissions", null);
-        perms = new ArrayList(permissions.size());
+        Vector<Permission> permissions = (Vector<Permission>)gfields.get("permissions", null);
+        perms = new ArrayList<Permission>(permissions.size());
         perms.addAll(permissions);
     }
 }
--- a/jdk/src/share/classes/java/net/StandardProtocolFamily.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/net/StandardProtocolFamily.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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
@@ -26,7 +26,7 @@
 package java.net;
 
 /**
- * Defines the standard family of communication protocols.
+ * Defines the standard families of communication protocols.
  *
  * @since 1.7
  */
--- a/jdk/src/share/classes/java/net/StandardSocketOption.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/net/StandardSocketOption.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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
@@ -59,6 +59,7 @@
      *
      * @see <a href="http://www.ietf.org/rfc/rfc919.txt">RFC&nbsp;929:
      * Broadcasting Internet Datagrams</a>
+     * @see DatagramSocket#setBroadcast
      */
     public static final SocketOption<Boolean> SO_BROADCAST =
         new StdSocketOption<Boolean>("SO_BROADCAST", Boolean.class);
@@ -78,6 +79,7 @@
      *
      * @see <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC&nbsp;1122
      * Requirements for Internet Hosts -- Communication Layers</a>
+     * @see Socket#setKeepAlive
      */
     public static final SocketOption<Boolean> SO_KEEPALIVE =
         new StdSocketOption<Boolean>("SO_KEEPALIVE", Boolean.class);
@@ -107,6 +109,8 @@
      * socket is bound or connected. Whether an implementation allows the
      * socket send buffer to be changed after the socket is bound is system
      * dependent.
+     *
+     * @see Socket#setSendBufferSize
      */
     public static final SocketOption<Integer> SO_SNDBUF =
         new StdSocketOption<Integer>("SO_SNDBUF", Integer.class);
@@ -145,6 +149,8 @@
      *
      * @see <a href="http://www.ietf.org/rfc/rfc1323.txt">RFC&nbsp;1323: TCP
      * Extensions for High Performance</a>
+     * @see Socket#setReceiveBufferSize
+     * @see ServerSocket#setReceiveBufferSize
      */
     public static final SocketOption<Integer> SO_RCVBUF =
         new StdSocketOption<Integer>("SO_RCVBUF", Integer.class);
@@ -175,6 +181,7 @@
      *
      * @see <a href="http://www.ietf.org/rfc/rfc793.txt">RFC&nbsp;793: Transmission
      * Control Protocol</a>
+     * @see ServerSocket#setReuseAddress
      */
     public static final SocketOption<Boolean> SO_REUSEADDR =
         new StdSocketOption<Boolean>("SO_REUSEADDR", Boolean.class);
@@ -205,6 +212,8 @@
      * is system dependent. Setting the linger interval to a value that is
      * greater than its maximum value causes the linger interval to be set to
      * its maximum value.
+     *
+     * @see Socket#setSoLinger
      */
     public static final SocketOption<Integer> SO_LINGER =
         new StdSocketOption<Integer>("SO_LINGER", Integer.class);
@@ -215,15 +224,15 @@
     /**
      * The Type of Service (ToS) octet in the Internet Protocol (IP) header.
      *
-     * <p> The value of this socket option is an {@code Integer}, the least
-     * significant 8 bits of which represents the value of the ToS octet in IP
-     * packets sent by sockets to an {@link StandardProtocolFamily#INET IPv4}
-     * socket. The interpretation of the ToS octet is network specific and
-     * is not defined by this class. Further information on the ToS octet can be
-     * found in <a href="http://www.ietf.org/rfc/rfc1349.txt">RFC&nbsp;1349</a>
-     * and <a href="http://www.ietf.org/rfc/rfc2474.txt">RFC&nbsp;2474</a>. The
-     * value of the socket option is a <em>hint</em>. An implementation may
-     * ignore the value, or ignore specific values.
+     * <p> The value of this socket option is an {@code Integer} representing
+     * the value of the ToS octet in IP packets sent by sockets to an {@link
+     * StandardProtocolFamily#INET IPv4} socket. The interpretation of the ToS
+     * octet is network specific and is not defined by this class. Further
+     * information on the ToS octet can be found in <a
+     * href="http://www.ietf.org/rfc/rfc1349.txt">RFC&nbsp;1349</a> and <a
+     * href="http://www.ietf.org/rfc/rfc2474.txt">RFC&nbsp;2474</a>. The value
+     * of the socket option is a <em>hint</em>. An implementation may ignore the
+     * value, or ignore specific values.
      *
      * <p> The initial/default value of the TOS field in the ToS octet is
      * implementation specific but will typically be {@code 0}. For
@@ -235,6 +244,8 @@
      * <p> The behavior of this socket option on a stream-oriented socket, or an
      * {@link StandardProtocolFamily#INET6 IPv6} socket, is not defined in this
      * release.
+     *
+     * @see DatagramSocket#setTrafficClass
      */
     public static final SocketOption<Integer> IP_TOS =
         new StdSocketOption<Integer>("IP_TOS", Integer.class);
@@ -257,6 +268,7 @@
      * is system dependent.
      *
      * @see java.nio.channels.MulticastChannel
+     * @see MulticastSocket#setInterface
      */
     public static final SocketOption<NetworkInterface> IP_MULTICAST_IF =
         new StdSocketOption<NetworkInterface>("IP_MULTICAST_IF", NetworkInterface.class);
@@ -283,6 +295,7 @@
      * prior to binding the socket is system dependent.
      *
      * @see java.nio.channels.MulticastChannel
+     * @see MulticastSocket#setTimeToLive
      */
     public static final SocketOption<Integer> IP_MULTICAST_TTL =
         new StdSocketOption<Integer>("IP_MULTICAST_TTL", Integer.class);
@@ -307,6 +320,7 @@
      * binding the socket is system dependent.
      *
      * @see java.nio.channels.MulticastChannel
+     *  @see MulticastSocket#setLoopbackMode
      */
     public static final SocketOption<Boolean> IP_MULTICAST_LOOP =
         new StdSocketOption<Boolean>("IP_MULTICAST_LOOP", Boolean.class);
@@ -328,11 +342,12 @@
      * coalescing impacts performance. The socket option may be enabled at any
      * time. In other words, the Nagle Algorithm can be disabled. Once the option
      * is enabled, it is system dependent whether it can be subsequently
-     * disabled. In that case, invoking the {@code setOption} method to disable
-     * the option has no effect.
+     * disabled. If it cannot, then invoking the {@code setOption} method to
+     * disable the option has no effect.
      *
      * @see <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC&nbsp;1122:
      * Requirements for Internet Hosts -- Communication Layers</a>
+     * @see Socket#setTcpNoDelay
      */
     public static final SocketOption<Boolean> TCP_NODELAY =
         new StdSocketOption<Boolean>("TCP_NODELAY", Boolean.class);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/AsynchronousByteChannel.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.channels;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.Future;
+
+/**
+ * An asynchronous channel that can read and write bytes.
+ *
+ * <p> Some channels may not allow more than one read or write to be outstanding
+ * at any given time. If a thread invokes a read method before a previous read
+ * operation has completed then a {@link ReadPendingException} will be thrown.
+ * Similarly, if a write method is invoked before a previous write has completed
+ * then {@link WritePendingException} is thrown. Whether or not other kinds of
+ * I/O operations may proceed concurrently with a read operation depends upon
+ * the type of the channel.
+ *
+ * <p> Note that {@link java.nio.ByteBuffer ByteBuffers} are not safe for use by
+ * multiple concurrent threads. When a read or write operation is initiated then
+ * care must be taken to ensure that the buffer is not accessed until the
+ * operation completes.
+ *
+ * @see Channels#newInputStream(AsynchronousByteChannel)
+ * @see Channels#newOutputStream(AsynchronousByteChannel)
+ *
+ * @since 1.7
+ */
+
+public interface AsynchronousByteChannel
+    extends AsynchronousChannel
+{
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer.
+     *
+     * <p> This method initiates an operation to read a sequence of bytes from
+     * this channel into the given buffer. The method returns a {@link Future}
+     * representing the pending result of the operation. The result of the
+     * operation, obtained by invoking the {@code Future} 's {@link
+     * Future#get() get} method, is the number of bytes read or {@code -1} if
+     * all bytes have been read and the channel has reached end-of-stream.
+     *
+     * <p> This method initiates a read operation to read up to <i>r</i> bytes
+     * from the channel, where <i>r</i> is the number of bytes remaining in the
+     * buffer, that is, {@code dst.remaining()} at the time that the read is
+     * attempted. Where <i>r</i> is 0, the read operation completes immediately
+     * with a result of {@code 0} without initiating an I/O operation.
+     *
+     * <p> Suppose that a byte sequence of length <i>n</i> is read, where
+     * <tt>0</tt>&nbsp;<tt>&lt;</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>.
+     * This byte sequence will be transferred into the buffer so that the first
+     * byte in the sequence is at index <i>p</i> and the last byte is at index
+     * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>&nbsp;<tt>-</tt>&nbsp;<tt>1</tt>,
+     * where <i>p</i> is the buffer's position at the moment the read is
+     * performed. Upon completion the buffer's position will be equal to
+     * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>; its limit will not have changed.
+     *
+     * <p> Buffers are not safe for use by multiple concurrent threads so care
+     * should be taken to not to access the buffer until the operaton has completed.
+     *
+     * <p> This method may be invoked at any time. Some channel types may not
+     * allow more than one read to be outstanding at any given time. If a thread
+     * initiates a read operation before a previous read operation has
+     * completed then a {@link ReadPendingException} will be thrown.
+     *
+     * <p> The <tt>handler</tt> parameter is used to specify a {@link
+     * CompletionHandler}. When the read operation completes the handler's
+     * {@link CompletionHandler#completed completed} method is executed.
+     *
+     *
+     * @param   dst
+     *          The buffer into which bytes are to be transferred
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The completion handler object; can be {@code null}
+     *
+     * @return  A Future representing the result of the operation
+     *
+     * @throws  IllegalArgumentException
+     *          If the buffer is read-only
+     * @throws  ReadPendingException
+     *          If the channel does not allow more than one read to be outstanding
+     *          and a previous read has not completed
+     */
+    <A> Future<Integer> read(ByteBuffer dst,
+                             A attachment,
+                             CompletionHandler<Integer,? super A> handler);
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer.
+     *
+     * <p> An invocation of this method of the form <tt>c.read(dst)</tt>
+     * behaves in exactly the same manner as the invocation
+     * <blockquote><pre>
+     * c.read(dst, null, null);</pre></blockquote>
+     *
+     * @param   dst
+     *          The buffer into which bytes are to be transferred
+     *
+     * @return  A Future representing the result of the operation
+     *
+     * @throws  IllegalArgumentException
+     *          If the buffer is read-only
+     * @throws  ReadPendingException
+     *          If the channel does not allow more than one read to be outstanding
+     *          and a previous read has not completed
+     */
+    Future<Integer> read(ByteBuffer dst);
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer.
+     *
+     * <p> This method initiates an operation to write a sequence of bytes to
+     * this channel from the given buffer. This method returns a {@link
+     * Future} representing the pending result of the operation. The result
+     * of the operation, obtained by invoking the <tt>Future</tt>'s {@link
+     * Future#get() get} method, is the number of bytes written, possibly zero.
+     *
+     * <p> This method initiates a write operation to write up to <i>r</i> bytes
+     * to the channel, where <i>r</i> is the number of bytes remaining in the
+     * buffer, that is, {@code src.remaining()}  at the moment the write is
+     * attempted. Where <i>r</i> is 0, the write operation completes immediately
+     * with a result of {@code 0} without initiating an I/O operation.
+     *
+     * <p> Suppose that a byte sequence of length <i>n</i> is written, where
+     * <tt>0</tt>&nbsp;<tt>&lt;</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>.
+     * This byte sequence will be transferred from the buffer starting at index
+     * <i>p</i>, where <i>p</i> is the buffer's position at the moment the
+     * write is performed; the index of the last byte written will be
+     * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>&nbsp;<tt>-</tt>&nbsp;<tt>1</tt>.
+     * Upon completion the buffer's position will be equal to
+     * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>; its limit will not have changed.
+     *
+     * <p> Buffers are not safe for use by multiple concurrent threads so care
+     * should be taken to not to access the buffer until the operaton has completed.
+     *
+     * <p> This method may be invoked at any time. Some channel types may not
+     * allow more than one write to be outstanding at any given time. If a thread
+     * initiates a write operation before a previous write operation has
+     * completed then a {@link WritePendingException} will be thrown.
+     *
+     * <p> The <tt>handler</tt> parameter is used to specify a {@link
+     * CompletionHandler}. When the write operation completes the handler's
+     * {@link CompletionHandler#completed completed} method is executed.
+     *
+     * @param   src
+     *          The buffer from which bytes are to be retrieved
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The completion handler object; can be {@code null}
+     *
+     * @return  A Future representing the result of the operation
+     *
+     * @throws  WritePendingException
+     *          If the channel does not allow more than one write to be outstanding
+     *          and a previous write has not completed
+     */
+    <A> Future<Integer> write(ByteBuffer src,
+                              A attachment,
+                              CompletionHandler<Integer,? super A> handler);
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer.
+     *
+     * <p> An invocation of this method of the form <tt>c.write(src)</tt>
+     * behaves in exactly the same manner as the invocation
+     * <blockquote><pre>
+     * c.write(src, null, null);</pre></blockquote>
+     *
+     * @param   src
+     *          The buffer from which bytes are to be retrieved
+     *
+     * @return A Future representing the result of the operation
+     *
+     * @throws  WritePendingException
+     *          If the channel does not allow more than one write to be outstanding
+     *          and a previous write has not completed
+     */
+    Future<Integer> write(ByteBuffer src);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/AsynchronousChannel.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+import java.util.concurrent.Future;  // javadoc
+
+/**
+ * A channel that supports asynchronous I/O operations. Asynchronous I/O
+ * operations will usually take one of two forms:
+ *
+ * <ol>
+ * <li><pre>{@link Future}&lt;V&gt; <em>operation</em>(<em>...</em>)</pre></li>
+ * <li><pre>Future&lt;V&gt; <em>operation</em>(<em>...</em> A attachment, {@link CompletionHandler}&lt;V,? super A&gt handler)</pre></li>
+ * </ol>
+ *
+ * where <i>operation</i> is the name of the I/O operation (read or write for
+ * example), <i>V</i> is the result type of the I/O operation, and <i>A</i> is
+ * the type of an object attached to the I/O operation to provide context when
+ * consuming the result. The attachment is important for cases where a
+ * <em>state-less</em> {@code CompletionHandler} is used to consume the result
+ * of many I/O operations.
+ *
+ * <p> In the first form, the methods defined by the {@link Future Future}
+ * interface may be used to check if the operation has completed, wait for its
+ * completion, and to retrieve the result. In the second form, a {@link
+ * CompletionHandler} is invoked to consume the result of the I/O operation when
+ * it completes, fails, or is cancelled.
+ *
+ * <p> A channel that implements this interface is <em>asynchronously
+ * closeable</em>: If an I/O operation is outstanding on the channel and the
+ * channel's {@link #close close} method is invoked, then the I/O operation
+ * fails with the exception {@link AsynchronousCloseException}.
+ *
+ * <p> Asynchronous channels are safe for use by multiple concurrent threads.
+ * Some channel implementations may support concurrent reading and writing, but
+ * may not allow more than one read and one write operation to be outstanding at
+ * any given time.
+ *
+ * <h4>Cancellation</h4>
+ *
+ * <p> The {@code Future} interface defines the {@link Future#cancel cancel}
+ * method to cancel execution of a task.
+ *
+ * <p> Where the {@code cancel} method is invoked with the {@code
+ * mayInterruptIfRunning} parameter set to {@code true} then the I/O operation
+ * may be interrupted by closing the channel. This will cause any other I/O
+ * operations outstanding on the channel to complete with the exception {@link
+ * AsynchronousCloseException}.
+ *
+ * <p> If a {@code CompletionHandler} is specified when initiating an I/O
+ * operation, and the {@code cancel} method is invoked to cancel the I/O
+ * operation before it completes, then the {@code CompletionHandler}'s {@link
+ * CompletionHandler#cancelled cancelled} method is invoked.
+ *
+ * <p> If an implementation of this interface supports a means to cancel I/O
+ * operations, and where cancellation may leave the channel, or the entity to
+ * which it is connected, in an inconsistent state, then the channel is put into
+ * an implementation specific <em>error state</em> that prevents further
+ * attempts to initiate I/O operations on the channel. For example, if a read
+ * operation is cancelled but the implementation cannot guarantee that bytes
+ * have not been read from the channel then it puts the channel into error state
+ * state; further attempts to initiate a {@code read} operation causes an
+ * unspecified runtime exception to be thrown.
+ *
+ * <p> Where the {@code cancel} method is invoked to cancel read or write
+ * operations then it recommended that all buffers used in the I/O operations be
+ * discarded or care taken to ensure that the buffers are not accessed while the
+ * channel remains open.
+ *
+ *  @since 1.7
+ */
+
+public interface AsynchronousChannel
+    extends Channel
+{
+    /**
+     * Closes this channel.
+     *
+     * <p> Any outstanding asynchronous operations upon this channel will
+     * complete with the exception {@link AsynchronousCloseException}. After a
+     * channel is closed then further attempts to initiate asynchronous I/O
+     * operations complete immediately with cause {@link ClosedChannelException}.
+     *
+     * <p>  This method otherwise behaves exactly as specified by the {@link
+     * Channel} interface.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    @Override
+    void close() throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/AsynchronousChannelGroup.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.channels;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A grouping of asynchronous channels for the purpose of resource sharing.
+ *
+ * <p> An asynchronous channel group encapsulates the mechanics required to
+ * handle the completion of I/O operations initiated by {@link AsynchronousChannel
+ * asynchronous channels} that are bound to the group. A group has an associated
+ * thread pool to which tasks are submitted to handle I/O events and dispatch to
+ * {@link CompletionHandler completion-handlers} that consume the result of
+ * asynchronous operations performed on channels in the group. In addition to
+ * handling I/O events, the pooled threads may also execute other tasks required
+ * to support the execution of asynchronous I/O operations.
+ *
+ * <p> An asynchronous channel group is created by invoking the {@link
+ * #withFixedThreadPool withFixedThreadPool} or {@link #withCachedThreadPool
+ * withCachedThreadPool} methods defined here. Channels are bound to a group by
+ * specifying the group when constructing the channel. The associated thread
+ * pool is <em>owned</em> by the group; termination of the group results in the
+ * shutdown of the associated thread pool.
+ *
+ * <p> In addition to groups created explicitly, the Java virtual machine
+ * maintains a system-wide <em>default group</em> that is constructed
+ * automatically. Asynchronous channels that do not specify a group at
+ * construction time are bound to the default group. The default group has an
+ * associated thread pool that creates new threads as needed. The default group
+ * may be configured by means of system properties defined in the table below.
+ * Where the {@link java.util.concurrent.ThreadFactory ThreadFactory} for the
+ * default group is not configured then the pooled threads of the default group
+ * are {@link Thread#isDaemon daemon} threads.
+ *
+ * <table border>
+ *   <tr>
+ *     <th>System property</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *   <tr>
+ *     <td> {@code java.nio.channels.DefaultThreadPool.threadFactory} </td>
+ *     <td> The value of this property is taken to be the fully-qualified name
+ *     of a concrete {@link java.util.concurrent.ThreadFactory ThreadFactory}
+ *     class. The class is loaded using the system class loader and instantiated.
+ *     The factory's {@link java.util.concurrent.ThreadFactory#newThread
+ *     newThread} method is invoked to create each thread for the default
+ *     group's thread pool. If the process to load and instantiate the value
+ *     of the property fails then an unspecified error is thrown during the
+ *     construction of the default group. </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@code java.nio.channels.DefaultThreadPool.initialSize} </td>
+ *     <td> The value of the {@code initialSize} parameter for the default
+ *     group (see {@link #withCachedThreadPool withCachedThreadPool}).
+ *     The value of the property is taken to be the {@code String}
+ *     representation of an {@code Integer} that is the initial size parameter.
+ *     If the value cannot be parsed as an {@code Integer} it causes an
+ *     unspecified error to be thrown during the construction of the default
+ *     group. </td>
+ *   </tr>
+ * </table>
+ *
+ * <a name="threading"><h4>Threading</h4></a>
+ *
+ * <p> The completion handler for an I/O operation initiated on a channel bound
+ * to a group is guaranteed to be invoked by one of the pooled threads in the
+ * group. This ensures that the completion handler is run by a thread with the
+ * expected <em>identity</em>.
+ *
+ * <p> Where an I/O operation completes immediately, and the initiating thread
+ * is one of the pooled threads in the group then the completion handler may
+ * be invoked directly by the initiating thread. To avoid stack overflow, an
+ * implementation may impose a limit as to the number of activations on the
+ * thread stack. Some I/O operations may prohibit invoking the completion
+ * handler directly by the initiating thread (see {@link
+ * AsynchronousServerSocketChannel#accept(Object,CompletionHandler) accept}).
+ *
+ * <a name="shutdown"><h4>Shutdown and Termination</h4></a>
+ *
+ * <p> The {@link #shutdown() shutdown} method is used to initiate an <em>orderly
+ * shutdown</em> of a group. An orderly shutdown marks the group as shutdown;
+ * further attempts to construct a channel that binds to the group will throw
+ * {@link ShutdownChannelGroupException}. Whether or not a group is shutdown can
+ * be tested using the {@link #isShutdown() isShutdown} method. Once shutdown,
+ * the group <em>terminates</em> when all asynchronous channels that are bound to
+ * the group are closed, all actively executing completion handlers have run to
+ * completion, and resources used by the group are released. No attempt is made
+ * to stop or interrupt threads that are executing completion handlers. The
+ * {@link #isTerminated() isTerminated} method is used to test if the group has
+ * terminated, and the {@link #awaitTermination awaitTermination} method can be
+ * used to block until the group has terminated.
+ *
+ * <p> The {@link #shutdownNow() shutdownNow} method can be used to initiate a
+ * <em>forceful shutdown</em> of the group. In addition to the actions performed
+ * by an orderly shutdown, the {@code shutdownNow} method closes all open channels
+ * in the group as if by invoking the {@link AsynchronousChannel#close close}
+ * method.
+ *
+ * @since 1.7
+ *
+ * @see AsynchronousSocketChannel#open(AsynchronousChannelGroup)
+ * @see AsynchronousServerSocketChannel#open(AsynchronousChannelGroup)
+ */
+
+public abstract class AsynchronousChannelGroup {
+    private final AsynchronousChannelProvider provider;
+
+    /**
+     * Initialize a new instance of this class.
+     *
+     * @param   provider
+     *          The asynchronous channel provider for this group
+     */
+    protected AsynchronousChannelGroup(AsynchronousChannelProvider provider) {
+        this.provider = provider;
+    }
+
+    /**
+     * Returns the provider that created this channel group.
+     *
+     * @return  The provider that created this channel group
+     */
+    public final AsynchronousChannelProvider provider() {
+        return provider;
+    }
+
+    /**
+     * Creates an asynchronous channel group with a fixed thread pool.
+     *
+     * <p> The resulting asynchronous channel group reuses a fixed number of
+     * threads. At any point, at most {@code nThreads} threads will be active
+     * processing tasks that are submitted to handle I/O events and dispatch
+     * completion results for operations initiated on asynchronous channels in
+     * the group.
+     *
+     * <p> The group is created by invoking the {@link
+     * AsynchronousChannelProvider#openAsynchronousChannelGroup(int,ThreadFactory)
+     * openAsynchronousChannelGroup(int,ThreadFactory)} method of the system-wide
+     * default {@link AsynchronousChannelProvider} object.
+     *
+     * @param   nThreads
+     *          The number of threads in the pool
+     * @param   threadFactory
+     *          The factory to use when creating new threads
+     *
+     * @return  A new asynchronous channel group
+     *
+     * @throws  IllegalArgumentException
+     *          If {@code nThreads <= 0}
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousChannelGroup withFixedThreadPool(int nThreads,
+                                                               ThreadFactory threadFactory)
+        throws IOException
+    {
+        return AsynchronousChannelProvider.provider()
+            .openAsynchronousChannelGroup(nThreads, threadFactory);
+    }
+
+    /**
+     * Creates an asynchronous channel group with a given thread pool that
+     * creates new threads as needed.
+     *
+     * <p> The {@code executor} parameter is an {@code ExecutorService} that
+     * creates new threads as needed to execute tasks that are submitted to
+     * handle I/O events and dispatch completion results for operations initiated
+     * on asynchronous channels in the group. It may reuse previously constructed
+     * threads when they are available.
+     *
+     * <p> The {@code initialSize} parameter may be used by the implementation
+     * as a <em>hint</em> as to the initial number of tasks it may submit. For
+     * example, it may be used to indictae the initial number of threads that
+     * wait on I/O events.
+     *
+     * <p> The executor is intended to be used exclusively by the resulting
+     * asynchronous channel group. Termination of the group results in the
+     * orderly  {@link ExecutorService#shutdown shutdown} of the executor
+     * service. Shutting down the executor service by other means results in
+     * unspecified behavior.
+     *
+     * <p> The group is created by invoking the {@link
+     * AsynchronousChannelProvider#openAsynchronousChannelGroup(ExecutorService,int)
+     * openAsynchronousChannelGroup(ExecutorService,int)} method of the system-wide
+     * default {@link AsynchronousChannelProvider} object.
+     *
+     * @param   executor
+     *          The thread pool for the resulting group
+     * @param   initialSize
+     *          A value {@code >=0} or a negative value for implementation
+     *          specific default
+     *
+     * @return  A new asynchronous channel group
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see java.util.concurrent.Executors#newCachedThreadPool
+     */
+    public static AsynchronousChannelGroup withCachedThreadPool(ExecutorService executor,
+                                                                int initialSize)
+        throws IOException
+    {
+        return AsynchronousChannelProvider.provider()
+            .openAsynchronousChannelGroup(executor, initialSize);
+    }
+
+    /**
+     * Creates an asynchronous channel group with a given thread pool.
+     *
+     * <p> The {@code executor} parameter is an {@code ExecutorService} that
+     * executes tasks submitted to dispatch completion results for operations
+     * initiated on asynchronous channels in the group.
+     *
+     * <p> Care should be taken when configuring the executor service. It
+     * should support <em>direct handoff</em> or <em>unbounded queuing</em> of
+     * submitted tasks, and the thread that invokes the {@link
+     * ExecutorService#execute execute} method should never invoke the task
+     * directly. An implementation may mandate additional constraints.
+     *
+     * <p> The executor is intended to be used exclusively by the resulting
+     * asynchronous channel group. Termination of the group results in the
+     * orderly  {@link ExecutorService#shutdown shutdown} of the executor
+     * service. Shutting down the executor service by other means results in
+     * unspecified behavior.
+     *
+     * <p> The group is created by invoking the {@link
+     * AsynchronousChannelProvider#openAsynchronousChannelGroup(ExecutorService,int)
+     * openAsynchronousChannelGroup(ExecutorService,int)} method of the system-wide
+     * default {@link AsynchronousChannelProvider} object with an {@code
+     * initialSize} of {@code 0}.
+     *
+     * @param   executor
+     *          The thread pool for the resulting group
+     *
+     * @return  A new asynchronous channel group
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousChannelGroup withThreadPool(ExecutorService executor)
+        throws IOException
+    {
+        return AsynchronousChannelProvider.provider()
+            .openAsynchronousChannelGroup(executor, 0);
+    }
+
+    /**
+     * Tells whether or not this asynchronous channel group is shutdown.
+     *
+     * @return  {@code true} if this asynchronous channel group is shutdown or
+     *          has been marked for shutdown.
+     */
+    public abstract boolean isShutdown();
+
+    /**
+     * Tells whether or not this group has terminated.
+     *
+     * <p> Where this method returns {@code true}, then the associated thread
+     * pool has also {@link ExecutorService#isTerminated terminated}.
+     *
+     * @return  {@code true} if this group has terminated
+     */
+    public abstract boolean isTerminated();
+
+    /**
+     * Initiates an orderly shutdown of the group.
+     *
+     * <p> This method marks the group as shutdown. Further attempts to construct
+     * channel that binds to this group will throw {@link ShutdownChannelGroupException}.
+     * The group terminates when all asynchronous channels in the group are
+     * closed, all actively executing completion handlers have run to completion,
+     * and all resources have been released. This method has no effect if the
+     * group is already shutdown.
+     */
+    public abstract void shutdown();
+
+    /**
+     * Shuts down the group and closes all open channels in the group.
+     *
+     * <p> In addition to the actions performed by the {@link #shutdown() shutdown}
+     * method, this method invokes the {@link AsynchronousChannel#close close}
+     * method on all open channels in the group. This method does not attempt to
+     * stop or interrupt threads that are executing completion handlers. The
+     * group terminates when all actively executing completion handlers have run
+     * to completion and all resources have been released. This method may be
+     * invoked at any time. If some other thread has already invoked it, then
+     * another invocation will block until the first invocation is complete,
+     * after which it will return without effect.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract void shutdownNow() throws IOException;
+
+    /**
+     * Awaits termination of the group.
+
+     * <p> This method blocks until the group has terminated, or the timeout
+     * occurs, or the current thread is interrupted, whichever happens first.
+     *
+     * @param   timeout
+     *          The maximum time to wait, or zero or less to not wait
+     * @param   unit
+     *          The time unit of the timeout argument
+     *
+     * @return  {@code true} if the group has terminated; {@code false} if the
+     *          timeout elapsed before termination
+     *
+     * @throws  InterruptedException
+     *          If interrupted while waiting
+     */
+    public abstract boolean awaitTermination(long timeout, TimeUnit unit)
+        throws InterruptedException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,718 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.channels;
+
+import java.nio.channels.spi.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.Future;
+import java.io.IOException;
+import java.net.SocketOption;
+import java.net.SocketAddress;
+import java.net.ProtocolFamily;
+import java.nio.ByteBuffer;
+
+/**
+ * An asynchronous channel for datagram-oriented sockets.
+ *
+ * <p> An asynchronous datagram channel is created by invoking one of the {@link
+ * #open open} methods defined by this class. It is not possible to create a channel
+ * for an arbitrary, pre-existing datagram socket. A newly-created asynchronous
+ * datagram channel is open but not connected. It need not be connected in order
+ * for the {@link #send send} and {@link #receive receive} methods to be used.
+ * A datagram channel may be connected, by invoking its {@link #connect connect}
+ * method, in order to avoid the overhead of the security checks that are otherwise
+ * performed as part of every send and receive operation when a security manager
+ * is set. The channel must be connected in order to use the {@link #read read}
+ * and {@link #write write} methods, since those methods do not accept or return
+ * socket addresses. Once connected, an asynchronous datagram channel remains
+ * connected until it is disconnected or closed.
+ *
+ * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. An asynchronous datagram channel to an Internet Protocol
+ * (IP) socket supports the following options:
+ * <blockquote>
+ * <table border>
+ *   <tr>
+ *     <th>Option Name</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF} </td>
+ *     <td> The size of the socket send buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} </td>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} </td>
+ *     <td> Re-use address </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_BROADCAST SO_BROADCAST} </td>
+ *     <td> Allow transmission of broadcast datagrams </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#IP_TOS IP_TOS} </td>
+ *     <td> The Type of Service (ToS) octet in the Internet Protocol (IP) header </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#IP_MULTICAST_IF IP_MULTICAST_IF} </td>
+ *     <td> The network interface for Internet Protocol (IP) multicast datagrams </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#IP_MULTICAST_TTL
+ *       IP_MULTICAST_TTL} </td>
+ *     <td> The <em>time-to-live</em> for Internet Protocol (IP) multicast
+ *       datagrams </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#IP_MULTICAST_LOOP
+ *       IP_MULTICAST_LOOP} </td>
+ *     <td> Loopback for Internet Protocol (IP) multicast datagrams </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
+ * <p> Asynchronous datagram channels allow more than one read/receive and
+ * write/send to be oustanding at any given time.
+ *
+ * <p> <b>Usage Example:</b>
+ * <pre>
+ *  final AsynchronousDatagramChannel dc = AsynchronousDatagramChannel.open()
+ *      .bind(new InetSocketAddress(4000));
+ *
+ *  // print the source address of all packets that we receive
+ *  dc.receive(buffer, buffer, new CompletionHandler&lt;SocketAddress,ByteBuffer&gt;() {
+ *      public void completed(SocketAddress sa, ByteBuffer buffer) {
+ *          try {
+ *               System.out.println(sa);
+ *
+ *               buffer.clear();
+ *               dc.receive(buffer, buffer, this);
+ *           } catch (...) { ... }
+ *      }
+ *      public void failed(Throwable exc, ByteBuffer buffer) {
+ *          ...
+ *      }
+ *      public void cancelled(ByteBuffer buffer) {
+ *          ...
+ *      }
+ *  });
+ * </pre>
+ *
+ * @since 1.7
+ */
+
+public abstract class AsynchronousDatagramChannel
+    implements AsynchronousByteChannel, MulticastChannel
+{
+    private final AsynchronousChannelProvider provider;
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected AsynchronousDatagramChannel(AsynchronousChannelProvider provider) {
+        this.provider = provider;
+    }
+
+    /**
+     * Returns the provider that created this channel.
+     */
+    public final AsynchronousChannelProvider provider() {
+        return provider;
+    }
+
+    /**
+     * Opens an asynchronous datagram channel.
+     *
+     * <p> The new channel is created by invoking the {@link
+     * java.nio.channels.spi.AsynchronousChannelProvider#openAsynchronousDatagramChannel
+     * openAsynchronousDatagramChannel} method on the {@link
+     * java.nio.channels.spi.AsynchronousChannelProvider} object that created
+     * the given group (or the default provider where {@code group} is {@code
+     * null}).
+     *
+     * <p> The {@code family} parameter is used to specify the {@link ProtocolFamily}.
+     * If the datagram channel is to be used for Internet Protocol {@link
+     * MulticastChannel multicasting} then this parameter should correspond to
+     * the address type of the multicast groups that this channel will join.
+     *
+     * @param   family
+     *          The protocol family, or {@code null} to use the default protocol
+     *          family
+     * @param   group
+     *          The group to which the newly constructed channel should be bound,
+     *          or {@code null} for the default group
+     *
+     * @return  A new asynchronous datagram channel
+     *
+     * @throws  UnsupportedOperationException
+     *          If the specified protocol family is not supported. For example,
+     *          suppose the parameter is specified as {@link
+     *          java.net.StandardProtocolFamily#INET6 INET6} but IPv6 is not
+     *          enabled on the platform.
+     * @throws  ShutdownChannelGroupException
+     *          The specified group is shutdown
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousDatagramChannel open(ProtocolFamily family,
+                                                   AsynchronousChannelGroup group)
+        throws IOException
+    {
+        AsynchronousChannelProvider provider = (group == null) ?
+            AsynchronousChannelProvider.provider() : group.provider();
+        return provider.openAsynchronousDatagramChannel(family, group);
+    }
+
+    /**
+     * Opens an asynchronous datagram channel.
+     *
+     * <p> This method returns an asynchronous datagram channel that is
+     * bound to the <em>default group</em>. This method is equivalent to evaluating
+     * the expression:
+     * <blockquote><pre>
+     * open((ProtocolFamily)null,&nbsp;(AsynchronousChannelGroup)null);
+     * </pre></blockquote>
+     *
+     * @return  A new asynchronous datagram channel
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousDatagramChannel open()
+        throws IOException
+    {
+        return open(null, null);
+    }
+
+    // -- Socket-specific operations --
+
+    /**
+     * @throws  AlreadyBoundException               {@inheritDoc}
+     * @throws  UnsupportedAddressTypeException     {@inheritDoc}
+     * @throws  ClosedChannelException              {@inheritDoc}
+     * @throws  IOException                         {@inheritDoc}
+     * @throws  SecurityException
+     *          If a security manager has been installed and its {@link
+     *          SecurityManager#checkListen checkListen} method denies the
+     *          operation
+     */
+    @Override
+    public abstract AsynchronousDatagramChannel bind(SocketAddress local)
+        throws IOException;
+
+    /**
+     * @throws  IllegalArgumentException                {@inheritDoc}
+     * @throws  ClosedChannelException                  {@inheritDoc}
+     * @throws  IOException                             {@inheritDoc}
+     */
+    @Override
+    public abstract <T> AsynchronousDatagramChannel setOption(SocketOption<T> name, T value)
+        throws IOException;
+
+    /**
+     * Returns the remote address to which this channel is connected.
+     *
+     * <p> Where the channel is connected to an Internet Protocol socket address
+     * then the return value from this method is of type {@link
+     * java.net.InetSocketAddress}.
+     *
+     * @return  The remote address; {@code null} if the channel's socket is not
+     *          connected
+     *
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract SocketAddress getRemoteAddress() throws IOException;
+
+    /**
+     * Connects this channel's socket.
+     *
+     * <p> The channel's socket is configured so that it only receives
+     * datagrams from, and sends datagrams to, the given remote <i>peer</i>
+     * address.  Once connected, datagrams may not be received from or sent to
+     * any other address.  A datagram socket remains connected until it is
+     * explicitly disconnected or until it is closed.
+     *
+     * <p> This method performs exactly the same security checks as the {@link
+     * java.net.DatagramSocket#connect connect} method of the {@link
+     * java.net.DatagramSocket} class.  That is, if a security manager has been
+     * installed then this method verifies that its {@link
+     * java.lang.SecurityManager#checkAccept checkAccept} and {@link
+     * java.lang.SecurityManager#checkConnect checkConnect} methods permit
+     * datagrams to be received from and sent to, respectively, the given
+     * remote address.
+     *
+     * <p> This method may be invoked at any time. Whether it has any effect
+     * on outstanding read or write operations is implementation specific and
+     * therefore not specified.
+     *
+     * @param  remote
+     *         The remote address to which this channel is to be connected
+     *
+     * @return  This datagram channel
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed
+     *          and it does not permit access to the given remote address
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract AsynchronousDatagramChannel connect(SocketAddress remote)
+        throws IOException;
+
+    /**
+     * Disconnects this channel's socket.
+     *
+     * <p> The channel's socket is configured so that it can receive datagrams
+     * from, and sends datagrams to, any remote address so long as the security
+     * manager, if installed, permits it.
+     *
+     * <p> This method may be invoked at any time. Whether it has any effect
+     * on outstanding read or write operations is implementation specific and
+     * therefore not specified.
+     *
+     * @return  This datagram channel
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract AsynchronousDatagramChannel disconnect() throws IOException;
+
+    /**
+     * Receives a datagram via this channel.
+     *
+     * <p> This method initiates the receiving of a datagram, returning a
+     * {@code Future} representing the pending result of the operation.
+     * The {@code Future}'s {@link Future#get() get} method returns
+     * the source address of the datagram upon successful completion.
+     *
+     * <p> The datagram is transferred into the given byte buffer starting at
+     * its current position, as if by a regular {@link AsynchronousByteChannel#read
+     * read} operation. If there are fewer bytes remaining in the buffer
+     * than are required to hold the datagram then the remainder of the datagram
+     * is silently discarded.
+     *
+     * <p> If a timeout is specified and the timeout elapses before the operation
+     * completes then the operation completes with the exception {@link
+     * InterruptedByTimeoutException}. When a timeout elapses then the state of
+     * the {@link ByteBuffer} is not defined. The buffers should be discarded or
+     * at least care must be taken to ensure that the buffer is not accessed
+     * while the channel remains open.
+     *
+     * <p> When a security manager has been installed and the channel is not
+     * connected, then it verifies that the source's address and port number are
+     * permitted by the security manager's {@link SecurityManager#checkAccept
+     * checkAccept} method. The permission check is performed with privileges that
+     * are restricted by the calling context of this method. If the permission
+     * check fails then the operation completes with a {@link SecurityException}.
+     * The overhead of this security check can be avoided by first connecting the
+     * socket via the {@link #connect connect} method.
+     *
+     * @param   dst
+     *          The buffer into which the datagram is to be transferred
+     * @param   timeout
+     *          The timeout, or {@code 0L} for no timeout
+     * @param   unit
+     *          The time unit of the {@code timeout} argument
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  a {@code Future} object representing the pending result
+     *
+     * @throws  IllegalArgumentException
+     *          If the timeout is negative or the buffer is read-only
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    public abstract <A> Future<SocketAddress> receive(ByteBuffer dst,
+                                                      long timeout,
+                                                      TimeUnit unit,
+                                                      A attachment,
+                                                      CompletionHandler<SocketAddress,? super A> handler);
+
+    /**
+     * Receives a datagram via this channel.
+     *
+     * <p> This method initiates the receiving of a datagram, returning a
+     * {@code Future} representing the pending result of the operation.
+     * The {@code Future}'s {@link Future#get() get} method returns
+     * the source address of the datagram upon successful completion.
+     *
+     * <p> This method is equivalent to invoking {@link
+     * #receive(ByteBuffer,long,TimeUnit,Object,CompletionHandler)} with a
+     * timeout of {@code 0L}.
+     *
+     * @param   dst
+     *          The buffer into which the datagram is to be transferred
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  a {@code Future} object representing the pending result
+     *
+     * @throws  IllegalArgumentException
+     *          If the buffer is read-only
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    public final <A> Future<SocketAddress> receive(ByteBuffer dst,
+                                                   A attachment,
+                                                   CompletionHandler<SocketAddress,? super A> handler)
+    {
+        return receive(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler);
+    }
+
+    /**
+     * Receives a datagram via this channel.
+     *
+     * <p> This method initiates the receiving of a datagram, returning a
+     * {@code Future} representing the pending result of the operation.
+     * The {@code Future}'s {@link Future#get() get} method returns
+     * the source address of the datagram upon successful completion.
+     *
+     * <p> This method is equivalent to invoking {@link
+     * #receive(ByteBuffer,long,TimeUnit,Object,CompletionHandler)} with a
+     * timeout of {@code 0L}, and an attachment and completion handler
+     * of {@code null}.
+     *
+     * @param   dst
+     *          The buffer into which the datagram is to be transferred
+     *
+     * @return  a {@code Future} object representing the pending result
+     *
+     * @throws  IllegalArgumentException
+     *          If the buffer is read-only
+     */
+    public final <A> Future<SocketAddress> receive(ByteBuffer dst) {
+        return receive(dst, 0L, TimeUnit.MILLISECONDS, null, null);
+    }
+
+    /**
+     * Sends a datagram via this channel.
+     *
+     * <p> This method initiates sending of a datagram, returning a
+     * {@code Future} representing the pending result of the operation.
+     * The operation sends the remaining bytes in the given buffer as a single
+     * datagram to the given target address. The result of the operation, obtained
+     * by invoking the {@code Future}'s {@link Future#get() get}
+     * method, is the number of bytes sent.
+     *
+     * <p> The datagram is transferred from the byte buffer as if by a regular
+     * {@link AsynchronousByteChannel#write write} operation.
+     *
+     * <p> If a timeout is specified and the timeout elapses before the operation
+     * completes then the operation completes with the exception {@link
+     * InterruptedByTimeoutException}. When a timeout elapses then the state of
+     * the {@link ByteBuffer} is not defined. The buffers should be discarded or
+     * at least care must be taken to ensure that the buffer is not accessed
+     * while the channel remains open.
+     *
+     * <p> If there is a security manager installed and the the channel is not
+     * connected then this method verifies that the target address and port number
+     * are permitted by the security manager's {@link SecurityManager#checkConnect
+     * checkConnect} method.  The overhead of this security check can be avoided
+     * by first connecting the socket via the {@link #connect connect} method.
+     *
+     * @param   src
+     *          The buffer containing the datagram to be sent
+     * @param   target
+     *          The address to which the datagram is to be sent
+     * @param   timeout
+     *          The timeout, or {@code 0L} for no timeout
+     * @param   unit
+     *          The time unit of the {@code timeout} argument
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  a {@code Future} object representing the pending result
+     *
+     * @throws  UnresolvedAddressException
+     *          If the given remote address is not fully resolved
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given remote address is not supported
+     * @throws  IllegalArgumentException
+     *          If the timeout is negative, or if the channel's socket is
+     *          connected to an address that is not equal to {@code target}
+     * @throws  SecurityException
+     *          If a security manager has been installed and it does not permit
+     *          datagrams to be sent to the given address
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    public abstract <A> Future<Integer> send(ByteBuffer src,
+                                             SocketAddress target,
+                                             long timeout,
+                                             TimeUnit unit,
+                                             A attachment,
+                                             CompletionHandler<Integer,? super A> handler);
+
+    /**
+     * Sends a datagram via this channel.
+     *
+     * <p> This method initiates sending of a datagram, returning a
+     * {@code Future} representing the pending result of the operation.
+     * The operation sends the remaining bytes in the given buffer as a single
+     * datagram to the given target address. The result of the operation, obtained
+     * by invoking the {@code Future}'s {@link Future#get() get}
+     * method, is the number of bytes sent.
+     *
+     * <p> This method is equivalent to invoking {@link
+     * #send(ByteBuffer,SocketAddress,long,TimeUnit,Object,CompletionHandler)}
+     * with a timeout of {@code 0L}.
+     *
+     * @param   src
+     *          The buffer containing the datagram to be sent
+     * @param   target
+     *          The address to which the datagram is to be sent
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  a {@code Future} object representing the pending result
+     *
+     * @throws  UnresolvedAddressException
+     *          If the given remote address is not fully resolved
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given remote address is not supported
+     * @throws  IllegalArgumentException
+     *          If the channel's socket is connected and is connected to an
+     *          address that is not equal to {@code target}
+     * @throws  SecurityException
+     *          If a security manager has been installed and it does not permit
+     *          datagrams to be sent to the given address
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    public final <A> Future<Integer> send(ByteBuffer src,
+                                          SocketAddress target,
+                                          A attachment,
+                                          CompletionHandler<Integer,? super A> handler)
+    {
+        return send(src, target, 0L, TimeUnit.MILLISECONDS, attachment, handler);
+    }
+
+    /**
+     * Sends a datagram via this channel.
+     *
+     * <p> This method initiates sending of a datagram, returning a
+     * {@code Future} representing the pending result of the operation.
+     * The operation sends the remaining bytes in the given buffer as a single
+     * datagram to the given target address. The result of the operation, obtained
+     * by invoking the {@code Future}'s {@link Future#get() get}
+     * method, is the number of bytes sent.
+     *
+     * <p> This method is equivalent to invoking {@link
+     * #send(ByteBuffer,SocketAddress,long,TimeUnit,Object,CompletionHandler)}
+     * with a timeout of {@code 0L} and an attachment and completion handler
+     * of {@code null}.
+     *
+     * @param   src
+     *          The buffer containing the datagram to be sent
+     * @param   target
+     *          The address to which the datagram is to be sent
+     *
+     * @return  a {@code Future} object representing the pending result
+     *
+     * @throws  UnresolvedAddressException
+     *          If the given remote address is not fully resolved
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given remote address is not supported
+     * @throws  IllegalArgumentException
+     *          If the channel's socket is connected and is connected to an
+     *          address that is not equal to {@code target}
+     * @throws  SecurityException
+     *          If a security manager has been installed and it does not permit
+     *          datagrams to be sent to the given address
+     */
+    public final Future<Integer> send(ByteBuffer src, SocketAddress target) {
+        return send(src, target, 0L, TimeUnit.MILLISECONDS, null, null);
+    }
+
+    /**
+     * Receives a datagram via this channel.
+     *
+     * <p> This method initiates the receiving of a datagram, returning a
+     * {@code Future} representing the pending result of the operation.
+     * The {@code Future}'s {@link Future#get() get} method returns
+     * the number of bytes transferred upon successful completion.
+     *
+     * <p> This method may only be invoked if this channel is connected, and it
+     * only accepts datagrams from the peer that the channel is connected too.
+     * The datagram is transferred into the given byte buffer starting at
+     * its current position and exactly as specified in the {@link
+     * AsynchronousByteChannel} interface. If there are fewer bytes
+     * remaining in the buffer than are required to hold the datagram then the
+     * remainder of the datagram is silently discarded.
+     *
+     * <p> If a timeout is specified and the timeout elapses before the operation
+     * completes then the operation completes with the exception {@link
+     * InterruptedByTimeoutException}. When a timeout elapses then the state of
+     * the {@link ByteBuffer} is not defined. The buffers should be discarded or
+     * at least care must be taken to ensure that the buffer is not accessed
+     * while the channel remains open.
+     *
+     * @param   dst
+     *          The buffer into which the datagram is to be transferred
+     * @param   timeout
+     *          The timeout, or {@code 0L} for no timeout
+     * @param   unit
+     *          The time unit of the {@code timeout} argument
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  a {@code Future} object representing the pending result
+     *
+     * @throws  IllegalArgumentException
+     *          If the timeout is negative or buffer is read-only
+     * @throws  NotYetConnectedException
+     *          If this channel is not connected
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    public abstract <A> Future<Integer> read(ByteBuffer dst,
+                                             long timeout,
+                                             TimeUnit unit,
+                                             A attachment,
+                                             CompletionHandler<Integer,? super A> handler);
+
+    /**
+     * @throws  NotYetConnectedException
+     *          If this channel is not connected
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    @Override
+    public final <A> Future<Integer> read(ByteBuffer dst,
+                                          A attachment,
+                                          CompletionHandler<Integer,? super A> handler)
+    {
+        return read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler);
+    }
+
+    /**
+     * @throws  NotYetConnectedException
+     *          If this channel is not connected
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    @Override
+    public final Future<Integer> read(ByteBuffer dst) {
+        return read(dst, 0L, TimeUnit.MILLISECONDS, null, null);
+    }
+
+    /**
+     * Writes a datagram to this channel.
+     *
+     * <p> This method initiates sending of a datagram, returning a
+     * {@code Future} representing the pending result of the operation.
+     * The operation sends the remaining bytes in the given buffer as a single
+     * datagram. The result of the operation, obtained by invoking the
+     * {@code Future}'s {@link Future#get() get} method, is the
+     * number of bytes sent.
+     *
+     * <p> The datagram is transferred from the byte buffer as if by a regular
+     * {@link AsynchronousByteChannel#write write} operation.
+     *
+     * <p> This method may only be invoked if this channel is connected,
+     * in which case it sends datagrams directly to the socket's peer.  Otherwise
+     * it behaves exactly as specified in the {@link
+     * AsynchronousByteChannel} interface.
+     *
+     * <p> If a timeout is specified and the timeout elapses before the operation
+     * completes then the operation completes with the exception {@link
+     * InterruptedByTimeoutException}. When a timeout elapses then the state of
+     * the {@link ByteBuffer} is not defined. The buffers should be discarded or
+     * at least care must be taken to ensure that the buffer is not accessed
+     * while the channel remains open.
+     *
+     * @param   src
+     *          The buffer containing the datagram to be sent
+     * @param   timeout
+     *          The timeout, or {@code 0L} for no timeout
+     * @param   unit
+     *          The time unit of the {@code timeout} argument
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  a {@code Future} object representing the pending result
+     *
+     * @throws  IllegalArgumentException
+     *          If the timeout is negative
+     * @throws  NotYetConnectedException
+     *          If this channel is not connected
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    public abstract <A> Future<Integer> write(ByteBuffer src,
+                                              long timeout,
+                                              TimeUnit unit,
+                                              A attachment,
+                                              CompletionHandler<Integer,? super A> handler);
+    /**
+     * @throws  NotYetConnectedException
+     *          If this channel is not connected
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    @Override
+    public final <A> Future<Integer> write(ByteBuffer src,
+                                           A attachment,
+                                           CompletionHandler<Integer,? super A> handler)
+    {
+        return write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler);
+    }
+
+    /**
+     * @throws  NotYetConnectedException
+     *          If this channel is not connected
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    @Override
+    public final Future<Integer> write(ByteBuffer src) {
+        return write(src, 0L, TimeUnit.MILLISECONDS, null, null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/AsynchronousFileChannel.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,774 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.channels;
+
+import java.nio.file.*;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.spi.*;
+import java.nio.ByteBuffer;
+import java.io.IOException;
+import java.util.concurrent.Future;
+import java.util.concurrent.ExecutorService;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+
+/**
+ * An asynchronous channel for reading, writing, and manipulating a file.
+ *
+ * <p> An asynchronous file channel is created when a file is opened by invoking
+ * one of the {@link #open open} methods defined by this class. The file contains
+ * a variable-length sequence of bytes that can be read and written and whose
+ * current size can be {@link #size() queried}. The size of the file increases
+ * when bytes are written beyond its  current size; the size of the file decreases
+ * when it is {@link #truncate truncated}.
+ *
+ * <p> An asynchronous file channel does not have a <i>current position</i>
+ * within the file. Instead, the file position is specified to each read and
+ * write operation.
+ *
+ * <p> In addition to read and write operations, this class defines the
+ * following operations: </p>
+ *
+ * <ul>
+ *
+ *   <li><p> Updates made to a file may be {@link #force <i>forced
+ *   out</i>} to the underlying storage device, ensuring that data are not
+ *   lost in the event of a system crash.  </p></li>
+ *
+ *   <li><p> A region of a file may be {@link FileLock <i>locked</i>}
+ *   against access by other programs.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> The {@link #read read}, {@link #write write}, and {@link #lock lock}
+ * methods defined by this class are asynchronous  and return a {@link Future}
+ * to represent the pending result of the operation. This may be used to check
+ * if the operation has completed, to wait for its completion, and to retrieve
+ * the result. These method may optionally specify a {@link CompletionHandler}
+ * that is invoked to consume the result of the I/O operation when it completes.
+ *
+ * <p> An {@code AsynchronousFileChannel} is associated with a thread pool to
+ * which tasks are submitted to handle I/O events and dispatch to completion
+ * handlers that consume the results of I/O operations on the channel. The
+ * completion handler for an I/O operation initiated on a channel is guaranteed
+ * to be invoked by one threads in the thread pool (This ensures that the
+ * completion handler is run by a thread with the expected <em>identity</em>).
+ * Where an I/O operation completes immediately, and the initiating thread is
+ * itself a thread in the thread pool, then the completion handler may be invoked
+ * directly by the initiating thread. When an {@code AsynchronousFileChannel} is
+ * created without specifying a thread pool then the channel is associated with
+ * a system-dependent and default thread pool that may be shared with other
+ * channels. The default thread pool is configured by the system properties
+ * defined by the {@link AsynchronousChannelGroup} class.
+ *
+ * <p> Channels of this type are safe for use by multiple concurrent threads. The
+ * {@link Channel#close close} method may be invoked at any time, as specified
+ * by the {@link Channel} interface. This causes all outstanding asynchronous
+ * operations on the channel to complete with the exception {@link
+ * AsynchronousCloseException}. Multiple read and write operations may be
+ * outstanding at the same time. When multiple read and write operations are
+ * outstanding then the ordering of the I/O operations, and the order that the
+ * completion handlers are invoked, is not specified; they are not, in particular,
+ * guaranteed to execute in the order that the operations were initiated. The
+ * {@link java.nio.ByteBuffer ByteBuffers} used when reading or writing are not
+ * safe for use by multiple concurrent I/O operations. Furthermore, after an I/O
+ * operation is initiated then care should be taken to ensure that the buffer is
+ * not accessed until after the operation has completed.
+ *
+ * <p> As with {@link FileChannel}, the view of a file provided by an instance of
+ * this class is guaranteed to be consistent with other views of the same file
+ * provided by other instances in the same program.  The view provided by an
+ * instance of this class may or may not, however, be consistent with the views
+ * seen by other concurrently-running programs due to caching performed by the
+ * underlying operating system and delays induced by 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.
+ *
+ * @since 1.7
+ */
+
+public abstract class AsynchronousFileChannel
+    implements AsynchronousChannel
+{
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected AsynchronousFileChannel() {
+    }
+
+    /**
+     * Closes this channel.
+     *
+     * <p> If this channel is associated with its own thread pool then closing
+     * the channel causes the thread pool to shutdown after all actively
+     * executing completion handlers have completed. No attempt is made to stop
+     * or interrupt actively completion handlers.
+     *
+     * <p> This method otherwise behaves exactly as specified by the {@link
+     * AsynchronousChannel} interface.
+     *
+     * @throws  IOException     {@inheritDoc}
+     */
+    @Override
+    public abstract void close() throws IOException;
+
+    /**
+     * Opens or creates a file for reading and/or writing, returning an
+     * asynchronous file channel to access the file.
+     *
+     * <p> The {@code options} parameter determines how the file is opened.
+     * The {@link StandardOpenOption#READ READ} and {@link StandardOpenOption#WRITE
+     * WRITE} options determines if the file should be opened for reading and/or
+     * writing. If neither option is contained in the array then an existing file
+     * is opened for  reading.
+     *
+     * <p> In addition to {@code READ} and {@code WRITE}, the following options
+     * may be present:
+     *
+     * <table border=1 cellpadding=5 summary="">
+     * <tr> <th>Option</th> <th>Description</th> </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} </td>
+     *   <td> When opening an existing file, the file is first truncated to a
+     *   size of 0 bytes. This option is ignored when the file is opened only
+     *   for reading.</td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#CREATE_NEW CREATE_NEW} </td>
+     *   <td> If this option is present then a new file is created, failing if
+     *   the file already exists. 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. </td>
+     * </tr>
+     * <tr>
+     *   <td > {@link StandardOpenOption#CREATE CREATE} </td>
+     *   <td> If this option is present then an existing file is opened if it
+     *   exists, otherwise a new file is created. 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 if the {@code CREATE_NEW} option is also present or
+     *   the file is opened only for reading. </td>
+     * </tr>
+     * <tr>
+     *   <td > {@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} </td>
+     *   <td> When this option is present then the implementation makes a
+     *   <em>best effort</em> attempt to delete the file when closed by the
+     *   the {@link #close close} method. If the {@code close} method is not
+     *   invoked then a <em>best effort</em> attempt is made to delete the file
+     *   when the Java virtual machine terminates. </td>
+     * </tr>
+     * <tr>
+     *   <td>{@link StandardOpenOption#SPARSE SPARSE} </td>
+     *   <td> When creating a new file this option is a <em>hint</em> that the
+     *   new file will be sparse. This option is ignored when not creating
+     *   a new file. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#SYNC SYNC} </td>
+     *   <td> Requires that every update to the file's content or metadata be
+     *   written synchronously to the underlying storage device. (see <a
+     *   href="../file/package-summary.html#integrity"> Synchronized I/O file
+     *   integrity</a>). </td>
+     * <tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#DSYNC DSYNC} </td>
+     *   <td> Requires that every update to the file's content be written
+     *   synchronously to the underlying storage device. (see <a
+     *   href="../file/package-summary.html#integrity"> Synchronized I/O file
+     *   integrity</a>). </td>
+     * </tr>
+     * </table>
+     *
+     * <p> An implementation may also support additional options.
+     *
+     * <p> The {@code executor} parameter is the {@link ExecutorService} to
+     * which tasks are submitted to handle I/O events and dispatch completion
+     * results for operations initiated on resulting channel.
+     * The nature of these tasks is highly implementation specific and so care
+     * should be taken when configuring the {@code Executor}. Minimally it
+     * should support an unbounded work queue and should not run tasks on the
+     * caller thread of the {@link ExecutorService#execute execute} method.
+     * {@link #close Closing} the channel results in the orderly {@link
+     * ExecutorService#shutdown shutdown} of the executor service. Shutting down
+     * the executor service by other means results in unspecified behavior.
+     *
+     * <p> The {@code attrs} parameter is an optional array of file {@link
+     * FileAttribute file-attributes} to set atomically when creating the file.
+     *
+     * <p> The new channel is created by invoking the {@link
+     * FileSystemProvider#newFileChannel newFileChannel} method on the
+     * provider that created the {@code Path}.
+     *
+     * @param   file
+     *          The path of the file to open or create
+     * @param   options
+     *          Options specifying how the file is opened
+     * @param   executor
+     *          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
+     *          creating the file
+     *
+     * @return  A new asynchronous file channel
+     *
+     * @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
+     *          support creating asynchronous file channels, or an unsupported
+     *          open option is specified, or the array contains an attribute that
+     *          cannot be set atomically when creating the file
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an
+     *          unspecified permission required by the implementation.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String)} method is invoked to check
+     *          read access if the file is opened for reading. The {@link
+     *          SecurityManager#checkWrite(String)} method is invoked to check
+     *          write access if the file is opened for writing
+     */
+    public static AsynchronousFileChannel open(Path file,
+                                               Set<? extends OpenOption> options,
+                                               ExecutorService executor,
+                                               FileAttribute<?>... attrs)
+        throws IOException
+    {
+        FileSystemProvider provider = file.getFileSystem().provider();
+        return provider.newAsynchronousFileChannel(file, options, executor, attrs);
+    }
+
+    private static final FileAttribute<?>[] NO_ATTRIBUTES = new FileAttribute[0];
+
+    /**
+     * Opens or creates a file for reading and/or writing, returning an
+     * asynchronous file channel to access the file.
+     *
+     * <p> An invocation of this method behaves in exactly the same way as the
+     * invocation
+     * <pre>
+     *     ch.{@link #open(Path,Set,ExecutorService,FileAttribute[]) open}(file, opts, null, new FileAttribute&lt;?&gt;[0]);
+     * </pre>
+     * where {@code opts} is a {@code Set} containing the options specified to
+     * this method.
+     *
+     * <p> The resulting channel is associated with default thread pool to which
+     * tasks are submitted to handle I/O events and dispatch to completion
+     * handlers that consume the result of asynchronous operations performed on
+     * the resulting channel.
+     *
+     * @param   file
+     *          The path of the file to open or create
+     * @param   options
+     *          Options specifying how the file is opened
+     *
+     * @return  A new asynchronous file channel
+     *
+     * @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
+     *          support creating file channels, or an unsupported open option is
+     *          specified
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an
+     *          unspecified permission required by the implementation.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String)} method is invoked to check
+     *          read access if the file is opened for reading. The {@link
+     *          SecurityManager#checkWrite(String)} method is invoked to check
+     *          write access if the file is opened for writing
+     */
+    public static AsynchronousFileChannel open(Path file, OpenOption... options)
+        throws IOException
+    {
+        Set<OpenOption> set = new HashSet<OpenOption>(options.length);
+        Collections.addAll(set, options);
+        return open(file, set, null, NO_ATTRIBUTES);
+    }
+
+    /**
+     * Returns the current size of this channel's file.
+     *
+     * @return  The current size of this channel's file, measured in bytes
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract long size() throws IOException;
+
+    /**
+     * Truncates this channel's file to the given size.
+     *
+     * <p> If the given size is less than the file's current size then the file
+     * is truncated, discarding any bytes beyond the new end of the file.  If
+     * the given size is greater than or equal to the file's current size then
+     * the file is not modified. </p>
+     *
+     * @param  size
+     *         The new size, a non-negative byte count
+     *
+     * @return  This file channel
+     *
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IllegalArgumentException
+     *          If the new size is negative
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract AsynchronousFileChannel truncate(long size) throws IOException;
+
+    /**
+     * Forces any updates to this channel's file to be written to the storage
+     * device that contains it.
+     *
+     * <p> If this channel's file resides on a local storage device then when
+     * this method returns it is guaranteed that all changes made to the file
+     * since this channel was created, or since this method was last invoked,
+     * will have been written to that device.  This is useful for ensuring that
+     * critical information is not lost in the event of a system crash.
+     *
+     * <p> If the file does not reside on a local device then no such guarantee
+     * is made.
+     *
+     * <p> The {@code metaData} parameter can be used to limit the number of
+     * I/O operations that this method is required to perform.  Passing
+     * {@code false} for this parameter indicates that only updates to the
+     * file's content need be written to storage; passing {@code true}
+     * indicates that updates to both the file's content and metadata must be
+     * written, which generally requires at least one more I/O operation.
+     * Whether this parameter actually has any effect is dependent upon the
+     * underlying operating system and is therefore unspecified.
+     *
+     * <p> Invoking this method may cause an I/O operation to occur even if the
+     * channel was only opened for reading.  Some operating systems, for
+     * example, maintain a last-access time as part of a file's metadata, and
+     * this time is updated whenever the file is read.  Whether or not this is
+     * actually done is system-dependent and is therefore unspecified.
+     *
+     * <p> This method is only guaranteed to force changes that were made to
+     * this channel's file via the methods defined in this class.
+     *
+     * @param   metaData
+     *          If {@code true} then this method is required to force changes
+     *          to both the file's content and metadata to be written to
+     *          storage; otherwise, it need only force content changes to be
+     *          written
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract void force(boolean metaData) throws IOException;
+
+    /**
+     * Acquires a lock on the given region of this channel's file.
+     *
+     * <p> This method initiates an operation to acquire a lock on the given region
+     * of this channel's file. The method returns a {@code Future} representing
+     * the pending result of the operation. Its {@link Future#get() get}
+     * method returns the {@link FileLock} on successful completion.
+     *
+     * <p> The region specified by the {@code position} and {@code size}
+     * parameters need not be contained within, or even overlap, the actual
+     * underlying file.  Lock regions are fixed in size; if a locked region
+     * initially contains the end of the file and the file grows beyond the
+     * region then the new portion of the file will not be covered by the lock.
+     * If a file is expected to grow in size and a lock on the entire file is
+     * required then a region starting at zero, and no smaller than the
+     * expected maximum size of the file, should be locked.  The two-argument
+     * {@link #lock(Object,CompletionHandler)} method simply locks a region
+     * of size {@link Long#MAX_VALUE}. If a lock that overlaps the requested
+     * region is already held by this Java virtual machine, or this method has
+     * been invoked to lock an overlapping region and that operation has not
+     * completed, then this method throws {@link OverlappingFileLockException}.
+     *
+     * <p> Some operating systems do not support a mechanism to acquire a file
+     * lock in an asynchronous manner. Consequently an implementation may
+     * acquire the file lock in a background thread or from a task executed by
+     * a thread in the associated thread pool. If there are many lock operations
+     * outstanding then it may consume threads in the Java virtual machine for
+     * indefinite periods.
+     *
+     * <p> Some operating systems do not support shared locks, in which case a
+     * request for a shared lock is automatically converted into a request for
+     * an exclusive lock.  Whether the newly-acquired lock is shared or
+     * exclusive may be tested by invoking the resulting lock object's {@link
+     * FileLock#isShared() isShared} method.
+     *
+     * <p> File locks are held on behalf of the entire Java virtual machine.
+     * They are not suitable for controlling access to a file by multiple
+     * threads within the same virtual machine.
+     *
+     * @param   position
+     *          The position at which the locked region is to start; must be
+     *          non-negative
+     * @param   size
+     *          The size of the locked region; must be non-negative, and the sum
+     *          {@code position}&nbsp;+&nbsp;{@code size} must be non-negative
+     * @param   shared
+     *          {@code true} to request a shared lock, in which case this
+     *          channel must be open for reading (and possibly writing);
+     *          {@code false} to request an exclusive lock, in which case this
+     *          channel must be open for writing (and possibly reading)
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  a {@code Future} object representing the pending result
+     *
+     * @throws  OverlappingFileLockException
+     *          If a lock that overlaps the requested region is already held by
+     *          this Java virtual machine, or there is already a pending attempt
+     *          to lock an overlapping region
+     * @throws  IllegalArgumentException
+     *          If the preconditions on the parameters do not hold
+     * @throws  NonReadableChannelException
+     *          If {@code shared} is true this channel but was not opened for reading
+     * @throws  NonWritableChannelException
+     *          If {@code shared} is false but this channel was not opened for writing
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, the channel is closed, and the channel
+     *          was originally created with its own thread pool
+     */
+    public abstract <A> Future<FileLock> lock(long position,
+                                              long size,
+                                              boolean shared,
+                                              A attachment,
+                                              CompletionHandler<FileLock,? super A> handler);
+
+    /**
+     * Acquires an exclusive lock on this channel's file.
+     *
+     * <p> This method initiates an operation to acquire an exclusive lock on this
+     * channel's file. The method returns a {@code Future} representing
+     * the pending result of the operation. Its {@link Future#get() get}
+     * method returns the {@link FileLock} on successful completion.
+     *
+     * <p> An invocation of this method of the form {@code ch.lock(att,handler)}
+     * behaves in exactly the same way as the invocation
+     * <pre>
+     *     ch.{@link #lock(long,long,boolean,Object,CompletionHandler) lock}(0L, Long.MAX_VALUE, false, att, handler)
+     * </pre>
+     *
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  a {@code Future} object representing the pending result
+     *
+     * @throws  OverlappingFileLockException
+     *          If a lock is already held by this Java virtual machine, or there
+     *          is already a pending attempt to lock a region
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, the channel is closed, and the channel
+     *          was originally created with its own thread pool
+     */
+    public final <A> Future<FileLock> lock(A attachment,
+                                           CompletionHandler<FileLock,? super A> handler)
+    {
+        return lock(0L, Long.MAX_VALUE, false, attachment, handler);
+    }
+
+    /**
+     * Acquires an exclusive lock on this channel's file.
+     *
+     * <p> This method initiates an operation to acquire an exclusive lock on this
+     * channel's file. The method returns a {@code Future} representing the
+     * pending result of the operation. Its {@link Future#get() get} method
+     * returns the {@link FileLock} on successful completion.
+     *
+     * <p> An invocation of this method behaves in exactly the same way as the
+     * invocation
+     * <pre>
+     *     ch.{@link #lock(long,long,boolean,Object,CompletionHandler) lock}(0L, Long.MAX_VALUE, false, null, null)
+     * </pre>
+     *
+     * @return  A {@code Future} object representing the pending result
+     *
+     * @throws  OverlappingFileLockException
+     *          If a lock is already held by this Java virtual machine, or there
+     *          is already a pending attempt to lock a region
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     */
+    public final Future<FileLock> lock() {
+        return lock(0L, Long.MAX_VALUE, false, null, null);
+    }
+
+    /**
+     * Attempts to acquire a lock on the given region of this channel's file.
+     *
+     * <p> This method does not block. An invocation always returns immediately,
+     * either having acquired a lock on the requested region or having failed to
+     * do so.  If it fails to acquire a lock because an overlapping lock is held
+     * by another program then it returns {@code null}.  If it fails to acquire
+     * a lock for any other reason then an appropriate exception is thrown.
+     *
+     * @param  position
+     *         The position at which the locked region is to start; must be
+     *         non-negative
+     *
+     * @param  size
+     *         The size of the locked region; must be non-negative, and the sum
+     *         {@code position}&nbsp;+&nbsp;{@code size} must be non-negative
+     *
+     * @param  shared
+     *         {@code true} to request a shared lock,
+     *         {@code false} to request an exclusive lock
+     *
+     * @return  A lock object representing the newly-acquired lock,
+     *          or {@code null} if the lock could not be acquired
+     *          because another program holds an overlapping lock
+     *
+     * @throws  IllegalArgumentException
+     *          If the preconditions on the parameters do not hold
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  OverlappingFileLockException
+     *          If a lock that overlaps the requested region is already held by
+     *          this Java virtual machine, or if another thread is already
+     *          blocked in this method and is attempting to lock an overlapping
+     *          region of the same file
+     * @throws  NonReadableChannelException
+     *          If {@code shared} is true this channel but was not opened for reading
+     * @throws  NonWritableChannelException
+     *          If {@code shared} is false but this channel was not opened for writing
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     *
+     * @see     #lock(Object,CompletionHandler)
+     * @see     #lock(long,long,boolean,Object,CompletionHandler)
+     * @see     #tryLock()
+     */
+    public abstract FileLock tryLock(long position, long size, boolean shared)
+        throws IOException;
+
+    /**
+     * Attempts to acquire an exclusive lock on this channel's file.
+     *
+     * <p> An invocation of this method of the form {@code ch.tryLock()}
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     ch.{@link #tryLock(long,long,boolean) tryLock}(0L, Long.MAX_VALUE, false) </pre>
+     *
+     * @return  A lock object representing the newly-acquired lock,
+     *          or {@code null} if the lock could not be acquired
+     *          because another program holds an overlapping lock
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  OverlappingFileLockException
+     *          If a lock that overlaps the requested region is already held by
+     *          this Java virtual machine, or if another thread is already
+     *          blocked in this method and is attempting to lock an overlapping
+     *          region
+     * @throws  NonWritableChannelException
+     *          If {@code shared} is false but this channel was not opened for writing
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     *
+     * @see     #lock(Object,CompletionHandler)
+     * @see     #lock(long,long,boolean,Object,CompletionHandler)
+     * @see     #tryLock(long,long,boolean)
+     */
+    public final FileLock tryLock() throws IOException {
+        return tryLock(0L, Long.MAX_VALUE, false);
+    }
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer,
+     * starting at the given file position.
+     *
+     * <p> This method initiates the reading of a sequence of bytes from this
+     * channel into the given buffer, starting at the given file position. This
+     * method returns a {@code Future} representing the pending result of the
+     * operation. The Future's {@link Future#get() get} method returns the
+     * number of bytes read or {@code -1} if the given position is greater than
+     * or equal to the file's size at the time that the read is attempted.
+     *
+     * <p> This method works in the same manner as the {@link
+     * AsynchronousByteChannel#read(ByteBuffer,Object,CompletionHandler)}
+     * method, except that bytes are read starting at the given file position.
+     * If the given file position is greater than the file's size at the time
+     * that the read is attempted then no bytes are read.
+     *
+     * @param   dst
+     *          The buffer into which bytes are to be transferred
+     * @param   position
+     *          The file position at which the transfer is to begin;
+     *          must be non-negative
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  A {@code Future} object representing the pending result
+     *
+     * @throws  IllegalArgumentException
+     *          If the position is negative or the buffer is read-only
+     * @throws  NonReadableChannelException
+     *          If this channel was not opened for reading
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, the channel is closed, and the channel
+     *          was originally created with its own thread pool
+     */
+    public abstract <A> Future<Integer> read(ByteBuffer dst,
+                                             long position,
+                                             A attachment,
+                                             CompletionHandler<Integer,? super A> handler);
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer,
+     * starting at the given file position.
+     *
+     * <p> This method initiates the reading of a sequence of bytes from this
+     * channel into the given buffer, starting at the given file position. This
+     * method returns a {@code Future} representing the pending result of the
+     * operation. The Future's {@link Future#get() get} method returns the
+     * number of bytes read or {@code -1} if the given position is greater
+     * than or equal to the file's size at the time that the read is attempted.
+     *
+     * <p> This method is equivalent to invoking {@link
+     * #read(ByteBuffer,long,Object,CompletionHandler)} with the {@code attachment}
+     * and handler parameters set to {@code null}.
+     *
+     * @param   dst
+     *          The buffer into which bytes are to be transferred
+     * @param   position
+     *          The file position at which the transfer is to begin;
+     *          must be non-negative
+     *
+     * @return  A {@code Future} object representing the pending result
+     *
+     * @throws  IllegalArgumentException
+     *          If the position is negative or the buffer is read-only
+     * @throws  NonReadableChannelException
+     *          If this channel was not opened for reading
+     */
+    public final Future<Integer> read(ByteBuffer dst, long position) {
+        return read(dst, position, null, null);
+    }
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer, starting
+     * at the given file position.
+     *
+     * <p> This method initiates the writing of a sequence of bytes to this channel
+     * from the given buffer, starting at the given file position. The method
+     * returns a {@code Future} representing the pending result of the write
+     * operation. The Future's {@link Future#get() get} method returns the
+     * number of bytes written.
+     *
+     * <p> This method works in the same manner as the {@link
+     * AsynchronousByteChannel#write(ByteBuffer,Object,CompletionHandler)}
+     * method, except that bytes are written starting at the given file position.
+     * If the given position is greater than the file's size, at the time that
+     * the write is attempted, then the file will be grown to accommodate the new
+     * bytes; the values of any bytes between the previous end-of-file and the
+     * newly-written bytes are unspecified.
+     *
+     * @param   src
+     *          The buffer from which bytes are to be transferred
+     * @param   position
+     *          The file position at which the transfer is to begin;
+     *          must be non-negative
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  A {@code Future} object representing the pending result
+     *
+     * @throws  IllegalArgumentException
+     *          If the position is negative
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, the channel is closed, and the channel
+     *          was originally created with its own thread pool
+     */
+    public abstract <A> Future<Integer> write(ByteBuffer src,
+                                              long position,
+                                              A attachment,
+                                              CompletionHandler<Integer,? super A> handler);
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer, starting
+     * at the given file position.
+     *
+     * <p> This method initiates the writing of a sequence of bytes to this channel
+     * from the given buffer, starting at the given file position. The method
+     * returns a {@code Future} representing the pending result of the write
+     * operation. The Future's {@link Future#get() get} method returns the
+     * number of bytes written.
+     *
+     * <p> This method is equivalent to invoking {@link
+     * #write(ByteBuffer,long,Object,CompletionHandler)} with the {@code attachment}
+     * and handler parameters set to {@code null}.
+     *
+     * @param   src
+     *          The buffer from which bytes are to be transferred
+     * @param   position
+     *          The file position at which the transfer is to begin;
+     *          must be non-negative
+     *
+     * @return  A {@code Future} object representing the pending result
+     *
+     * @throws  IllegalArgumentException
+     *          If the position is negative
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     */
+    public final Future<Integer> write(ByteBuffer src, long position) {
+        return write(src, position, null, null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.channels;
+
+import java.nio.channels.spi.*;
+import java.net.SocketOption;
+import java.net.SocketAddress;
+import java.util.concurrent.Future;
+import java.io.IOException;
+
+/**
+ * An asynchronous channel for stream-oriented listening sockets.
+ *
+ * <p> An asynchronous server-socket channel is created by invoking the
+ * {@link #open open} method of this class.
+ * A newly-created asynchronous server-socket channel is open but not yet bound.
+ * It can be bound to a local address and configured to listen for connections
+ * by invoking the {@link #bind(SocketAddress,int) bind} method. Once bound,
+ * the {@link #accept(Object,CompletionHandler) accept} method
+ * is used to initiate the accepting of connections to the channel's socket.
+ * An attempt to invoke the <tt>accept</tt> method on an unbound channel will
+ * cause a {@link NotYetBoundException} to be thrown.
+ *
+ * <p> Channels of this type are safe for use by multiple concurrent threads
+ * though at most one accept operation can be outstanding at any time.
+ * If a thread initiates an accept operation before a previous accept operation
+ * has completed then an {@link AcceptPendingException} will be thrown.
+ *
+ * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. Channels of this type support the following options:
+ * <blockquote>
+ * <table border>
+ *   <tr>
+ *     <th>Option Name</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} </td>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} </td>
+ *     <td> Re-use address </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
+ * <p> <b>Usage Example:</b>
+ * <pre>
+ *  final AsynchronousServerSocketChannel listener =
+ *      AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(5000));
+ *
+ *  listener.accept(null, new CompletionHandler&lt;AsynchronousSocketChannel,Void&gt;() {
+ *      public void completed(AsynchronousSocketChannel ch, Void att) {
+ *          // accept the next connection
+ *          listener.accept(null, this);
+ *
+ *          // handle this connection
+ *          handle(ch);
+ *      }
+ *      public void failed(Throwable exc, Void att) {
+ *          ...
+ *      }
+ *      public void cancelled(Void att) {
+ *          ...
+ *      }
+ *  });
+ * </pre>
+ *
+ * @since 1.7
+ */
+
+public abstract class AsynchronousServerSocketChannel
+    implements AsynchronousChannel, NetworkChannel
+{
+    private final AsynchronousChannelProvider provider;
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected AsynchronousServerSocketChannel(AsynchronousChannelProvider provider) {
+        this.provider = provider;
+    }
+
+    /**
+     * Returns the provider that created this channel.
+     */
+    public final AsynchronousChannelProvider provider() {
+        return provider;
+    }
+
+    /**
+     * Opens an asynchronous server-socket channel.
+     *
+     * <p> The new channel is created by invoking the {@link
+     * java.nio.channels.spi.AsynchronousChannelProvider#openAsynchronousServerSocketChannel
+     * openAsynchronousServerSocketChannel} method on the {@link
+     * java.nio.channels.spi.AsynchronousChannelProvider} object that created
+     * the given group. If the group parameter is <tt>null</tt> then the
+     * resulting channel is created by the system-wide default provider, and
+     * bound to the <em>default group</em>.
+     *
+     * @param   group
+     *          The group to which the newly constructed channel should be bound,
+     *          or <tt>null</tt> for the default group
+     *
+     * @return  A new asynchronous server socket channel
+     *
+     * @throws  ShutdownChannelGroupException
+     *          If the channel group is shutdown
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousServerSocketChannel open(AsynchronousChannelGroup group)
+        throws IOException
+    {
+        AsynchronousChannelProvider provider = (group == null) ?
+            AsynchronousChannelProvider.provider() : group.provider();
+        return provider.openAsynchronousServerSocketChannel(group);
+    }
+
+    /**
+     * Opens an asynchronous server-socket channel.
+     *
+     * <p> This method returns an asynchronous server socket channel that is
+     * bound to the <em>default group</em>. This method is equivalent to evaluating
+     * the expression:
+     * <blockquote><pre>
+     * open((AsynchronousChannelGroup)null);
+     * </pre></blockquote>
+     *
+     * @return  A new asynchronous server socket channel
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousServerSocketChannel open()
+        throws IOException
+    {
+        return open(null);
+    }
+
+    /**
+     * Binds the channel's socket to a local address and configures the socket to
+     * listen for connections.
+     *
+     * <p> An invocation of this method is equivalent to the following:
+     * <blockquote><pre>
+     * bind(local, 0);
+     * </pre></blockquote>
+     *
+     * @param   local
+     *          The local address to bind the socket, or <tt>null</tt> to bind
+     *          to an automatically assigned socket address
+     *
+     * @return  This channel
+     *
+     * @throws  AlreadyBoundException               {@inheritDoc}
+     * @throws  UnsupportedAddressTypeException     {@inheritDoc}
+     * @throws  SecurityException                   {@inheritDoc}
+     * @throws  ClosedChannelException              {@inheritDoc}
+     * @throws  IOException                         {@inheritDoc}
+     */
+    public final AsynchronousServerSocketChannel bind(SocketAddress local)
+        throws IOException
+    {
+        return bind(local, 0);
+    }
+
+    /**
+     * Binds the channel's socket to a local address and configures the socket to
+     * listen for connections.
+     *
+     * <p> This method is used to establish an association between the socket and
+     * a local address. Once an association is established then the socket remains
+     * bound until the associated channel is closed.
+     *
+     * <p> The {@code backlog} parameter is the maximum number of pending
+     * connections on the socket. Its exact semantics are implementation specific.
+     * In particular, an implementation may impose a maximum length or may choose
+     * to ignore the parameter altogther. If the {@code backlog} parameter has
+     * the value {@code 0}, or a negative value, then an implementation specific
+     * default is used.
+     *
+     * @param   local
+     *          The local address to bind the socket, or {@code null} to bind
+     *          to an automatically assigned socket address
+     * @param   backlog
+     *          The maximum number of pending connections
+     *
+     * @return  This channel
+     *
+     * @throws  AlreadyBoundException
+     *          If the socket is already bound
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given address is not supported
+     * @throws  SecurityException
+     *          If a security manager has been installed and its {@link
+     *          SecurityManager#checkListen checkListen} method denies the operation
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract AsynchronousServerSocketChannel bind(SocketAddress local, int backlog)
+        throws IOException;
+
+    /**
+     * @throws  IllegalArgumentException                {@inheritDoc}
+     * @throws  ClosedChannelException                  {@inheritDoc}
+     * @throws  IOException                             {@inheritDoc}
+     */
+    public abstract <T> AsynchronousServerSocketChannel setOption(SocketOption<T> name, T value)
+        throws IOException;
+
+    /**
+     * Accepts a connection.
+     *
+     * <p> This method initiates accepting a connection made to this channel's
+     * socket, returning a {@link Future} representing the pending result
+     * of the operation. The {@code Future}'s {@link Future#get() get}
+     * method will return the {@link AsynchronousSocketChannel} for the new
+     * connection on successful completion.
+     *
+     * <p> When a new connection is accepted then the resulting {@code
+     * AsynchronousSocketChannel} will be bound to the same {@link
+     * AsynchronousChannelGroup} as this channel. If the group is {@link
+     * AsynchronousChannelGroup#isShutdown shutdown} and a connection is accepted,
+     * then the connection is closed, and the operation completes with an {@code
+     * IOException} and cause {@link ShutdownChannelGroupException}.
+     *
+     * <p> To allow for concurrent handling of new connections, the completion
+     * handler is not invoked directly by the initiating thread when a new
+     * connection is accepted immediately (see <a
+     * href="AsynchronousChannelGroup.html#threading">Threading<a>).
+     *
+     * <p> If a security manager has been installed then it verifies that the
+     * address and port number of the connection's remote endpoint are permitted
+     * by the security manager's {@link SecurityManager#checkAccept checkAccept}
+     * method. The permission check is performed with privileges that are restricted
+     * by the calling context of this method. If the permission check fails then
+     * the connection is closed and the operation completes with a {@link
+     * SecurityException}.
+     *
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  an <tt>Future</tt> object representing the pending result
+     *
+     * @throws  AcceptPendingException
+     *          If an accept operation is already in progress on this channel
+     * @throws  NotYetBoundException
+     *          If this channel's socket has not yet been bound
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    public abstract <A> Future<AsynchronousSocketChannel>
+        accept(A attachment, CompletionHandler<AsynchronousSocketChannel,? super A> handler);
+
+    /**
+     * Accepts a connection.
+     *
+     * <p> This method is equivalent to invoking {@link
+     * #accept(Object,CompletionHandler)} with the {@code attachment}
+     * and {@code handler} parameters set to {@code null}.
+     *
+     * @return  an <tt>Future</tt> object representing the pending result
+     *
+     * @throws  AcceptPendingException
+     *          If an accept operation is already in progress on this channel
+     * @throws  NotYetBoundException
+     *          If this channel's socket has not yet been bound
+     */
+    public final Future<AsynchronousSocketChannel> accept() {
+        return accept(null, null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,670 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.channels;
+
+import java.nio.channels.spi.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.Future;
+import java.io.IOException;
+import java.net.SocketOption;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+
+/**
+ * An asynchronous channel for stream-oriented connecting sockets.
+ *
+ * <p> Asynchronous socket channels are created in one of two ways. A newly-created
+ * {@code AsynchronousSocketChannel} is created by invoking one of the {@link
+ * #open open} methods defined by this class. A newly-created channel is open but
+ * not yet connected. A connected {@code AsynchronousSocketChannel} is created
+ * when a connection is made to the socket of an {@link AsynchronousServerSocketChannel}.
+ * It is not possible to create an asynchronous socket channel for an arbitrary,
+ * pre-existing {@link java.net.Socket socket}.
+ *
+ * <p> A newly-created channel is connected by invoking its {@link #connect connect}
+ * method; once connected, a channel remains connected until it is closed.  Whether
+ * or not a socket channel is connected may be determined by invoking its {@link
+ * #getRemoteAddress getRemoteAddress} method. An attempt to invoke an I/O
+ * operation upon an unconnected channel will cause a {@link NotYetConnectedException}
+ * to be thrown.
+ *
+ * <p> Channels of this type are safe for use by multiple concurrent threads.
+ * They support concurrent reading and writing, though at most one read operation
+ * and one write operation can be outstanding at any time.
+ * If a thread initiates a read operation before a previous read operation has
+ * completed then a {@link ReadPendingException} will be thrown. Similarly, an
+ * attempt to initiate a write operation before a previous write has completed
+ * will throw a {@link WritePendingException}.
+ *
+ * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. Asynchronous socket channels support the following options:
+ * <blockquote>
+ * <table border>
+ *   <tr>
+ *     <th>Option Name</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF} </td>
+ *     <td> The size of the socket send buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} </td>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_KEEPALIVE SO_KEEPALIVE} </td>
+ *     <td> Keep connection alive </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} </td>
+ *     <td> Re-use address </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOption#TCP_NODELAY TCP_NODELAY} </td>
+ *     <td> Disable the Nagle algorithm </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
+ * <h4>Timeouts</h4>
+ *
+ * <p> The {@link #read(ByteBuffer,long,TimeUnit,Object,CompletionHandler) read}
+ * and {@link #write(ByteBuffer,long,TimeUnit,Object,CompletionHandler) write}
+ * methods defined by this class allow a timeout to be specified when initiating
+ * a read or write operation. If the timeout elapses before an operation completes
+ * then the operation completes with the exception {@link
+ * InterruptedByTimeoutException}. A timeout may leave the channel, or the
+ * underlying connection, in an inconsistent state. Where the implementation
+ * cannot guarantee that bytes have not been read from the channel then it puts
+ * the channel into an implementation specific <em>error state</em>. A subsequent
+ * attempt to initiate a {@code read} operation causes an unspecified runtime
+ * exception to be thrown. Similarly if a {@code write} operation times out and
+ * the implementation cannot guarantee bytes have not been written to the
+ * channel then further attempts to {@code write} to the channel cause an
+ * unspecified runtime exception to be thrown. When a timeout elapses then the
+ * state of the {@link ByteBuffer}, or the sequence of buffers, for the I/O
+ * operation is not defined. Buffers should be discarded or at least care must
+ * be taken to ensure that the buffers are not accessed while the channel remains
+ * open.
+ *
+ * @since 1.7
+ */
+
+public abstract class AsynchronousSocketChannel
+    implements AsynchronousByteChannel, NetworkChannel
+{
+    private final AsynchronousChannelProvider provider;
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected AsynchronousSocketChannel(AsynchronousChannelProvider provider) {
+        this.provider = provider;
+    }
+
+    /**
+     * Returns the provider that created this channel.
+     */
+    public final AsynchronousChannelProvider provider() {
+        return provider;
+    }
+
+    /**
+     * Opens an asynchronous socket channel.
+     *
+     * <p> The new channel is created by invoking the {@link
+     * AsynchronousChannelProvider#openAsynchronousSocketChannel
+     * openAsynchronousSocketChannel} method on the {@link
+     * AsynchronousChannelProvider} that created the group. If the group parameter
+     * is {@code null} then the resulting channel is created by the system-wide
+     * default provider, and bound to the <em>default group</em>.
+     *
+     * @param   group
+     *          The group to which the newly constructed channel should be bound,
+     *          or {@code null} for the default group
+     *
+     * @return  A new asynchronous socket channel
+     *
+     * @throws  ShutdownChannelGroupException
+     *          If the channel group is shutdown
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousSocketChannel open(AsynchronousChannelGroup group)
+        throws IOException
+    {
+        AsynchronousChannelProvider provider = (group == null) ?
+            AsynchronousChannelProvider.provider() : group.provider();
+        return provider.openAsynchronousSocketChannel(group);
+    }
+
+    /**
+     * Opens an asynchronous socket channel.
+     *
+     * <p> This method returns an asynchronous socket channel that is bound to
+     * the <em>default group</em>.This method is equivalent to evaluating the
+     * expression:
+     * <blockquote><pre>
+     * open((AsynchronousChannelGroup)null);
+     * </pre></blockquote>
+     *
+     * @return  A new asynchronous socket channel
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousSocketChannel open()
+        throws IOException
+    {
+        return open(null);
+    }
+
+
+    // -- socket options and related --
+
+    /**
+     * @throws  ConnectionPendingException
+     *          If a connection operation is already in progress on this channel
+     * @throws  AlreadyBoundException               {@inheritDoc}
+     * @throws  UnsupportedAddressTypeException     {@inheritDoc}
+     * @throws  ClosedChannelException              {@inheritDoc}
+     * @throws  IOException                         {@inheritDoc}
+     */
+    @Override
+    public abstract AsynchronousSocketChannel bind(SocketAddress local)
+        throws IOException;
+
+    /**
+     * @throws  IllegalArgumentException                {@inheritDoc}
+     * @throws  ClosedChannelException                  {@inheritDoc}
+     * @throws  IOException                             {@inheritDoc}
+     */
+    @Override
+    public abstract <T> AsynchronousSocketChannel setOption(SocketOption<T> name, T value)
+        throws IOException;
+
+    /**
+     * Shutdown the connection for reading without closing the channel.
+     *
+     * <p> Once shutdown for reading then further reads on the channel will
+     * return {@code -1}, the end-of-stream indication. If the input side of the
+     * connection is already shutdown then invoking this method has no effect.
+     * The effect on an outstanding read operation is system dependent and
+     * therefore not specified. The effect, if any, when there is data in the
+     * socket receive buffer that has not been read, or data arrives subsequently,
+     * is also system dependent.
+     *
+     * @return  The channel
+     *
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract AsynchronousSocketChannel shutdownInput() throws IOException;
+
+    /**
+     * Shutdown the connection for writing without closing the channel.
+     *
+     * <p> Once shutdown for writing then further attempts to write to the
+     * channel will throw {@link ClosedChannelException}. If the output side of
+     * the connection is already shutdown then invoking this method has no
+     * effect. The effect on an outstanding write operation is system dependent
+     * and therefore not specified.
+     *
+     * @return  The channel
+     *
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract AsynchronousSocketChannel shutdownOutput() throws IOException;
+
+    // -- state --
+
+    /**
+     * Returns the remote address to which this channel's socket is connected.
+     *
+     * <p> Where the channel is bound and connected to an Internet Protocol
+     * socket address then the return value from this method is of type {@link
+     * java.net.InetSocketAddress}.
+     *
+     * @return  The remote address; {@code null} if the channel's socket is not
+     *          connected
+     *
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract SocketAddress getRemoteAddress() throws IOException;
+
+    // -- asynchronous operations --
+
+    /**
+     * Connects this channel.
+     *
+     * <p> This method initiates an operation to connect this channel, returning
+     * a {@code Future} representing the pending result of the operation. If
+     * the connection is successfully established then the {@code Future}'s
+     * {@link Future#get() get} method will return {@code null}. If the
+     * connection cannot be established then the channel is closed. In that case,
+     * invoking the {@code get} method throws {@link
+     * java.util.concurrent.ExecutionException} with an {@code IOException} as
+     * the cause.
+     *
+     * <p> This method performs exactly the same security checks as the {@link
+     * java.net.Socket} class.  That is, if a security manager has been
+     * installed then this method verifies that its {@link
+     * java.lang.SecurityManager#checkConnect checkConnect} method permits
+     * connecting to the address and port number of the given remote endpoint.
+     *
+     * @param   remote
+     *          The remote address to which this channel is to be connected
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  A {@code Future} object representing the pending result
+     *
+     * @throws  UnresolvedAddressException
+     *          If the given remote address is not fully resolved
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given remote address is not supported
+     * @throws  AlreadyConnectedException
+     *          If this channel is already connected
+     * @throws  ConnectionPendingException
+     *          If a connection operation is already in progress on this channel
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     * @throws  SecurityException
+     *          If a security manager has been installed
+     *          and it does not permit access to the given remote endpoint
+     *
+     * @see #getRemoteAddress
+     */
+    public abstract <A> Future<Void> connect(SocketAddress remote,
+                                             A attachment,
+                                             CompletionHandler<Void,? super A> handler);
+
+    /**
+     * Connects this channel.
+     *
+     * <p> This method is equivalent to invoking {@link
+     * #connect(SocketAddress,Object,CompletionHandler)} with the {@code attachment}
+     * and handler parameters set to {@code null}.
+     *
+     * @param   remote
+     *          The remote address to which this channel is to be connected
+     *
+     * @return  A {@code Future} object representing the pending result
+     *
+     * @throws  UnresolvedAddressException
+     *          If the given remote address is not fully resolved
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given remote address is not supported
+     * @throws  AlreadyConnectedException
+     *          If this channel is already connected
+     * @throws  ConnectionPendingException
+     *          If a connection operation is already in progress on this channel
+     * @throws  SecurityException
+     *          If a security manager has been installed
+     *          and it does not permit access to the given remote endpoint
+     */
+    public final Future<Void> connect(SocketAddress remote) {
+        return connect(remote, null, null);
+    }
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer.
+     *
+     * <p> This method initiates the reading of a sequence of bytes from this
+     * channel into the given buffer, returning a {@code Future} representing
+     * the pending result of the operation. The {@code Future}'s {@link
+     * Future#get() get} method returns the number of bytes read or {@code -1}
+     * if all bytes have been read and channel has reached end-of-stream.
+     *
+     * <p> If a timeout is specified and the timeout elapses before the operation
+     * completes then the operation completes with the exception {@link
+     * InterruptedByTimeoutException}. Where a timeout occurs, and the
+     * implementation cannot guarantee that bytes have not been read, or will not
+     * be read from the channel into the given buffer, then further attempts to
+     * read from the channel will cause an unspecific runtime exception to be
+     * thrown.
+     *
+     * <p> Otherwise this method works in the same manner as the {@link
+     * AsynchronousByteChannel#read(ByteBuffer,Object,CompletionHandler)}
+     * method.
+     *
+     * @param   dst
+     *          The buffer into which bytes are to be transferred
+     * @param   timeout
+     *          The timeout, or {@code 0L} for no timeout
+     * @param   unit
+     *          The time unit of the {@code timeout} argument
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  A {@code Future} object representing the pending result
+     *
+     * @throws  IllegalArgumentException
+     *          If the {@code timeout} parameter is negative or the buffer is
+     *          read-only
+     * @throws  ReadPendingException
+     *          If a read operation is already in progress on this channel
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    public abstract <A> Future<Integer> read(ByteBuffer dst,
+                                             long timeout,
+                                             TimeUnit unit,
+                                             A attachment,
+                                             CompletionHandler<Integer,? super A> handler);
+
+    /**
+     * @throws  IllegalArgumentException        {@inheritDoc}
+     * @throws  ReadPendingException            {@inheritDoc}
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    @Override
+    public final <A> Future<Integer> read(ByteBuffer dst,
+                                          A attachment,
+                                          CompletionHandler<Integer,? super A> handler)
+    {
+        return read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler);
+    }
+
+    /**
+     * @throws  IllegalArgumentException        {@inheritDoc}
+     * @throws  ReadPendingException            {@inheritDoc}
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     */
+    @Override
+    public final Future<Integer> read(ByteBuffer dst) {
+        return read(dst, 0L, TimeUnit.MILLISECONDS, null, null);
+    }
+
+    /**
+     * Reads a sequence of bytes from this channel into a subsequence of the
+     * given buffers. This operation, sometimes called a <em>scattering read</em>,
+     * is often useful when implementing network protocols that group data into
+     * segments consisting of one or more fixed-length headers followed by a
+     * variable-length body.
+     *
+     * <p> This method initiates a read of up to <i>r</i> bytes from this channel,
+     * where <i>r</i> is the total number of bytes remaining in the specified
+     * subsequence of the given buffer array, that is,
+     *
+     * <blockquote><pre>
+     * dsts[offset].remaining()
+     *     + dsts[offset+1].remaining()
+     *     + ... + dsts[offset+length-1].remaining()</pre></blockquote>
+     *
+     * at the moment that the read is attempted.
+     *
+     * <p> Suppose that a byte sequence of length <i>n</i> is read, where
+     * <tt>0</tt>&nbsp;<tt>&lt;</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>.
+     * Up to the first <tt>dsts[offset].remaining()</tt> bytes of this sequence
+     * are transferred into buffer <tt>dsts[offset]</tt>, up to the next
+     * <tt>dsts[offset+1].remaining()</tt> bytes are transferred into buffer
+     * <tt>dsts[offset+1]</tt>, and so forth, until the entire byte sequence
+     * is transferred into the given buffers.  As many bytes as possible are
+     * transferred into each buffer, hence the final position of each updated
+     * buffer, except the last updated buffer, is guaranteed to be equal to
+     * that buffer's limit. The underlying operating system may impose a limit
+     * on the number of buffers that may be used in an I/O operation. Where the
+     * number of buffers (with bytes remaining), exceeds this limit, then the
+     * I/O operation is performed with the maximum number of buffers allowed by
+     * the operating system.
+     *
+     * <p> The return value from this method is a {@code Future} representing
+     * the pending result of the operation. The {@code Future}'s {@link
+     * Future#get() get} method returns the number of bytes read or {@code -1L}
+     * if all bytes have been read and the channel has reached end-of-stream.
+     *
+     * <p> If a timeout is specified and the timeout elapses before the operation
+     * completes then it completes with the exception {@link
+     * InterruptedByTimeoutException}. Where a timeout occurs, and the
+     * implementation cannot guarantee that bytes have not been read, or will not
+     * be read from the channel into the given buffers, then further attempts to
+     * read from the channel will cause an unspecific runtime exception to be
+     * thrown.
+     *
+     * @param   dsts
+     *          The buffers into which bytes are to be transferred
+     * @param   offset
+     *          The offset within the buffer array of the first buffer into which
+     *          bytes are to be transferred; must be non-negative and no larger than
+     *          {@code dsts.length}
+     * @param   length
+     *          The maximum number of buffers to be accessed; must be non-negative
+     *          and no larger than {@code dsts.length - offset}
+     * @param   timeout
+     *          The timeout, or {@code 0L} for no timeout
+     * @param   unit
+     *          The time unit of the {@code timeout} argument
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  A {@code Future} object representing the pending result
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the pre-conditions for the {@code offset}  and {@code length}
+     *          parameter aren't met
+     * @throws  IllegalArgumentException
+     *          If the {@code timeout} parameter is negative, or a buffer is
+     *          read-only
+     * @throws  ReadPendingException
+     *          If a read operation is already in progress on this channel
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    public abstract <A> Future<Long> read(ByteBuffer[] dsts,
+                                          int offset,
+                                          int length,
+                                          long timeout,
+                                          TimeUnit unit,
+                                          A attachment,
+                                          CompletionHandler<Long,? super A> handler);
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer.
+     *
+     * <p> This method initiates the writing of a sequence of bytes to this channel
+     * from the given buffer, returning a {@code Future} representing the
+     * pending result of the operation. The {@code Future}'s {@link Future#get()
+     * get} method will return the number of bytes written.
+     *
+     * <p> If a timeout is specified and the timeout elapses before the operation
+     * completes then it completes with the exception {@link
+     * InterruptedByTimeoutException}. Where a timeout occurs, and the
+     * implementation cannot guarantee that bytes have not been written, or will
+     * not be written to the channel from the given buffer, then further attempts
+     * to write to the channel will cause an unspecific runtime exception to be
+     * thrown.
+     *
+     * <p> Otherwise this method works in the same manner as the {@link
+     * AsynchronousByteChannel#write(ByteBuffer,Object,CompletionHandler)}
+     * method.
+     *
+     * @param   src
+     *          The buffer from which bytes are to be retrieved
+     * @param   timeout
+     *          The timeout, or {@code 0L} for no timeout
+     * @param   unit
+     *          The time unit of the {@code timeout} argument
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  A {@code Future} object representing the pending result
+     *
+     * @throws  IllegalArgumentException
+     *          If the {@code timeout} parameter is negative
+     * @throws  WritePendingException
+     *          If a write operation is already in progress on this channel
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    public abstract <A> Future<Integer> write(ByteBuffer src,
+                                              long timeout,
+                                              TimeUnit unit,
+                                              A attachment,
+                                              CompletionHandler<Integer,? super A> handler);
+
+    /**
+     * @throws  WritePendingException          {@inheritDoc}
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    @Override
+    public final <A> Future<Integer> write(ByteBuffer src,
+                                           A attachment,
+                                           CompletionHandler<Integer,? super A> handler)
+
+    {
+        return write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler);
+    }
+
+    /**
+     * @throws  WritePendingException       {@inheritDoc}
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     */
+    @Override
+    public final Future<Integer> write(ByteBuffer src) {
+        return write(src, 0L, TimeUnit.MILLISECONDS, null, null);
+    }
+
+    /**
+     * Writes a sequence of bytes to this channel from a subsequence of the given
+     * buffers. This operation, sometimes called a <em>gathering write</em>, is
+     * often useful when implementing network protocols that group data into
+     * segments consisting of one or more fixed-length headers followed by a
+     * variable-length body.
+     *
+     * <p> This method initiates a write of up to <i>r</i> bytes to this channel,
+     * where <i>r</i> is the total number of bytes remaining in the specified
+     * subsequence of the given buffer array, that is,
+     *
+     * <blockquote><pre>
+     * srcs[offset].remaining()
+     *     + srcs[offset+1].remaining()
+     *     + ... + srcs[offset+length-1].remaining()</pre></blockquote>
+     *
+     * at the moment that the write is attempted.
+     *
+     * <p> Suppose that a byte sequence of length <i>n</i> is written, where
+     * <tt>0</tt>&nbsp;<tt>&lt;</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>.
+     * Up to the first <tt>srcs[offset].remaining()</tt> bytes of this sequence
+     * are written from buffer <tt>srcs[offset]</tt>, up to the next
+     * <tt>srcs[offset+1].remaining()</tt> bytes are written from buffer
+     * <tt>srcs[offset+1]</tt>, and so forth, until the entire byte sequence is
+     * written.  As many bytes as possible are written from each buffer, hence
+     * the final position of each updated buffer, except the last updated
+     * buffer, is guaranteed to be equal to that buffer's limit. The underlying
+     * operating system may impose a limit on the number of buffers that may be
+     * used in an I/O operation. Where the number of buffers (with bytes
+     * remaining), exceeds this limit, then the I/O operation is performed with
+     * the maximum number of buffers allowed by the operating system.
+     *
+     * <p> The return value from this method is a {@code Future} representing
+     * the pending result of the operation. The {@code Future}'s {@link
+     * Future#get() get} method will return the number of bytes written.
+     *
+     * <p> If a timeout is specified and the timeout elapses before the operation
+     * completes then it completes with the exception {@link
+     * InterruptedByTimeoutException}. Where a timeout occurs, and the
+     * implementation cannot guarantee that bytes have not been written, or will
+     * not be written to the channel from the given buffers, then further attempts
+     * to write to the channel will cause an unspecific runtime exception to be
+     * thrown.
+     *
+     * @param   srcs
+     *          The buffers from which bytes are to be retrieved
+     * @param   offset
+     *          The offset within the buffer array of the first buffer from which
+     *          bytes are to be retrieved; must be non-negative and no larger
+     *          than {@code srcs.length}
+     * @param   length
+     *          The maximum number of buffers to be accessed; must be non-negative
+     *          and no larger than {@code srcs.length - offset}
+     * @param   timeout
+     *          The timeout, or {@code 0L} for no timeout
+     * @param   unit
+     *          The time unit of the {@code timeout} argument
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result; can be {@code null}
+     *
+     * @return  A {@code Future} object representing the pending result
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the pre-conditions for the {@code offset}  and {@code length}
+     *          parameter aren't met
+     * @throws  IllegalArgumentException
+     *          If the {@code timeout} parameter is negative
+     * @throws  WritePendingException
+     *          If a write operation is already in progress on this channel
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ShutdownChannelGroupException
+     *          If a handler is specified, and the channel group is shutdown
+     */
+    public abstract <A> Future<Long> write(ByteBuffer[] srcs,
+                                           int offset,
+                                           int length,
+                                           long timeout,
+                                           TimeUnit unit,
+                                           A attachment,
+                                           CompletionHandler<Long,? super A> handler);
+}
--- a/jdk/src/share/classes/java/nio/channels/Channels.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/nio/channels/Channels.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -33,15 +33,12 @@
 import java.io.Writer;
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.BufferOverflowException;
-import java.nio.BufferUnderflowException;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetDecoder;
 import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CoderResult;
 import java.nio.charset.UnsupportedCharsetException;
 import java.nio.channels.spi.AbstractInterruptibleChannel;
+import java.util.concurrent.ExecutionException;
 import sun.nio.ch.ChannelInputStream;
 import sun.nio.cs.StreamDecoder;
 import sun.nio.cs.StreamEncoder;
@@ -184,6 +181,155 @@
             };
     }
 
+    /**
+     * {@note new}
+     * Constructs a stream that reads bytes from the given channel.
+     *
+     * <p> The stream will not be buffered, and it will not support the {@link
+     * InputStream#mark mark} or {@link InputStream#reset reset} methods.  The
+     * stream will be safe for access by multiple concurrent threads.  Closing
+     * the stream will in turn cause the channel to be closed.  </p>
+     *
+     * @param  ch
+     *         The channel from which bytes will be read
+     *
+     * @return  A new input stream
+     *
+     * @since 1.7
+     */
+    public static InputStream newInputStream(final AsynchronousByteChannel ch) {
+        checkNotNull(ch, "ch");
+        return new InputStream() {
+
+            private ByteBuffer bb = null;
+            private byte[] bs = null;           // Invoker's previous array
+            private byte[] b1 = null;
+
+            @Override
+            public synchronized int read() throws IOException {
+                if (b1 == null)
+                    b1 = new byte[1];
+                int n = this.read(b1);
+                if (n == 1)
+                    return b1[0] & 0xff;
+                return -1;
+            }
+
+            @Override
+            public synchronized int read(byte[] bs, int off, int len)
+                throws IOException
+            {
+                if ((off < 0) || (off > bs.length) || (len < 0) ||
+                    ((off + len) > bs.length) || ((off + len) < 0)) {
+                    throw new IndexOutOfBoundsException();
+                } else if (len == 0)
+                    return 0;
+
+                ByteBuffer bb = ((this.bs == bs)
+                                 ? this.bb
+                                 : ByteBuffer.wrap(bs));
+                bb.position(off);
+                bb.limit(Math.min(off + len, bb.capacity()));
+                this.bb = bb;
+                this.bs = bs;
+
+                boolean interrupted = false;
+                try {
+                    for (;;) {
+                        try {
+                            return ch.read(bb).get();
+                        } catch (ExecutionException ee) {
+                            throw new IOException(ee.getCause());
+                        } catch (InterruptedException ie) {
+                            interrupted = true;
+                        }
+                    }
+                } finally {
+                    if (interrupted)
+                        Thread.currentThread().interrupt();
+                }
+            }
+
+            @Override
+            public void close() throws IOException {
+                ch.close();
+            }
+        };
+    }
+
+    /**
+     * {@note new}
+     * Constructs a stream that writes bytes to the given channel.
+     *
+     * <p> The stream will not be buffered. The stream will be safe for access
+     * by multiple concurrent threads.  Closing the stream will in turn cause
+     * the channel to be closed.  </p>
+     *
+     * @param  ch
+     *         The channel to which bytes will be written
+     *
+     * @return  A new output stream
+     *
+     * @since 1.7
+     */
+    public static OutputStream newOutputStream(final AsynchronousByteChannel ch) {
+        checkNotNull(ch, "ch");
+        return new OutputStream() {
+
+            private ByteBuffer bb = null;
+            private byte[] bs = null;   // Invoker's previous array
+            private byte[] b1 = null;
+
+            @Override
+            public synchronized void write(int b) throws IOException {
+               if (b1 == null)
+                    b1 = new byte[1];
+                b1[0] = (byte)b;
+                this.write(b1);
+            }
+
+            @Override
+            public synchronized void write(byte[] bs, int off, int len)
+                throws IOException
+            {
+                if ((off < 0) || (off > bs.length) || (len < 0) ||
+                    ((off + len) > bs.length) || ((off + len) < 0)) {
+                    throw new IndexOutOfBoundsException();
+                } else if (len == 0) {
+                    return;
+                }
+                ByteBuffer bb = ((this.bs == bs)
+                                 ? this.bb
+                                 : ByteBuffer.wrap(bs));
+                bb.limit(Math.min(off + len, bb.capacity()));
+                bb.position(off);
+                this.bb = bb;
+                this.bs = bs;
+
+                boolean interrupted = false;
+                try {
+                    while (bb.remaining() > 0) {
+                        try {
+                            ch.write(bb).get();
+                        } catch (ExecutionException ee) {
+                            throw new IOException(ee.getCause());
+                        } catch (InterruptedException ie) {
+                            interrupted = true;
+                        }
+                    }
+                } finally {
+                    if (interrupted)
+                        Thread.currentThread().interrupt();
+                }
+            }
+
+            @Override
+            public void close() throws IOException {
+                ch.close();
+            }
+        };
+    }
+
 
     // -- Channels from streams --
 
@@ -468,5 +614,4 @@
         checkNotNull(csName, "csName");
         return newWriter(ch, Charset.forName(csName).newEncoder(), -1);
     }
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/CompletionHandler.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.channels;
+
+/**
+ * A handler for consuming the result of an asynchronous I/O operation.
+ *
+ * <p> The asynchronous channels defined in this package allow a completion
+ * handler to be specified to consume the result of an asynchronous operation.
+ * The {@link #completed completed} method is invoked when the I/O operation
+ * completes successfully. The {@link #failed failed} method is invoked if the
+ * I/O operations fails. The {@link #cancelled cancelled} method is invoked when
+ * the I/O operation is cancelled by invoking the {@link
+ * java.util.concurrent.Future#cancel cancel} method. The implementations of
+ * these methods should complete in a timely manner so as to avoid keeping the
+ * invoking thread from dispatching to other completion handlers.
+ *
+ * @param   <V>     The result type of the I/O operation
+ * @param   <A>     The type of the object attached to the I/O operation
+ *
+ * @since 1.7
+ */
+
+public interface CompletionHandler<V,A> {
+
+    /**
+     * Invoked when an operation has completed.
+     *
+     * @param   result
+     *          The result of the I/O operation.
+     * @param   attachment
+     *          The object attached to the I/O operation when it was initiated.
+     */
+    void completed(V result, A attachment);
+
+    /**
+     * Invoked when an operation fails.
+     *
+     * @param   exc
+     *          The exception to indicate why the I/O operation failed
+     * @param   attachment
+     *          The object attached to the I/O operation when it was initiated.
+     */
+    void failed(Throwable exc, A attachment);
+
+    /**
+     * Invoked when an operation is cancelled by invoking the {@link
+     * java.util.concurrent.Future#cancel cancel} method.
+     *
+     * @param   attachment
+     *          The object attached to the I/O operation when it was initiated.
+     */
+    void cancelled(A attachment);
+}
--- a/jdk/src/share/classes/java/nio/channels/DatagramChannel.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/nio/channels/DatagramChannel.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -31,7 +31,8 @@
 import java.net.SocketOption;
 import java.net.SocketAddress;
 import java.nio.ByteBuffer;
-import java.nio.channels.spi.*;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.SelectorProvider;
 
 /**
  * A selectable channel for datagram-oriented sockets.
@@ -53,7 +54,8 @@
  * be determined by invoking its {@link #isConnected isConnected} method.
  *
  * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
- * setOption} method. Datagram channels support the following options:
+ * setOption} method. A datagram channel to an Internet Protocol socket supports
+ * the following options:
  * <blockquote>
  * <table border>
  *   <tr>
@@ -211,6 +213,7 @@
         throws IOException;
 
     /**
+     * @throws  UnsupportedOperationException           {@inheritDoc}
      * @throws  IllegalArgumentException                {@inheritDoc}
      * @throws  ClosedChannelException                  {@inheritDoc}
      * @throws  IOException                             {@inheritDoc}
@@ -220,7 +223,6 @@
     public abstract <T> DatagramChannel setOption(SocketOption<T> name, T value)
         throws IOException;
 
-
     /**
      * Retrieves a datagram socket associated with this channel.
      *
@@ -313,15 +315,17 @@
     /**
      * Returns the remote address to which this channel's socket is connected.
      *
-     * @return  The remote address; {@code null} if the channel is not {@link
-     *          #isOpen open} or the channel's socket is not connected
+     * @return  The remote address; {@code null} if the channel's socket is not
+     *          connected
      *
+     * @throws  ClosedChannelException
+     *          If the channel is closed
      * @throws  IOException
      *          If an I/O error occurs
      *
      * @since 1.7
      */
-    public abstract SocketAddress getConnectedAddress() throws IOException;
+    public abstract SocketAddress getRemoteAddress() throws IOException;
 
     /**
      * Receives a datagram via this channel.
--- a/jdk/src/share/classes/java/nio/channels/FileChannel.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/nio/channels/FileChannel.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -29,16 +29,23 @@
 import java.nio.ByteBuffer;
 import java.nio.MappedByteBuffer;
 import java.nio.channels.spi.AbstractInterruptibleChannel;
-
+import java.nio.file.*;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.spi.*;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
 
 /**
  * A channel for reading, writing, mapping, and manipulating a file.
  *
- * <p> A file channel has a current <i>position</i> within its file which can
- * be both {@link #position() </code>queried<code>} and {@link #position(long)
- * </code>modified<code>}.  The file itself contains a variable-length sequence
+ * <p> {@note revised}
+ * A file channel is a {@link SeekableByteChannel} that is connected to
+ * a file. It has a current <i>position</i> within its file which can
+ * be both {@link #position() <i>queried</i>} and {@link #position(long)
+ * <i>modified</i>}.  The file itself contains a variable-length sequence
  * of bytes that can be read and written and whose current {@link #size
- * </code><i>size</i><code>} can be queried.  The size of the file increases
+ * <i>size</i>} can be queried.  The size of the file increases
  * when bytes are written beyond its current size; the size of the file
  * decreases when it is {@link #truncate </code><i>truncated</i><code>}.  The
  * file may also have some associated <i>metadata</i> such as access
@@ -50,27 +57,27 @@
  *
  * <ul>
  *
- *   <li><p> Bytes may be {@link #read(ByteBuffer, long) </code>read<code>} or
- *   {@link #write(ByteBuffer, long) </code>written<code>} at an absolute
+ *   <li><p> Bytes may be {@link #read(ByteBuffer, long) read} or
+ *   {@link #write(ByteBuffer, long) <i>written</i>} at an absolute
  *   position in a file in a way that does not affect the channel's current
  *   position.  </p></li>
  *
- *   <li><p> A region of a file may be {@link #map </code>mapped<code>}
+ *   <li><p> A region of a file may be {@link #map <i>mapped</i>}
  *   directly into memory; for large files this is often much more efficient
  *   than invoking the usual <tt>read</tt> or <tt>write</tt> methods.
  *   </p></li>
  *
- *   <li><p> Updates made to a file may be {@link #force </code>forced
- *   out<code>} to the underlying storage device, ensuring that data are not
+ *   <li><p> Updates made to a file may be {@link #force <i>forced
+ *   out</i>} to the underlying storage device, ensuring that data are not
  *   lost in the event of a system crash.  </p></li>
  *
- *   <li><p> Bytes can be transferred from a file {@link #transferTo </code>to
- *   some other channel<code>}, and {@link #transferFrom </code>vice
- *   versa<code>}, in a way that can be optimized by many operating systems
+ *   <li><p> Bytes can be transferred from a file {@link #transferTo <i>to
+ *   some other channel</i>}, and {@link #transferFrom <i>vice
+ *   versa</i>}, in a way that can be optimized by many operating systems
  *   into a very fast transfer directly to or from the filesystem cache.
  *   </p></li>
  *
- *   <li><p> A region of a file may be {@link FileLock </code>locked<code>}
+ *   <li><p> A region of a file may be {@link FileLock <i>locked</i>}
  *   against access by other programs.  </p></li>
  *
  * </ul>
@@ -96,25 +103,23 @@
  * machine.  The exact nature of any such inconsistencies are system-dependent
  * and are therefore unspecified.
  *
- * <p> This class does not define methods for opening existing files or for
- * creating new ones; such methods may be added in a future release.  In this
- * release a file channel can be obtained from an existing {@link
- * java.io.FileInputStream#getChannel FileInputStream}, {@link
+ * <p> A file channel is created by invoking one of the {@link #open open}
+ * methods defined by this class. A file channel can also be obtained from an
+ * existing {@link java.io.FileInputStream#getChannel FileInputStream}, {@link
  * java.io.FileOutputStream#getChannel FileOutputStream}, or {@link
  * java.io.RandomAccessFile#getChannel RandomAccessFile} object by invoking
  * that object's <tt>getChannel</tt> method, which returns a file channel that
- * is connected to the same underlying file.
+ * is connected to the same underlying file. Where the file channel is obtained
+ * from an existing stream or random access file then the state of the file
+ * channel is intimately connected to that of the object whose <tt>getChannel</tt>
+ * method returned the channel.  Changing the channel's position, whether
+ * explicitly or by reading or writing bytes, will change the file position of
+ * the originating object, and vice versa. Changing the file's length via the
+ * file channel will change the length seen via the originating object, and vice
+ * versa.  Changing the file's content by writing bytes will change the content
+ * seen by the originating object, and vice versa.
  *
- * <p> The state of a file channel is intimately connected to that of the
- * object whose <tt>getChannel</tt> method returned the channel.  Changing the
- * channel's position, whether explicitly or by reading or writing bytes, will
- * change the file position of the originating object, and vice versa.
- * Changing the file's length via the file channel will change the length seen
- * via the originating object, and vice versa.  Changing the file's content by
- * writing bytes will change the content seen by the originating object, and
- * vice versa.
- *
- * <a name="open-mode"><p> At various points this class specifies that an
+ * <a name="open-mode"></a> <p> At various points this class specifies that an
  * instance that is "open for reading," "open for writing," or "open for
  * reading and writing" is required.  A channel obtained via the {@link
  * java.io.FileInputStream#getChannel getChannel} method of a {@link
@@ -127,7 +132,7 @@
  * was created with mode <tt>"r"</tt> and will be open for reading and writing
  * if the instance was created with mode <tt>"rw"</tt>.
  *
- * <a name="append-mode"><p> A file channel that is open for writing may be in
+ * <a name="append-mode"></a><p> A file channel that is open for writing may be in
  * <i>append mode</i>, for example if it was obtained from a file-output stream
  * that was created by invoking the {@link
  * java.io.FileOutputStream#FileOutputStream(java.io.File,boolean)
@@ -138,7 +143,6 @@
  * of the data are done in a single atomic operation is system-dependent and
  * therefore unspecified.
  *
- *
  * @see java.io.FileInputStream#getChannel()
  * @see java.io.FileOutputStream#getChannel()
  * @see java.io.RandomAccessFile#getChannel()
@@ -147,18 +151,190 @@
  * @author Mike McCloskey
  * @author JSR-51 Expert Group
  * @since 1.4
+ * @updated 1.7
  */
 
 public abstract class FileChannel
     extends AbstractInterruptibleChannel
-    implements ByteChannel, GatheringByteChannel, ScatteringByteChannel
+    implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel
 {
-
     /**
      * Initializes a new instance of this class.
      */
     protected FileChannel() { }
 
+    /**
+     * {@note new}
+     * Opens or creates a file, returning a file channel to access the file.
+     *
+     * <p> 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.
+     *
+     * <p> In the addition to {@code READ} and {@code WRITE}, the following
+     * options may be present:
+     *
+     * <table border=1 cellpadding=5 summary="">
+     * <tr> <th>Option</th> <th>Description</th> </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#APPEND APPEND} </td>
+     *   <td> 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. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} </td>
+     *   <td> 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. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#CREATE_NEW CREATE_NEW} </td>
+     *   <td> If this option is present then a new file is created, failing if
+     *   the file already exists. 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. </td>
+     * </tr>
+     * <tr>
+     *   <td > {@link StandardOpenOption#CREATE CREATE} </td>
+     *   <td> If this option is present then an existing file is opened if it
+     *   exists, otherwise a new file is created. 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 if the {@code CREATE_NEW} option is also present or
+     *   the file is opened only for reading. </td>
+     * </tr>
+     * <tr>
+     *   <td > {@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} </td>
+     *   <td> When this option is present then the implementation makes a
+     *   <em>best effort</em> attempt to delete the file when closed by the
+     *   the {@link #close close} method. If the {@code close} method is not
+     *   invoked then a <em>best effort</em> attempt is made to delete the file
+     *   when the Java virtual machine terminates. </td>
+     * </tr>
+     * <tr>
+     *   <td>{@link StandardOpenOption#SPARSE SPARSE} </td>
+     *   <td> When creating a new file this option is a <em>hint</em> that the
+     *   new file will be sparse. This option is ignored when not creating
+     *   a new file. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#SYNC SYNC} </td>
+     *   <td> Requires that every update to the file's content or metadata be
+     *   written synchronously to the underlying storage device. (see <a
+     *   href="../file/package-summary.html#integrity"> Synchronized I/O file
+     *   integrity</a>). </td>
+     * <tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#DSYNC DSYNC} </td>
+     *   <td> Requires that every update to the file's content be written
+     *   synchronously to the underlying storage device. (see <a
+     *   href="../file/package-summary.html#integrity"> Synchronized I/O file
+     *   integrity</a>). </td>
+     * </tr>
+     * </table>
+     *
+     * <p> An implementation may also support additional options.
+     *
+     * <p> The {@code attrs} parameter is an optional array of file {@link
+     * FileAttribute file-attributes} to set atomically when creating the file.
+     *
+     * <p> The new channel is created by invoking the {@link
+     * FileSystemProvider#newFileChannel newFileChannel} method on the
+     * provider that created the {@code Path}.
+     *
+     * @param   file
+     *          The path of 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 file channel
+     *
+     * @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
+     *          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
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an
+     *          unspecified permission required by the implementation.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String)} method is invoked to check
+     *          read access if the file is opened for reading. The {@link
+     *          SecurityManager#checkWrite(String)} method is invoked to check
+     *          write access if the file is opened for writing
+     *
+     * @since   1.7
+     */
+    public static FileChannel open(Path file,
+                                   Set<? extends OpenOption> options,
+                                   FileAttribute<?>... attrs)
+        throws IOException
+    {
+        FileSystemProvider provider = file.getFileSystem().provider();
+        return provider.newFileChannel(file, options, attrs);
+    }
+
+    private static final FileAttribute<?>[] NO_ATTRIBUTES = new FileAttribute[0];
+
+    /**
+     * {@note new}
+     * Opens or creates a file, returning a file channel to access the file.
+     *
+     * <p> An invocation of this method behaves in exactly the same way as the
+     * invocation
+     * <pre>
+     *     fc.{@link #open(Path,Set,FileAttribute[]) open}(file, options, new FileAttribute&lt;?&gt;[0]);
+     * </pre>
+     *
+     * @param   file
+     *          The path of the file to open or create
+     * @param   options
+     *          Options specifying how the file is opened
+     *
+     * @return  A new file channel
+     *
+     * @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
+     *          support creating file channels, or an unsupported open option is
+     *          specified
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an
+     *          unspecified permission required by the implementation.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String)} method is invoked to check
+     *          read access if the file is opened for reading. The {@link
+     *          SecurityManager#checkWrite(String)} method is invoked to check
+     *          write access if the file is opened for writing
+     *
+     * @since   1.7
+     */
+    public static FileChannel open(Path file, OpenOption... options)
+        throws IOException
+    {
+        Set<OpenOption> set = new HashSet<OpenOption>(options.length);
+        Collections.addAll(set, options);
+        return open(file, set, NO_ATTRIBUTES);
+    }
 
     // -- Channel operations --
 
@@ -286,7 +462,7 @@
     public abstract FileChannel position(long newPosition) throws IOException;
 
     /**
-     * Returns the current size of this channel's file. </p>
+     * Returns the current size of this channel's file.  </p>
      *
      * @return  The current size of this channel's file,
      *          measured in bytes
@@ -359,7 +535,7 @@
      * <p> This method is only guaranteed to force changes that were made to
      * this channel's file via the methods defined in this class.  It may or
      * may not force changes that were made by modifying the content of a
-     * {@link MappedByteBuffer </code>mapped byte buffer<code>} obtained by
+     * {@link MappedByteBuffer <i>mapped byte buffer</i>} obtained by
      * invoking the {@link #map map} method.  Invoking the {@link
      * MappedByteBuffer#force force} method of the mapped byte buffer will
      * force changes made to the buffer's content to be written.  </p>
@@ -678,7 +854,7 @@
      * reading; for a read/write or private mapping, this channel must have
      * been opened for both reading and writing.
      *
-     * <p> The {@link MappedByteBuffer </code>mapped byte buffer<code>}
+     * <p> The {@link MappedByteBuffer <i>mapped byte buffer</i>}
      * returned by this method will have a position of zero and a limit and
      * capacity of <tt>size</tt>; its mark will be undefined.  The buffer and
      * the mapping that it represents will remain valid until the buffer itself
@@ -717,6 +893,8 @@
      *         The size of the region to be mapped; must be non-negative and
      *         no greater than {@link java.lang.Integer#MAX_VALUE}
      *
+     * @return  The mapped byte buffer
+     *
      * @throws NonReadableChannelException
      *         If the <tt>mode</tt> is {@link MapMode#READ_ONLY READ_ONLY} but
      *         this channel was not opened for reading
--- a/jdk/src/share/classes/java/nio/channels/FileLock.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/nio/channels/FileLock.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2001-2009 Sun Microsystems, Inc.  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
@@ -27,14 +27,16 @@
 
 import java.io.IOException;
 
-
 /**
  * A token representing a lock on a region of a file.
  *
  * <p> A file-lock object is created each time a lock is acquired on a file via
  * one of the {@link FileChannel#lock(long,long,boolean) lock} or {@link
- * FileChannel#tryLock(long,long,boolean) tryLock} methods of the {@link
- * FileChannel} class.
+ * FileChannel#tryLock(long,long,boolean) tryLock} methods of the
+ * {@link FileChannel} class, or the {@link
+ * AsynchronousFileChannel#lock(long,long,boolean,Object,CompletionHandler) lock}
+ * or {@link AsynchronousFileChannel#tryLock(long,long,boolean) tryLock}
+ * methods of the {@link AsynchronousFileChannel} class.
  *
  * <p> A file-lock object is initially valid.  It remains valid until the lock
  * is released by invoking the {@link #release release} method, by closing the
@@ -70,8 +72,7 @@
  * <p> File-lock objects are safe for use by multiple concurrent threads.
  *
  *
- * <a name="pdep">
- * <h4> Platform dependencies </h4>
+ * <a name="pdep"><h4> Platform dependencies </h4></a>
  *
  * <p> This file-locking API is intended to map directly to the native locking
  * facility of the underlying operating system.  Thus the locks held on a file
@@ -93,7 +94,7 @@
  *
  * <p> On some systems, acquiring a mandatory lock on a region of a file
  * prevents that region from being {@link java.nio.channels.FileChannel#map
- * </code>mapped into memory<code>}, and vice versa.  Programs that combine
+ * <i>mapped into memory</i>}, and vice versa.  Programs that combine
  * locking and mapping should be prepared for this combination to fail.
  *
  * <p> On some systems, closing a channel releases all locks held by the Java
@@ -113,11 +114,12 @@
  * @author Mark Reinhold
  * @author JSR-51 Expert Group
  * @since 1.4
+ * @updated 1.7
  */
 
 public abstract class FileLock {
 
-    private final FileChannel channel;
+    private final Channel channel;
     private final long position;
     private final long size;
     private final boolean shared;
@@ -159,11 +161,66 @@
     }
 
     /**
-     * Returns the file channel upon whose file this lock is held.  </p>
+     * {@note new} Initializes a new instance of this class.
+     *
+     * @param  channel
+     *         The channel upon whose file this lock is held
+     *
+     * @param  position
+     *         The position within the file at which the locked region starts;
+     *         must be non-negative
+     *
+     * @param  size
+     *         The size of the locked region; must be non-negative, and the sum
+     *         <tt>position</tt>&nbsp;+&nbsp;<tt>size</tt> must be non-negative
+     *
+     * @param  shared
+     *         <tt>true</tt> if this lock is shared,
+     *         <tt>false</tt> if it is exclusive
+     *
+     * @throws IllegalArgumentException
+     *         If the preconditions on the parameters do not hold
      *
-     * @return  The file channel
+     * @since 1.7
+     */
+    protected FileLock(AsynchronousFileChannel channel,
+                       long position, long size, boolean shared)
+    {
+        if (position < 0)
+            throw new IllegalArgumentException("Negative position");
+        if (size < 0)
+            throw new IllegalArgumentException("Negative size");
+        if (position + size < 0)
+            throw new IllegalArgumentException("Negative position + size");
+        this.channel = channel;
+        this.position = position;
+        this.size = size;
+        this.shared = shared;
+    }
+
+    /**
+     * {@note revised}
+     * Returns the file channel upon whose file this lock was acquired.
+     *
+     * <p> This method has been superseded by the {@link #acquiredBy acquiredBy}
+     * method.
+     *
+     * @return  The file channel, or {@code null} if the file lock was not
+     *          acquired by a file channel.
      */
     public final FileChannel channel() {
+        return (channel instanceof FileChannel) ? (FileChannel)channel : null;
+    }
+
+    /**
+     * {@note new}
+     * Returns the channel upon whose file this lock was acquired.
+     *
+     * @return  The channel upon whose file this lock was acquired.
+     *
+     * @since 1.7
+     */
+    public Channel acquiredBy() {
         return channel;
     }
 
--- a/jdk/src/share/classes/java/nio/channels/MembershipKey.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/nio/channels/MembershipKey.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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
@@ -28,7 +28,6 @@
 import java.net.InetAddress;
 import java.net.NetworkInterface;
 import java.io.IOException;
-import java.util.List;
 
 /**
  * A token representing the membership of an Internet Protocol (IP) multicast
@@ -38,7 +37,7 @@
  * to the group, or it may be <em>source-specific</em>, meaning that it
  * represents a membership that receives only datagrams from a specific source
  * address. Whether or not a membership key is source-specific may be determined
- * by invoking its {@link #getSourceAddress() getSourceAddress} method.
+ * by invoking its {@link #sourceAddress() sourceAddress} method.
  *
  * <p> A membership key is valid upon creation and remains valid until the
  * membership is dropped by invoking the {@link #drop() drop} method, or
@@ -93,11 +92,8 @@
      * If the multicast group membership is already invalid then invoking this
      * method has no effect. Once a multicast group membership is invalid,
      * it remains invalid forever.
-     *
-     * @throws  IOException
-     *          If an I/O error occurs
      */
-    public abstract void drop() throws IOException;
+    public abstract void drop();
 
     /**
      * Block multicast datagrams from the given source address.
@@ -140,10 +136,8 @@
      * @throws  IllegalStateException
      *          If the given source address is not currently blocked or the
      *          membership key is no longer valid
-     * @throws  IOException
-     *          If an I/O error occurs
      */
-    public abstract MembershipKey unblock(InetAddress source) throws IOException;
+    public abstract MembershipKey unblock(InetAddress source);
 
     /**
      * Returns the channel for which this membership key was created. This
@@ -152,7 +146,7 @@
      *
      * @return  the channel
      */
-    public abstract MulticastChannel getChannel();
+    public abstract MulticastChannel channel();
 
     /**
      * Returns the multicast group for which this membership key was created.
@@ -161,7 +155,7 @@
      *
      * @return  the multicast group
      */
-    public abstract InetAddress getGroup();
+    public abstract InetAddress group();
 
     /**
      * Returns the network interface for which this membership key was created.
@@ -170,7 +164,7 @@
      *
      * @return  the network interface
      */
-    public abstract NetworkInterface getNetworkInterface();
+    public abstract NetworkInterface networkInterface();
 
     /**
      * Returns the source address if this membership key is source-specific,
@@ -179,5 +173,5 @@
      * @return  The source address if this membership key is source-specific,
      *          otherwise {@code null}
      */
-    public abstract InetAddress getSourceAddress();
+    public abstract InetAddress sourceAddress();
 }
--- a/jdk/src/share/classes/java/nio/channels/MulticastChannel.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/nio/channels/MulticastChannel.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -123,6 +123,22 @@
     extends NetworkChannel
 {
     /**
+     * Closes this channel.
+     *
+     * <p> If the channel is a member of a multicast group then the membership
+     * is {@link MembershipKey#drop dropped}. Upon return, the {@link
+     * MembershipKey membership-key} will be {@link MembershipKey#isValid
+     * invalid}.
+     *
+     * <p> This method otherwise behaves exactly as specified by the {@link
+     * Channel} interface.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    @Override void close() throws IOException;
+
+    /**
      * Joins a multicast group to begin receiving all datagrams sent to the group,
      * returning a membership key.
      *
@@ -130,7 +146,7 @@
      * interface to receive all datagrams then the membership key, representing
      * that membership, is returned. Otherwise this channel joins the group and
      * the resulting new membership key is returned. The resulting membership key
-     * is not {@link MembershipKey#getSourceAddress source-specific}.
+     * is not {@link MembershipKey#sourceAddress source-specific}.
      *
      * <p> A multicast channel may join several multicast groups, including
      * the same group on more than one interface. An implementation may impose a
@@ -150,6 +166,8 @@
      * @throws  IllegalStateException
      *          If the channel already has source-specific membership of the
      *          group on the interface
+     * @throws  UnsupportedOperationException
+     *          If the channel's socket is not an Internet Protocol socket
      * @throws  ClosedChannelException
      *          If this channel is closed
      * @throws  IOException
@@ -170,7 +188,7 @@
      * interface to receive datagrams from the given source address then the
      * membership key, representing that membership, is returned. Otherwise this
      * channel joins the group and the resulting new membership key is returned.
-     * The resulting membership key is {@link MembershipKey#getSourceAddress
+     * The resulting membership key is {@link MembershipKey#sourceAddress
      * source-specific}.
      *
      * <p> Membership is <em>cumulative</em> and this method may be invoked
@@ -196,7 +214,8 @@
      *          If the channel is currently a member of the group on the given
      *          interface to receive all datagrams
      * @throws  UnsupportedOperationException
-     *          If the underlying operation system does not support source filtering
+     *          If the channel's socket is not an Internet Protocol socket or
+     *          source filtering is not supported
      * @throws  ClosedChannelException
      *          If this channel is closed
      * @throws  IOException
--- a/jdk/src/share/classes/java/nio/channels/NetworkChannel.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/nio/channels/NetworkChannel.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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
@@ -95,9 +95,10 @@
      * java.net.InetSocketAddress}.
      *
      * @return  The socket address that the socket is bound to, or {@code null}
-     *          if the channel is not {@link #isOpen open} or the channel's socket
-     *          is not bound
+     *          if the channel's socket is not bound
      *
+     * @throws  ClosedChannelException
+     *          If the channel is closed
      * @throws  IOException
      *          If an I/O error occurs
      */
@@ -114,9 +115,10 @@
      *
      * @return  This channel
      *
+     * @throws  UnsupportedOperationException
+     *          If the socket option is not supported by this channel
      * @throws  IllegalArgumentException
-     *          If the socket option is not supported by this channel, or
-     *          the value is not a valid value for this socket option
+     *          If the value is not a valid value for this socket option
      * @throws  ClosedChannelException
      *          If this channel is closed
      * @throws  IOException
@@ -135,7 +137,7 @@
      * @return  The value of the socket option. A value of {@code null} may be
      *          a valid value for some socket options.
      *
-     * @throws  IllegalArgumentException
+     * @throws  UnsupportedOperationException
      *          If the socket option is not supported by this channel
      * @throws  ClosedChannelException
      *          If this channel is closed
@@ -154,5 +156,5 @@
      *
      * @return  A set of the socket options supported by this channel
      */
-    Set<SocketOption<?>> options();
+    Set<SocketOption<?>> supportedOptions();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/SeekableByteChannel.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.channels;
+
+import java.nio.ByteBuffer;
+import java.io.IOException;
+
+/**
+ * A byte channel that maintains a current <i>position</i> and allows the
+ * position to be changed.
+ *
+ * <p> A seekable byte channel is connected to an entity, typically a file,
+ * that contains a variable-length sequence of bytes that can be read and
+ * written. The current position can be {@link #position() <i>queried</i>} and
+ * {@link #position(long) <i>modified</i>}. The channel also provides access to
+ * the current <i>size</i> of the entity to which the channel is connected. The
+ * size increases when bytes are written beyond its current size; the size
+ * decreases when it is {@link #truncate <i>truncated</i>}.
+ *
+ * <p> The {@link #position(long) position} and {@link #truncate truncate} methods
+ * which do not otherwise have a value to return are specified to return the
+ * channel upon which they are invoked. This allows method invocations to be
+ * chained. Implementations of this interface should specialize the return type
+ * so that method invocations on the implementation class can be chained.
+ *
+ * @since 1.7
+ * @see java.nio.file.FileRef#newByteChannel
+ */
+
+public interface SeekableByteChannel
+    extends ByteChannel
+{
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer.
+     *
+     * <p> Bytes are read starting at this channel's current position, and
+     * then the position is updated with the number of bytes actually read.
+     * Otherwise this method behaves exactly as specified in the {@link
+     * ReadableByteChannel} interface.
+     */
+    @Override
+    int read(ByteBuffer dst) throws IOException;
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer.
+     *
+     * <p> Bytes are written starting at this channel's current position, unless
+     * the channel is connected to an entity such as a file that is opened with
+     * the {@link java.nio.file.StandardOpenOption#APPEND APPEND} option, in
+     * which case the position is first advanced to the end. The entity to which
+     * the channel is connected is grown, if necessary, to accommodate the
+     * written bytes, and then the position is updated with the number of bytes
+     * actually written. Otherwise this method behaves exactly as specified by
+     * the {@link WritableByteChannel} interface.
+     */
+    @Override
+    int write(ByteBuffer src) throws IOException;
+
+    /**
+     * Returns this channel's position.
+     *
+     * @return  This channel's position,
+     *          a non-negative integer counting the number of bytes
+     *          from the beginning of the entity to the current position
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    long position() throws IOException;
+
+    /**
+     * Sets this channel's position.
+     *
+     * <p> Setting the position to a value that is greater than the current size
+     * is legal but does not change the size of the entity.  A later attempt to
+     * read bytes at such a position will immediately return an end-of-file
+     * indication.  A later attempt to write bytes at such a position will cause
+     * the entity to grow to accommodate the new bytes; the values of any bytes
+     * between the previous end-of-file and the newly-written bytes are
+     * unspecified.
+     *
+     * <p> Setting the channel's position is not recommended when connected to
+     * an entity, typically a file, that is opened with the {@link
+     * java.nio.file.StandardOpenOption#APPEND APPEND} option. When opened for
+     * append, the position is first advanced to the end before writing.
+     *
+     * @param  newPosition
+     *         The new position, a non-negative integer counting
+     *         the number of bytes from the beginning of the entity
+     *
+     * @return  This channel
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IllegalArgumentException
+     *          If the new position is negative
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    SeekableByteChannel position(long newPosition) throws IOException;
+
+    /**
+     * Returns the current size of entity to which this channel is connected.
+     *
+     * @return  The current size, measured in bytes
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    long size() throws IOException;
+
+    /**
+     * Truncates the entity, to which this channel is connected, to the given
+     * size.
+     *
+     * <p> If the given size is less than the current size then the entity is
+     * truncated, discarding any bytes beyond the new end. If the given size is
+     * greater than or equal to the current size then the entity is not modified.
+     * In either case, if the current position is greater than the given size
+     * then it is set to that size.
+     *
+     * <p> An implementation of this interface may prohibit truncation when
+     * connected to an entity, typically a file, opened with the {@link
+     * java.nio.file.StandardOpenOption#APPEND APPEND} option.
+     *
+     * @param  size
+     *         The new size, a non-negative byte count
+     *
+     * @return  This channel
+     *
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IllegalArgumentException
+     *          If the new size is negative
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    SeekableByteChannel truncate(long size) throws IOException;
+}
--- a/jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -29,7 +29,8 @@
 import java.net.ServerSocket;
 import java.net.SocketOption;
 import java.net.SocketAddress;
-import java.nio.channels.spi.*;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.SelectorProvider;
 
 /**
  * A selectable channel for stream-oriented listening sockets.
@@ -195,6 +196,7 @@
         throws IOException;
 
     /**
+     * @throws  UnsupportedOperationException           {@inheritDoc}
      * @throws  IllegalArgumentException                {@inheritDoc}
      * @throws  ClosedChannelException                  {@inheritDoc}
      * @throws  IOException                             {@inheritDoc}
--- a/jdk/src/share/classes/java/nio/channels/SocketChannel.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/nio/channels/SocketChannel.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -30,7 +30,8 @@
 import java.net.SocketOption;
 import java.net.SocketAddress;
 import java.nio.ByteBuffer;
-import java.nio.channels.spi.*;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.SelectorProvider;
 
 /**
  * A selectable channel for stream-oriented connecting sockets.
@@ -212,7 +213,7 @@
 
     /**
      * @throws  ConnectionPendingException
-     *          If a non-blocking connection operation is already in progress on
+     *          If a non-blocking connect operation is already in progress on
      *          this channel
      * @throws  AlreadyBoundException               {@inheritDoc}
      * @throws  UnsupportedAddressTypeException     {@inheritDoc}
@@ -226,6 +227,7 @@
         throws IOException;
 
     /**
+     * @throws  UnsupportedOperationException           {@inheritDoc}
      * @throws  IllegalArgumentException                {@inheritDoc}
      * @throws  ClosedChannelException                  {@inheritDoc}
      * @throws  IOException                             {@inheritDoc}
@@ -432,15 +434,17 @@
      * socket address then the return value from this method is of type {@link
      * java.net.InetSocketAddress}.
      *
-     * @return  The remote address; {@code null} if the channel is not {@link
-     *          #isOpen open} or the channel's socket is not connected
+     * @return  The remote address; {@code null} if the channel's socket is not
+     *          connected
      *
+     * @throws  ClosedChannelException
+     *          If the channel is closed
      * @throws  IOException
      *          If an I/O error occurs
      *
      * @since 1.7
      */
-    public abstract SocketAddress getConnectedAddress() throws IOException;
+    public abstract SocketAddress getRemoteAddress() throws IOException;
 
     // -- ByteChannel operations --
 
--- a/jdk/src/share/classes/java/nio/channels/exceptions	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/nio/channels/exceptions	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -150,6 +150,21 @@
 
 SINCE=1.7
 
+SUPER=java.io.IOException
+
+gen InterruptedByTimeoutException "
+ * Checked exception received by a thread when a timeout elapses before an
+ * asynchronous operation completes." \
+ -4268008601014042947L
+
+SUPER=IllegalArgumentException
+
+gen IllegalChannelGroupException "
+ * Unchecked exception thrown when an attempt is made to open a channel
+ * in a group that was not created by the same provider. " \
+ -2495041211157744253L
+
+
 SUPER=IllegalStateException
 
 gen AlreadyBoundException "
@@ -157,3 +172,23 @@
  * network oriented channel that is already bound." \
  6796072983322737592L
 
+gen AcceptPendingException "
+ * Unchecked exception thrown when an attempt is made to initiate an accept
+ * operation on a channel and a previous accept operation has not completed." \
+ 2721339977965416421L
+
+gen ReadPendingException "
+ * Unchecked exception thrown when an attempt is made to read from an
+ * asynchronous socket channel and a previous read has not completed." \
+ 1986315242191227217L
+
+gen WritePendingException "
+ * Unchecked exception thrown when an attempt is made to write to an
+ * asynchronous socket channel and a previous write has not completed." \
+ 7031871839266032276L
+
+gen ShutdownChannelGroupException "
+ * Unchecked exception thrown when an attempt is made to construct a channel in 
+ * a group that is shutdown or the completion handler for an I/O operation 
+ * cannot be invoked because the channel group is shutdown." \
+ -3903801676350154157L
--- a/jdk/src/share/classes/java/nio/channels/package-info.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/nio/channels/package-info.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2001-2009 Sun Microsystems, Inc.  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
@@ -46,6 +46,10 @@
  *     <td>Can read/write to/from a&nbsp;buffer</td></tr>
  * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.SeekableByteChannel}</i></tt></td>
  *     <td>A {@code ByteChannel} connected to an entity that contains a variable-length sequence of bytes</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.AsynchronousChannel}</i></tt></td>
+ *     <td>Supports asynchronous I/O operations.</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.AsynchronousByteChannel}</i></tt></td>
+ *     <td>Can read and write bytes asynchronously</td></tr>
  * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.NetworkChannel}</i></tt></td>
  *     <td>A channel to a network socket</td></tr>
  * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.MulticastChannel}</i></tt></td>
@@ -218,12 +222,70 @@
  * directly; custom channel classes should extend the appropriate {@link
  * java.nio.channels.SelectableChannel} subclasses defined in this package.
  *
+ * <a name="async"></a>
+ *
+ * <blockquote><table cellspacing=1 cellpadding=0 summary="Lists asynchronous channels and their descriptions">
+ * <tr><th><p align="left">Asynchronous I/O</p></th><th><p align="left">Description</p></th></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousFileChannel}</tt></td>
+ *     <td>An asynchronous channel for reading, writing, and manipulating a file</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousSocketChannel}</tt></td>
+ *     <td>An asynchronous channel to a stream-oriented connecting socket</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousServerSocketChannel}&nbsp;&nbsp;</tt></td>
+ *     <td>An asynchronous channel to a stream-oriented listening socket</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousDatagramChannel}</tt></td>
+ *     <td>An asynchronous channel to a datagram-oriented socket</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.CompletionHandler}</tt></td>
+ *     <td>A handler for consuming the result of an asynchronous operation</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousChannelGroup}</tt></td>
+ *     <td>A grouping of asynchronous channels for the purpose of resource sharing</td></tr>
+ * </table></blockquote>
+ *
+ * <p> {@link java.nio.channels.AsynchronousChannel Asynchronous channels} are a
+ * special type of channel capable of asynchronous I/O operations. Asynchronous
+ * channels are non-blocking and define methods to initiate asynchronous
+ * operations, returning a {@link java.util.concurrent.Future} representing the
+ * pending result of each operation. The {@code Future} can be used to poll or
+ * wait for the result of the operation. Asynchronous I/O operations can also
+ * specify a {@link java.nio.channels.CompletionHandler} to invoke when the
+ * operation completes. A completion handler is user provided code that is executed
+ * to consume the result of I/O operation.
+ *
+ * <p> This package defines asynchronous-channel classes that are connected to
+ * a stream-oriented connecting or listening socket, or a datagram-oriented socket.
+ * It also defines the {@link java.nio.channels.AsynchronousFileChannel} class
+ * for asynchronous reading, writing, and manipulating a file. As with the {@link
+ * java.nio.channels.FileChannel} it supports operations to truncate the file
+ * to a specific size, force updates to the file to be written to the storage
+ * device, or acquire locks on the whole file or on a specific region of the file.
+ * Unlike the {@code FileChannel} it does not define methods for mapping a
+ * region of the file directly into memory. Where memory mapped I/O is required,
+ * then a {@code FileChannel} can be used.
+ *
+ * <p> Asynchronous channels are bound to an asynchronous channel group for the
+ * purpose of resource sharing. A group has an associated {@link
+ * java.util.concurrent.ExecutorService} to which tasks are submitted to handle
+ * I/O events and dispatch to completion handlers that consume the result of
+ * asynchronous operations performed on channels in the group. The group can
+ * optionally be specified when creating the channel or the channel can be bound
+ * to a <em>default group</em>. Sophisticated users may wish to create their
+ * own asynchronous channel groups or configure the {@code ExecutorService}
+ * that will be used for the default group.
+ *
+ * <p> As with selectors, the implementatin of asynchronous channels can be
+ * replaced by "plugging in" an alternative definition or instance of the {@link
+ * java.nio.channels.spi.AsynchronousChannelProvider} class defined in the
+ * <tt>{@link java.nio.channels.spi}</tt> package.  It is not expected that many
+ * developers will actually make use of this facility; it is provided primarily
+ * so that sophisticated users can take advantage of operating-system-specific
+ * asynchronous I/O mechanisms when very high performance is required.
+ *
  * <hr width="80%">
  * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
  * or method in any class or interface in this package will cause a {@link
  * java.lang.NullPointerException NullPointerException} to be thrown.
  *
  * @since 1.4
+ * @updated 1.7
  * @author Mark Reinhold
  * @author JSR-51 Expert Group
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.channels.spi;
+
+import java.nio.channels.*;
+import java.net.ProtocolFamily;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import java.util.ServiceConfigurationError;
+import java.util.concurrent.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Service-provider class for asynchronous channels.
+ *
+ * <p> An asynchronous channel provider is a concrete subclass of this class that
+ * has a zero-argument constructor and implements the abstract methods specified
+ * below.  A given invocation of the Java virtual machine maintains a single
+ * system-wide default provider instance, which is returned by the {@link
+ * #provider() provider} method.  The first invocation of that method will locate
+ * the default provider as specified below.
+ *
+ * <p> All of the methods in this class are safe for use by multiple concurrent
+ * threads.  </p>
+ *
+ * @since 1.7
+ */
+
+public abstract class AsynchronousChannelProvider {
+    private static Void checkPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(new RuntimePermission("asynchronousChannelProvider"));
+        return null;
+    }
+    private AsynchronousChannelProvider(Void ignore) { }
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     *          {@link RuntimePermission}<tt>("asynchronousChannelProvider")</tt>
+     */
+    protected AsynchronousChannelProvider() {
+        this(checkPermission());
+    }
+
+    // lazy initialization of default provider
+    private static class ProviderHolder {
+        static final AsynchronousChannelProvider provider = load();
+
+        private static AsynchronousChannelProvider load() {
+            return AccessController
+                .doPrivileged(new PrivilegedAction<AsynchronousChannelProvider>() {
+                    public AsynchronousChannelProvider run() {
+                        AsynchronousChannelProvider p;
+                        p = loadProviderFromProperty();
+                        if (p != null)
+                            return p;
+                        p = loadProviderAsService();
+                        if (p != null)
+                            return p;
+                        return sun.nio.ch.DefaultAsynchronousChannelProvider.create();
+                    }});
+        }
+
+        private static AsynchronousChannelProvider loadProviderFromProperty() {
+            String cn = System.getProperty("java.nio.channels.spi.AsynchronousChannelProvider");
+            if (cn == null)
+                return null;
+            try {
+                Class<?> c = Class.forName(cn, true,
+                                           ClassLoader.getSystemClassLoader());
+                return (AsynchronousChannelProvider)c.newInstance();
+            } catch (ClassNotFoundException x) {
+                throw new ServiceConfigurationError(null, x);
+            } catch (IllegalAccessException x) {
+                throw new ServiceConfigurationError(null, x);
+            } catch (InstantiationException x) {
+                throw new ServiceConfigurationError(null, x);
+            } catch (SecurityException x) {
+                throw new ServiceConfigurationError(null, x);
+            }
+        }
+
+        private static AsynchronousChannelProvider loadProviderAsService() {
+            ServiceLoader<AsynchronousChannelProvider> sl =
+                ServiceLoader.load(AsynchronousChannelProvider.class,
+                                   ClassLoader.getSystemClassLoader());
+            Iterator<AsynchronousChannelProvider> i = sl.iterator();
+            for (;;) {
+                try {
+                    return (i.hasNext()) ? i.next() : null;
+                } catch (ServiceConfigurationError sce) {
+                    if (sce.getCause() instanceof SecurityException) {
+                        // Ignore the security exception, try the next provider
+                        continue;
+                    }
+                    throw sce;
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the system-wide default asynchronous channel provider for this
+     * invocation of the Java virtual machine.
+     *
+     * <p> The first invocation of this method locates the default provider
+     * object as follows: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> If the system property
+     *   <tt>java.nio.channels.spi.AsynchronousChannelProvider</tt> is defined
+     *   then it is taken to be the fully-qualified name of a concrete provider class.
+     *   The class is loaded and instantiated; if this process fails then an
+     *   unspecified error is thrown.  </p></li>
+     *
+     *   <li><p> If a provider class has been installed in a jar file that is
+     *   visible to the system class loader, and that jar file contains a
+     *   provider-configuration file named
+     *   <tt>java.nio.channels.spi.AsynchronousChannelProvider</tt> in the resource
+     *   directory <tt>META-INF/services</tt>, then the first class name
+     *   specified in that file is taken.  The class is loaded and
+     *   instantiated; if this process fails then an unspecified error is
+     *   thrown.  </p></li>
+     *
+     *   <li><p> Finally, if no provider has been specified by any of the above
+     *   means then the system-default provider class is instantiated and the
+     *   result is returned.  </p></li>
+     *
+     * </ol>
+     *
+     * <p> Subsequent invocations of this method return the provider that was
+     * returned by the first invocation.  </p>
+     *
+     * @return  The system-wide default AsynchronousChannel provider
+     */
+    public static AsynchronousChannelProvider provider() {
+        return ProviderHolder.provider;
+    }
+
+    /**
+     * Constructs a new asynchronous channel group with a fixed thread pool.
+     *
+     * @param   nThreads
+     *          The number of threads in the pool
+     * @param   threadFactory
+     *          The factory to use when creating new threads
+     *
+     * @throws  IllegalArgumentException
+     *          If {@code nThreads <= 0}
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see AsynchronousChannelGroup#withFixedThreadPool
+     */
+    public abstract AsynchronousChannelGroup
+        openAsynchronousChannelGroup(int nThreads, ThreadFactory threadFactory) throws IOException;
+
+    /**
+     * Constructs a new asynchronous channel group with the given thread pool.
+     *
+     * @param   executor
+     *          The thread pool
+     * @param   initialSize
+     *          A value {@code >=0} or a negative value for implementation
+     *          specific default
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see AsynchronousChannelGroup#withCachedThreadPool
+     */
+    public abstract AsynchronousChannelGroup
+        openAsynchronousChannelGroup(ExecutorService executor, int initialSize) throws IOException;
+
+    /**
+     * Opens an asynchronous server-socket channel.
+     *
+     * @param   group
+     *          The group to which the channel is bound, or {@code null} to
+     *          bind to the default group
+     *
+     * @return  The new channel
+     *
+     * @throws  IllegalChannelGroupException
+     *          If the provider that created the group differs from this provider
+     * @throws  ShutdownChannelGroupException
+     *          The group is shutdown
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract AsynchronousServerSocketChannel openAsynchronousServerSocketChannel
+        (AsynchronousChannelGroup group) throws IOException;
+
+    /**
+     * Opens an asynchronous socket channel.
+     *
+     * @param   group
+     *          The group to which the channel is bound, or {@code null} to
+     *          bind to the default group
+     *
+     * @return  The new channel
+     *
+     * @throws  IllegalChannelGroupException
+     *          If the provider that created the group differs from this provider
+     * @throws  ShutdownChannelGroupException
+     *          The group is shutdown
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract AsynchronousSocketChannel openAsynchronousSocketChannel
+        (AsynchronousChannelGroup group) throws IOException;
+
+    /**
+     * Opens an asynchronous datagram channel.
+     *
+     * @param   family
+     *          The protocol family, or {@code null} for the default protocol
+     *          family
+     * @param   group
+     *          The group to which the channel is bound, or {@code null} to
+     *          bind to the default group
+     *
+     * @return  The new channel
+     *
+     * @throws  IllegalChannelGroupException
+     *          If the provider that created the group differs from this provider
+     * @throws  ShutdownChannelGroupException
+     *          The group is shutdown
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract AsynchronousDatagramChannel openAsynchronousDatagramChannel
+        (ProtocolFamily family, AsynchronousChannelGroup group) throws IOException;
+}
--- a/jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -89,8 +89,8 @@
         if (cn == null)
             return false;
         try {
-            Class c = Class.forName(cn, true,
-                                    ClassLoader.getSystemClassLoader());
+            Class<?> c = Class.forName(cn, true,
+                                       ClassLoader.getSystemClassLoader());
             provider = (SelectorProvider)c.newInstance();
             return true;
         } catch (ClassNotFoundException x) {
--- a/jdk/src/share/classes/java/nio/channels/spi/package.html	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/nio/channels/spi/package.html	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 <!--
- Copyright 2000-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -29,8 +29,8 @@
 
 Service-provider classes for the <tt>{@link java.nio.channels}</tt> package.
 
-<p> Only developers who are defining new selector providers should need to make
-direct use of this package.  </p>
+<p> Only developers who are defining new selector providers or asynchronous
+channel providers should need to make direct use of this package.  </p>
 
 <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
 or method in any class or interface in this package will cause a {@link
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/AccessDeniedException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when a file system operation is denied, typically
+ * due to a file permission or other access check.
+ *
+ * <p> This exception is not related to the {@link
+ * java.security.AccessControlException AccessControlException} or {@link
+ * SecurityException} thrown by access controllers or security managers when
+ * access to a file is denied.
+ *
+ * @since 1.7
+ */
+
+public class AccessDeniedException
+    extends FileSystemException
+{
+    private static final long serialVersionUID = 4943049599949219617L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          A string identifying the file or {@code null} if not known.
+     */
+    public AccessDeniedException(String file) {
+        super(file);
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          A string identifying the file or {@code null} if not known.
+     * @param   other
+     *          A string identifying the other file or {@code null} if not known.
+     * @param   reason
+     *          A reason message with additional information or {@code null}
+     */
+    public AccessDeniedException(String file, String other, String reason) {
+        super(file, other, reason);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/AccessMode.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Defines access modes used to test the accessibility of a file.
+ *
+ * @since 1.7
+ *
+ * @see FileRef#checkAccess
+ */
+
+public enum AccessMode {
+    /**
+     * Test read access.
+     */
+    READ,
+    /**
+     * Test write access.
+     */
+    WRITE,
+    /**
+     * Test execute access.
+     */
+    EXECUTE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/AtomicMoveNotSupportedException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when a file cannot be moved as an atomic file system
+ * operation.
+ *
+ * @since 1.7
+ */
+
+public class AtomicMoveNotSupportedException
+    extends FileSystemException
+{
+    static final long serialVersionUID = 5402760225333135579L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   source
+     *          A string identifying the source file or {@code null} if not known.
+     * @param   target
+     *          A string identifying the target file or {@code null} if not known.
+     * @param   reason
+     *          A reason message with additional information
+     */
+    public AtomicMoveNotSupportedException(String source,
+                                           String target,
+                                           String reason)
+    {
+        super(source, target, reason);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/ClosedDirectoryStreamException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Unchecked exception thrown when an attempt is made to invoke an operation on
+ * a directory stream that is closed.
+ *
+ * @since 1.7
+ */
+
+public class ClosedDirectoryStreamException
+    extends IllegalStateException
+{
+    static final long serialVersionUID = 4228386650900895400L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ClosedDirectoryStreamException() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/ClosedFileSystemException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Unchecked exception thrown when an attempt is made to invoke an operation on
+ * a file and the file system is closed.
+ */
+
+public class ClosedFileSystemException
+    extends IllegalStateException
+{
+    static final long serialVersionUID = -8158336077256193488L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ClosedFileSystemException() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/ClosedWatchServiceException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Unchecked exception thrown when an attempt is made to invoke an operation on
+ * a watch service that is closed.
+ */
+
+public class ClosedWatchServiceException
+    extends IllegalStateException
+{
+    static final long serialVersionUID = 1853336266231677732L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ClosedWatchServiceException() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/CopyOption.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * An object that configures how to copy or move a file.
+ *
+ * <p> 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.
+ *
+ * <p> The {@link StandardCopyOption} enumeration type defines the
+ * <i>standard</i> options.
+ *
+ * @since 1.7
+ */
+
+public interface CopyOption {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/DirectoryNotEmptyException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when a file system operation fails because a
+ * directory is not empty.
+ *
+ * @since 1.7
+ */
+
+public class DirectoryNotEmptyException
+    extends FileSystemException
+{
+    static final long serialVersionUID = 3056667871802779003L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   dir
+     *          A string identifying the directory or {@code null} if not known.
+     */
+    public DirectoryNotEmptyException(String dir) {
+        super(dir);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/DirectoryStream.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.util.Iterator;
+import java.io.Closeable;
+
+/**
+ * An object to iterate over the entries in a directory. A directory stream
+ * allows for convenient use of the for-each construct:
+ * <pre>
+ *   Path dir = ...
+ *   DirectoryStream&lt;Path&gt; stream = dir.newDirectoryStream();
+ *   try {
+ *       for (Path entry: stream) {
+ *         ..
+ *       }
+ *   } finally {
+ *       stream.close();
+ *   }
+ * </pre>
+ *
+ * <p><b> A {@code DirectoryStream} is not a general-purpose {@code Iterable}.
+ * While this interface extends {@code Iterable}, the {@code iterator} method
+ * may only be invoked once to obtain the iterator; a second, or subsequent,
+ * call to the {@code iterator} method throws {@code IllegalStateException}. </b>
+ *
+ * <p> A {@code DirectoryStream} is opened upon creation and is closed by
+ * invoking the {@link #close close} method. Closing the directory stream
+ * releases any resources associated with the stream. The {@link
+ * Files#withDirectory Files.withDirectory} utility method is useful for cases
+ * where a task is performed on entries in a directory. This method automatically
+ * closes the directory stream when iteration is complete (or an error occurs).
+ * Once a directory stream is closed, all further method invocations on the
+ * iterator throw {@link java.util.concurrent.ConcurrentModificationException}
+ * with cause {@link ClosedDirectoryStreamException}.
+ *
+ * <p> A directory stream is not required to be <i>asynchronously closeable</i>.
+ * If a thread is blocked on the directory stream's iterator, reading from the
+ * directory, and another thread invokes the {@code close} method then it may
+ * require to block until the read operation is complete.
+ *
+ * <p> The {@link Iterator#hasNext() hasNext} and {@link Iterator#next() next}
+ * methods can encounter an I/O error when iterating over the directory in which
+ * case {@code ConcurrentModificationException} is thrown with cause
+ * {@link java.io.IOException}. The {@code hasNext} method is guaranteed to
+ * read-ahead by at least one element. This means that if the {@code hasNext}
+ * method returns {@code true} and is followed by a call to the {@code next}
+ * method then it is guaranteed not to fail with a {@code
+ * ConcurrentModificationException}.
+ *
+ * <p> The elements returned by the iterator are in no specific order. Some file
+ * systems maintain special links to the directory itself and the directory's
+ * parent directory. Entries representing these links are not returned by the
+ * iterator.
+ *
+ * <p> The iterator's {@link Iterator#remove() remove} method removes the
+ * directory entry for the last element returned by the iterator, as if by
+ * invoking the {@link FileRef#delete delete} method. If an I/O error or
+ * security exception occurs then {@code ConcurrentModificationException} is
+ * thrown with the cause.
+ *
+ * <p> The iterator is <i>weakly consistent</i>. It is thread safe but does not
+ * freeze the directory while iterating, so it may (or may not) reflect updates
+ * to the directory that occur after the {@code DirectoryStream} is created.
+ *
+ * @param   <T>     The type of element returned by the iterator
+ *
+ * @since 1.7
+ *
+ * @see Path#newDirectoryStream
+ */
+
+public interface DirectoryStream<T>
+    extends Closeable, Iterable<T>
+{
+    /**
+     * 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.
+     *
+     * <p> The {@link DirectoryStreamFilters} class defines factory methods to
+     * create filters for a number of common usages and also methods to combine
+     * filters.
+     *
+     * @param   <T>     The type of the directory entry
+     *
+     * @since 1.7
+     */
+    public static interface Filter<T> {
+        /**
+         * Decides if the given directory entry should be accepted or filtered.
+         *
+         * @param   entry
+         *          The directory entry to be tested
+         *
+         * @return  {@code true} if the directory entry should be accepted
+         */
+        boolean accept(T entry);
+    }
+
+    /**
+     * Returns the iterator associated with this {@code DirectoryStream}.
+     *
+     * @return  The iterator associated with this {@code DirectoryStream}
+     *
+     * @throws  IllegalStateException
+     *          If this directory stream is closed or the iterator has already
+     *          been returned
+     */
+    @Override
+    Iterator<T> iterator();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/DirectoryStreamFilters.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.io.IOException;
+import java.io.IOError;
+import sun.nio.fs.MimeType;
+
+/**
+ * This class consists exclusively of static methods that construct or combine
+ * filters.
+ *
+ * @since 1.7
+ */
+
+public final class DirectoryStreamFilters {
+    private DirectoryStreamFilters() { }
+
+    /**
+     * Constructs a directory stream filter that filters directory entries by
+     * their  <a href="http://www.ietf.org/rfc/rfc2045.txt">MIME</a> content
+     * type. The directory stream filter's {@link
+     * java.nio.file.DirectoryStream.Filter#accept accept} method returns {@code
+     * true} if the content type of the directory entry can be determined by
+     * invoking the {@link Files#probeContentType probeContentType} method, and
+     * the content type matches the given content type.
+     *
+     * <p> The {@code type} parameter is the value of a Multipurpose Internet
+     * Mail Extension (MIME) content type as defined by <a
+     * href="http://www.ietf.org/rfc/rfc2045.txt"><i>RFC&nbsp;2045: Multipurpose
+     * Internet Mail Extensions (MIME) Part One: Format of Internet Message
+     * Bodies</i></a>. It is parsable according to the grammar in the RFC. Any
+     * space characters (<code>'&#92;u0020'</code>) surrounding its components are
+     * ignored. The {@code type} parameter is parsed into its primary and subtype
+     * components which are used to match the primary and subtype components of
+     * each directory entry's content type. Parameters are not allowed. The
+     * primary type matches if it has value {@code '*'} or is equal to the
+     * primary type of the directory entry's content type without regard to
+     * case. The subtype matches if has the value {@code '*'} or is equal to the
+     * subtype of the directory entry's content type without regard to case. If
+     * both the primary and subtype match then the filter's {@code accept} method
+     * returns {@code true}. If the content type of a directory entry cannot be
+     * determined then the entry is filtered.
+     *
+     * <p> The {@code accept} method of the resulting directory stream filter
+     * throws {@link IOError} if the probing of the content type fails by
+     * throwing an {@link IOException}. Security exceptions are also propogated
+     * to the caller of the {@code accept} method.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we require to list only the HTML files in a directory.
+     * <pre>
+     *     DirectoryStream.Filter&lt;FileRef&gt; filter =
+     *         DirectoryStreamFilters.newContentTypeFilter("text/html");
+     * </pre>
+     *
+     * @param   type
+     *          The content type
+     *
+     * @return  A new directory stream filter
+     *
+     * @throws  IllegalArgumentException
+     *          If the {@code type} parameter cannot be parsed as a MIME type
+     *          or it has parameters
+     */
+    public static <T extends FileRef> DirectoryStream.Filter<T>
+        newContentTypeFilter(String type)
+    {
+        final MimeType matchType = MimeType.parse(type);
+        if (matchType.hasParameters())
+            throw new IllegalArgumentException("Parameters not allowed");
+        return new DirectoryStream.Filter<T>() {
+            @Override
+            public boolean accept(T entry) {
+                String fileType;
+                try {
+                    fileType = Files.probeContentType(entry);
+                } catch (IOException x) {
+                    throw new IOError(x);
+                }
+                if (fileType != null) {
+                    return matchType.match(fileType);
+                }
+                return false;
+            }
+        };
+    }
+
+    /**
+     * Returns a directory stream filter that {@link DirectoryStream.Filter#accept
+     * accepts} a directory entry if the entry is accepted by all of the given
+     * filters.
+     *
+     * <p> This method returns a filter that invokes, in iterator order, the
+     * {@code accept} method of each of the filters. If {@code false} is returned
+     * by any of the filters then the directory entry is filtered. If the
+     * directory entry is not filtered then the resulting filter accepts the
+     * entry. If the iterator returns zero elements then the resulting filter
+     * accepts all directory entries.
+     *
+     * <p> <b>Usage Example:</b>
+     * <pre>
+     *     List&lt;DirectoryStream.Filter&lt;? super Path&gt;&gt; filters = ...
+     *     DirectoryStream.Filter&lt;Path&gt; filter = DirectoryStreamFilters.allOf(filters);
+     * </pre>
+     *
+     * @param   filters
+     *          The sequence of filters
+     *
+     * @return  The resulting filter
+     */
+    public static <T> DirectoryStream.Filter<T>
+        allOf(final Iterable<? extends DirectoryStream.Filter<? super T>> filters)
+    {
+        if (filters == null)
+            throw new NullPointerException("'filters' is null");
+        return new DirectoryStream.Filter<T>() {
+            @Override
+            public boolean accept(T entry) {
+                for (DirectoryStream.Filter<? super T> filter: filters) {
+                    if (!filter.accept(entry))
+                        return false;
+                }
+                return true;
+            }
+        };
+    }
+
+    /**
+     * Returns a directory stream filter that {@link DirectoryStream.Filter#accept
+     * accepts} a directory entry if the entry is accepted by one or more of
+     * the given filters.
+     *
+     * <p> This method returns a filter that invokes, in iteration order, the
+     * {@code accept} method of each of filter. If {@code true} is returned by
+     * any of the filters then the directory entry is accepted. If none of the
+     * filters accepts the directory entry then it is filtered. If the iterator
+     * returns zero elements then the resulting filter filters all directory
+     * entries.
+     *
+     * @param   filters
+     *          The sequence of filters
+     *
+     * @return  The resulting filter
+     */
+    public static <T> DirectoryStream.Filter<T>
+        anyOf(final Iterable<? extends DirectoryStream.Filter<? super T>> filters)
+    {
+        if (filters == null)
+            throw new NullPointerException("'filters' is null");
+        return new DirectoryStream.Filter<T>() {
+            @Override
+            public boolean accept(T entry) {
+                for (DirectoryStream.Filter<? super T> filter: filters) {
+                    if (filter.accept(entry))
+                        return true;
+                }
+                return false;
+            }
+        };
+    }
+
+    /**
+     * Returns a directory stream filter that is the <em>complement</em> of the
+     * given filter. The resulting filter {@link
+     * java.nio.file.DirectoryStream.Filter#accept accepts} a directory entry
+     * if filtered by the given filter, and filters any entries that are accepted
+     * by the given filter.
+     *
+     * @param   filter
+     *          The given filter
+     *
+     * @return  The resulting filter that is the complement of the given filter
+     */
+    public static <T> DirectoryStream.Filter<T>
+        complementOf(final DirectoryStream.Filter<T> filter)
+    {
+        if (filter == null)
+            throw new NullPointerException("'filter' is null");
+        return new DirectoryStream.Filter<T>() {
+            @Override
+            public boolean accept(T entry) {
+                return !filter.accept(entry);
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/FileAction.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.io.IOException;
+
+/**
+ * An interface that is implemented by objects that operate on a file. An
+ * implementation of this interface is provided to the {@link Files#withDirectory
+ * withDirectory} utility method so that the file action is {@link #invoke
+ * invoked} for all accepted entries in the directory, after which, the directory
+ * is automatically closed.
+ *
+ * <p> <b>Usage Example:</b>
+ * Suppose we require to perform a task on all class files in a directory:
+ * <pre>
+ *     Path dir = ...
+ *     Files.withDirectory(dir, "*.class", new FileAction&lt;Path&gt;() {
+ *         public void invoke(Path entry) {
+ *             :
+ *         }
+ *     });
+ * </pre>
+ *
+ * @param   <T>     The type of file reference
+ *
+ * @since 1.7
+ */
+
+public interface FileAction<T extends FileRef> {
+    /**
+     * Invoked for a file.
+     *
+     * @param   file
+     *          The file
+     *
+     * @throws  IOException
+     *          If the block terminates due an uncaught I/O exception
+     */
+    void invoke(T file) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/FileAlreadyExistsException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when an attempt is made to create a file or
+ * directory and a file of that name already exists.
+ *
+ * @since 1.7
+ */
+
+public class FileAlreadyExistsException
+    extends FileSystemException
+{
+    static final long serialVersionUID = 7579540934498831181L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          A string identifying the file or {@code null} if not known.
+     */
+    public FileAlreadyExistsException(String file) {
+        super(file);
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          A string identifying the file or {@code null} if not known.
+     * @param   other
+     *          A string identifying the other file or {@code null} if not known.
+     * @param   reason
+     *          A reason message with additional information or {@code null}
+     */
+    public FileAlreadyExistsException(String file, String other, String reason) {
+        super(file, other, reason);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/FileRef.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,424 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.attribute.*;
+import java.nio.channels.SeekableByteChannel;
+import java.io.IOException;
+
+/**
+ * A reference to a file.
+ *
+ * <p> A {@code FileRef} is an object that locates a file and defines methods to
+ * access the file. The means by which the file is located depends on the
+ * implementation. In many cases, a file is located by a {@link Path} but it may
+ * be located by other means such as a file-system identifier.
+ *
+ * <p> This interface defines the following operations:
+ * <ul>
+ *   <li><p> The {@link #newByteChannel newByteChannel} method
+ *     may be used to open a file and obtain a byte channel for reading or
+ *     writing. </p></li>
+ *   <li><p> The {@link #delete delete} method may be used to delete a file.
+ *     </p></li>
+ *   <li><p> The {@link #checkAccess checkAccess} method may be used to check
+ *     the existence or accessibility of a file. </p></li>
+ *   <li><p> The {@link #isSameFile isSameFile} method may be used to test if
+ *     two file references locate the same file. </p></li>
+ *   <li><p> The {@link #getFileStore getFileStore} method may be used to
+ *     obtain the {@link FileStore} representing the storage where a file is
+ *     located. </p></li>
+ * </ul>
+ *
+ * <p> Access to associated metadata or file attributes requires an appropriate
+ * {@link FileAttributeView FileAttributeView}. The {@link
+ * #getFileAttributeView(Class,LinkOption[]) getFileAttributeView(Class,LinkOption[])}
+ * method may be used to obtain a file attribute view that defines type-safe
+ * methods to read or update file attributes. The {@link
+ * #getFileAttributeView(String,LinkOption[]) getFileAttributeView(String,LinkOption[])}
+ * method may be used to obtain a file attribute view where dynamic access to
+ * file attributes where required.
+ *
+ * <p> A {@code FileRef} is immutable and safe for use by multiple concurrent
+ * threads.
+ *
+ * @since 1.7
+ */
+
+public interface FileRef {
+
+    /**
+     * Opens the file referenced by this object, returning a seekable byte
+     * channel to access the file.
+     *
+     * <p> 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.
+     *
+     * <p> In the addition to {@code READ} and {@code WRITE}, the following
+     * options may be present:
+     *
+     * <table border=1 cellpadding=5 summary="">
+     * <tr> <th>Option</th> <th>Description</th> </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#APPEND APPEND} </td>
+     *   <td> 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. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} </td>
+     *   <td> 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. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#SYNC SYNC} </td>
+     *   <td> Requires that every update to the file's content or metadata be
+     *   written synchronously to the underlying storage device. (see <a
+     *   href="package-summary.html#integrity"> Synchronized I/O file
+     *   integrity</a>). </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#DSYNC DSYNC} </td>
+     *   <td> Requires that every update to the file's content be written
+     *   synchronously to the underlying storage device. (see <a
+     *   href="package-summary.html#integrity"> Synchronized I/O file
+     *   integrity</a>). </td>
+     * </tr>
+     * </table>
+     *
+     * <p> An implementation of this interface may support additional options
+     * defined by the {@link StandardOpenOption} enumeration type or other
+     * implementation specific options.
+     *
+     * <p> The {@link java.nio.channels.Channels} utility classes defines methods
+     * to construct input and output streams where inter-operation with the
+     * {@link java.io} package is required.
+     *
+     * @param   options
+     *          Options specifying how the file is opened
+     *
+     * @return  a new seekable byte channel
+     *
+     * @throws  IllegalArgumentException
+     *          If an invalid combination of options is specified
+     * @throws  UnsupportedOperationException
+     *          If an unsupported open 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 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.
+     */
+    SeekableByteChannel newByteChannel(OpenOption... options)
+        throws IOException;
+
+    /**
+     * Returns the {@link FileStore} representing the file store where the file
+     * referenced by this object is stored.
+     *
+     * <p> 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}<tt>
+     *          ("getFileStoreAttributes")</tt>
+     */
+    FileStore getFileStore() throws IOException;
+
+    /**
+     * Checks the existence and optionally the accessibility of the file
+     * referenced by this object.
+     *
+     * <p> 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:
+     *
+     * <table border=1 cellpadding=5 summary="">
+     * <tr> <th>Value</th> <th>Description</th> </tr>
+     * <tr>
+     *   <td> {@link AccessMode#READ READ} </td>
+     *   <td> Checks that the file exists and that the Java virtual machine has
+     *     permission to read the file. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link AccessMode#WRITE WRITE} </td>
+     *   <td> Checks that the file exists and that the Java virtual machine has
+     *     permission to write to the file, </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link AccessMode#EXECUTE EXECUTE} </td>
+     *   <td> 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. </td>
+     * </tr>
+     * </table>
+     *
+     * <p> If the {@code modes} parameter is of length zero, then the existence
+     * of the file is checked.
+     *
+     * <p> 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 <i>(optional specific exception)</i>
+     * @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. <i>(optional specific exception)</i>
+     * @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.
+     */
+    void checkAccess(AccessMode... modes) throws IOException;
+
+    /**
+     * Returns a file attribute view of a given type.
+     *
+     * <p> 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.
+     *
+     * <p> 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 extends FileAttributeView> V getFileAttributeView(Class<V> type, LinkOption... options);
+
+    /**
+     * Returns a file attribute view of the given name.
+     *
+     * <p> 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
+     * <em>dynamic access</em> to the file attributes is required. The {@code
+     * name} parameter specifies the {@link FileAttributeView#name name} of the
+     * file attribute view and this method returns an instance of that view if
+     * supported. The {@link BasicFileAttributeView} type supports access to the
+     * basic attributes of a file and is name {@code "basic"}. Invoking this
+     * method to select a file attribute view named {@code "basic"} will always
+     * return an instance of that class.
+     *
+     * <p> 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   name
+     *          The name of the file attribute view
+     * @param   options
+     *          Options indicating how symbolic links are handled
+     *
+     * @return  A file attribute view of the given name, or {@code null} if
+     *          the attribute view 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.
+     */
+    FileAttributeView getFileAttributeView(String name, LinkOption... options);
+
+    /**
+     * Tests if the file referenced by this object is the same file referenced
+     * by another object.
+     *
+     * <p> If this {@code FileRef} and the given {@code FileRef} are {@link
+     * #equals(Object) equal} then this method returns {@code true} without checking
+     * if the file exists. If the {@code FileRef} and the given {@code FileRef}
+     * are associated with different providers, or the given {@code FileRef} is
+     * {@code null} then this method returns {@code false}. Otherwise, this method
+     * checks if both {@code FileRefs} locate the same file, and depending on the
+     * implementation, may require to open or access both files.
+     *
+     * <p> If the file system and files remain static, then this method implements
+     * an equivalence relation for non-null {@code FileRefs}.
+     * <ul>
+     * <li>It is <i>reflexive</i>: for a non-null {@code FileRef} {@code f},
+     *     {@code f.isSameFile(f)} should return {@code true}.
+     * <li>It is <i>symmetric</i>: for two non-null {@code FileRefs}
+     *     {@code f} and {@code g}, {@code f.isSameFile(g)} will equal
+     *     {@code g.isSameFile(f)}.
+     * <li>It is <i>transitive</i>: for three {@code FileRefs}
+     *     {@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}.
+     * </ul>
+     *
+     * @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
+     */
+    boolean isSameFile(FileRef other) throws IOException;
+
+    /**
+     * Deletes the file referenced by this object.
+     *
+     * <p> 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
+     * link is deleted and not the final target of the link.
+     *
+     * <p> 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.
+     *
+     * <p> 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 <i>(optional specific exception)</i>
+     * @throws  DirectoryNotEmptyException
+     *          If the file is a directory and could not otherwise be deleted
+     *          because the directory is not empty <i>(optional specific
+     *          exception)</i>
+     * @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
+     */
+    void delete() throws IOException;
+
+    /**
+     * Tests this object for equality with another object.
+     *
+     * <p> If the given object is not a {@code FileRef} then this method
+     * immediately returns {@code false}.
+     *
+     * <p> For two file references to be considered equal requires that they
+     * are both the same type of {@code FileRef} and encapsulate components
+     * to locate the same file. This method does not access the file system and
+     * the file may not exist.
+     *
+     * <p> This method satisfies the general contract of the {@link
+     * java.lang.Object#equals(Object) Object.equals} method. </p>
+     *
+     * @param   ob   The object to which this object is to be compared
+     *
+     * @return  {@code true} if, and only if, the given object is a {@code FileRef}
+     *          that is identical to this {@code FileRef}
+     *
+     * @see #isSameFile
+     */
+    boolean equals(Object ob);
+
+    /**
+     * Returns the hash-code value for this object.
+     *
+     * <p> This method satisfies the general contract of the
+     * {@link java.lang.Object#hashCode() Object.hashCode} method.
+     */
+    int hashCode();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/FileStore.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.attribute.*;
+
+/**
+ * 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 FileRef#getFileStore getFileStore} method, or all file
+ * stores can be enumerated by invoking the {@link FileSystem#getFileStores
+ * getFileStores} method.
+ *
+ * <p> 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
+ */
+
+public abstract class FileStore {
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected FileStore() {
+    }
+
+    /**
+     * Returns the name of this file store. The format of the name is highly
+     * implementation specific. It will typically be the name of the storage
+     * pool or volume.
+     *
+     * <p> The string returned by this method may differ from the string
+     * returned by the {@link Object#toString() toString} method.
+     *
+     * @return  The name of this file store
+     */
+    public abstract String name();
+
+    /**
+     * Returns the <em>type</em> of this file store. The format of the string
+     * returned by this method is highly implementation specific. It may
+     * indicate, for example, the format used or if the file store is local
+     * or remote.
+     *
+     * @return  A string representing the type of this file store
+     */
+    public abstract String type();
+
+    /**
+     * Tells whether this file store is read-only. A file store is read-only if
+     * it does not support write operations or other changes to files. Any
+     * attempt to create a file, open an existing file for writing etc. causes
+     * an {@code IOException} to be thrown.
+     *
+     * @return  {@code true} if, and only if, this file store is read-only
+     */
+    public abstract boolean isReadOnly();
+
+    /**
+     * Tells whether or not this file store supports the file attributes
+     * identified by the given file attribute view.
+     *
+     * <p> Invoking this method to test if the file store supports {@link
+     * BasicFileAttributeView} will always return {@code true}. In the case of
+     * the default provider, this method cannot guarantee to give the correct
+     * result when the file store is not a local storage device. The reasons for
+     * this are implementation specific and therefore unspecified.
+     *
+     * @param   type
+     *          The file attribute view type
+     *
+     * @return  {@code true} if, and only if, the file attribute view is
+     *          supported
+     */
+    public abstract boolean supportsFileAttributeView(Class<? extends FileAttributeView> type);
+
+    /**
+     * Tells whether or not this file store supports the file attributes
+     * identified by the given file attribute view.
+     *
+     * <p> Invoking this method to test if the file store supports {@link
+     * BasicFileAttributeView}, identified by the name "{@code basic}" will
+     * always return {@code true}. In the case of the default provider, this
+     * method cannot guarantee to give the correct result when the file store is
+     * not a local storage device. The reasons for this are implementation
+     * specific and therefore unspecified.
+     *
+     * @param   name
+     *          The {@link FileAttributeView#name name} of file attribute view
+     *
+     * @return  {@code true} if, and only if, the file attribute view is
+     *          supported
+     */
+    public abstract boolean supportsFileAttributeView(String name);
+
+    /**
+     * Returns a {@code FileStoreAttributeView} of the given type.
+     *
+     * <p> This method is intended to be used where the file store attribute
+     * view defines type-safe methods to read or update the file store attributes.
+     * The {@code type} parameter is the type of the attribute view required and
+     * the method returns an instance of that type if supported.
+     *
+     * <p> 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
+     *
+     * @return  A file store attribute view of the specified type or
+     *          {@code null} if the attribute view is not available
+     */
+    public abstract <V extends FileStoreAttributeView> V
+        getFileStoreAttributeView(Class<V> type);
+
+    /**
+     * Returns a {@code FileStoreAttributeView} of the given name.
+     *
+     * <p> This method is intended to be used where <em>dynamic access</em> to
+     * file store attributes is required. The {@code name} parameter specifies
+     * the {@link FileAttributeView#name name} of the file store attribute view
+     * and this method returns an instance of that view if supported.
+     *
+     * <p> 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 "space"} will always return an instance
+     * of that class.
+     *
+     * @param   name
+     *          The name of the attribute view
+     *
+     * @return  A file store attribute view of the given name, or {@code null}
+     *          if the attribute view is not available
+     */
+    public abstract FileStoreAttributeView getFileStoreAttributeView(String name);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/FileSystem.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,453 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.attribute.*;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.Set;
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * Provides an interface to a file system and is the factory for objects to
+ * access files and other objects in the file system.
+ *
+ * <p> 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.
+ *
+ * <p> A file system is the factory for several types of objects:
+ *
+ * <ul>
+ *   <li><p> The {@link #getPath getPath} method converts a system dependent
+ *     <em>path string</em>, returning a {@link Path} object that may be used
+ *     to locate and access a file. </p></li>
+ *   <li><p> The {@link #getPathMatcher  getPathMatcher} method is used
+ *     to create a {@link PathMatcher} that performs match operations on
+ *     paths. </p></li>
+ *   <li><p> The {@link #getFileStores getFileStores} method returns an iterator
+ *     over the underlying {@link FileStore file-stores}. </p></li>
+ *   <li><p> The {@link #getUserPrincipalLookupService getUserPrincipalLookupService}
+ *     method returns the {@link UserPrincipalLookupService} to lookup users or
+ *     groups by name. </p></li>
+ *   <li><p> The {@link #newWatchService newWatchService} method creates a
+ *     {@link WatchService} that may be used to watch objects for changes and
+ *     events. </p></li>
+ * </ul>
+ *
+ * <p> File systems vary greatly. In some cases the file system is a single
+ * hierarchy of files with one top-level root directory. In other cases it may
+ * have several distinct file hierarchies, each with its own top-level root
+ * directory. The {@link #getRootDirectories getRootDirectories} method may be
+ * used to iterate over the root directories in the file system. A file system
+ * is typically composed of one or more underlying {@link FileStore file-stores}
+ * that provide the storage for the files. Theses file stores can also vary in
+ * the features they support, and the file attributes or <em>meta-data</em> that
+ * they associate with files.
+ *
+ * <p> A file system is open upon creation and can be closed by invoking its
+ * {@link #close() close} method. Once closed, any further attempt to access
+ * objects in the file system cause {@link ClosedFileSystemException} to be
+ * thrown. File systems created by the default {@link FileSystemProvider provider}
+ * cannot be closed.
+ *
+ * <p> A {@code FileSystem} can provide read-only or read-write access to the
+ * file system. Whether or not a file system provides read-only access is
+ * established when the {@code FileSystem} is created and can be tested by invoking
+ * its {@link #isReadOnly() isReadOnly} method. Attempts to write to file stores
+ * by means of an object associated with a read-only file system throws {@link
+ * ReadOnlyFileSystemException}.
+ *
+ * <p> File systems are safe for use by multiple concurrent threads. The {@link
+ * #close close} method may be invoked at any time to close a file system but
+ * whether a file system is <i>asynchronously closeable</i> is provider specific
+ * and therefore unspecified. In other words, if a thread is accessing an
+ * object in a file system, and another thread invokes the {@code close} method
+ * then it may require to block until the first operation is complete. Closing
+ * a file system causes all open channels, watch services, and other {@link
+ * Closeable closeable} objects associated with the file system to be closed.
+ *
+ * @since 1.7
+ */
+
+public abstract class FileSystem
+    implements Closeable
+{
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected FileSystem() {
+    }
+
+    /**
+     * Returns the provider that created this file system.
+     *
+     * @return  The provider that created this file system.
+     */
+    public abstract FileSystemProvider provider();
+
+    /**
+     * Closes this file system.
+     *
+     * <p> After a file system is closed then all subsequent access to the file
+     * system, either by methods defined by this class or on objects associated
+     * with this file system, throw {@link ClosedFileSystemException}. If the
+     * file system is already closed then invoking this method has no effect.
+     *
+     * <p> Closing a file system will close all open {@link
+     * java.nio.channels.Channel channels}, {@link DirectoryStream directory-streams},
+     * {@link WatchService watch-service}, and other closeable objects associated
+     * with this file system. The {@link FileSystems#getDefault default} file
+     * system cannot be closed.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  UnsupportedOperationException
+     *          Thrown in the case of the default file system
+     */
+    @Override
+    public abstract void close() throws IOException;
+
+    /**
+     * Tells whether or not this file system is open.
+     *
+     * <p> File systems created by the default provider are always open.
+     *
+     * @return  {@code true} if, and only if, this file system is open
+     */
+    public abstract boolean isOpen();
+
+    /**
+     * Tells whether or not this file system allows only read-only access to
+     * its file stores.
+     *
+     * @return  {@code true} if, and only if, this file system provides
+     *          read-only access
+     */
+    public abstract boolean isReadOnly();
+
+    /**
+     * Returns the name separator, represented as a string.
+     *
+     * <p> The name separator is used to separate names in a path string. An
+     * implementation may support multiple name separators in which case this
+     * method returns an implementation specific <em>default</em> name separator.
+     * This separator is used when creating path strings by invoking the {@link
+     * Path#toString() toString()} method.
+     *
+     * <p> In the case of the default provider, this method returns the same
+     * separator as {@link java.io.File#separator}.
+     *
+     * @return  The name separator
+     */
+    public abstract String getSeparator();
+
+    /**
+     * Returns an object to iterate over the paths of the root directories.
+     *
+     * <p> A file system provides access to a file store that may be composed
+     * of a number of distinct file hierarchies, each with its own top-level
+     * root directory. Unless denied by the security manager, each element in
+     * the returned iterator corresponds to the root directory of a distinct
+     * file hierarchy. The order of the elements is not defined. The file
+     * hierarchies may change during the lifetime of the Java virtual machine.
+     * For example, in some implementations, the insertion of removable media
+     * may result in the creation of a new file hierarchy with its own
+     * top-level directory.
+     *
+     * <p> When a security manager is installed, it is invoked to check access
+     * to the each root directory. If denied, the root directory is not returned
+     * by the iterator. In the case of the default provider, the {@link
+     * SecurityManager#checkRead(String)} method is invoked to check read access
+     * to each root directory. It is system dependent if the permission checks
+     * are done when the iterator is obtained or during iteration.
+     *
+     * @return  An object to iterate over the root directories
+     */
+    public abstract Iterable<Path> getRootDirectories();
+
+    /**
+     * Returns an object to iterate over the underlying file stores.
+     *
+     * <p> The elements of the returned iterator are the {@link
+     * FileStore FileStores} for this file system. The order of the elements is
+     * not defined and the file stores may change during the lifetime of the
+     * Java virtual machine. When an I/O error occurs, perhaps because a file
+     * store is not accessible, then it is not returned by the iterator.
+     *
+     * <p> In the case of the default provider, and a security manager is
+     * installed, the security manager is invoked to check {@link
+     * RuntimePermission}<tt>("getFileStoreAttributes")</tt>. If denied, then
+     * no file stores are returned by the iterator. In addition, the security
+     * manager's {@link SecurityManager#checkRead(String)} method is invoked to
+     * check read access to the file store's <em>top-most</em> directory. If
+     * denied, the file store is not returned by the iterator. It is system
+     * dependent if the permission checks are done when the iterator is obtained
+     * or during iteration.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to print the space usage for all file stores:
+     * <pre>
+     *     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;
+     *         System.out.format("%-20s %12d %12d %12d%n", store, total, used, avail);
+     *     }
+     * </pre>
+     *
+     * @return  An object to iterate over the backing file stores
+     */
+    public abstract Iterable<FileStore> getFileStores();
+
+    /**
+     * Returns the set of the {@link FileAttributeView#name names} of the file
+     * attribute views supported by this {@code FileSystem}.
+     *
+     * <p> The {@link BasicFileAttributeView} is required to be supported and
+     * therefore the set contains at least one element, "basic".
+     *
+     * <p> The {@link FileStore#supportsFileAttributeView(String)
+     * supportsFileAttributeView(String)} method may be used to test if an
+     * underlying {@link FileStore} supports the file attributes identified by a
+     * file attribute view.
+     *
+     * @return  An unmodifiable set of the names of the supported file attribute
+     *          views
+     */
+    public abstract Set<String> supportedFileAttributeViews();
+
+    /**
+     * Converts a path string to a {@code Path}.
+     *
+     * <p> The parsing and conversion to a path object is inherently
+     * implementation dependent. In the simplest case, the path string is rejected,
+     * and {@link InvalidPathException} thrown, if the path string contains
+     * characters that cannot be converted to characters that are <em>legal</em>
+     * to the file store. For example, on UNIX systems, the NUL (&#92;u0000)
+     * character is not allowed to be present in a path. An implementation may
+     * choose to reject path strings that contain names that are longer than those
+     * allowed by any file store, and where an implementation supports a complex
+     * path syntax, it may choose to reject path strings that are <em>badly
+     * formed</em>.
+     *
+     * <p> In the case of the default provider, path strings are parsed based
+     * on the definition of paths at the platform or virtual file system level.
+     * For example, an operating system may not allow specific characters to be
+     * present in a file name, but a specific underlying file store may impose
+     * different or additional restrictions on the set of legal
+     * characters.
+     *
+     * <p> This method throws {@link InvalidPathException} when the path string
+     * cannot be converted to a path. Where possible, and where applicable,
+     * the exception is created with an {@link InvalidPathException#getIndex
+     * index} value indicating the first position in the {@code path} parameter
+     * that caused the path string to be rejected.
+     *
+     * <p> Invoking this method with an empty path string throws
+     * {@code InvalidPathException}.
+     *
+     * @param   path
+     *          The path string
+     *
+     * @return  A {@code Path} object
+     *
+     * @throws  InvalidPathException
+     *          If the path string cannot be converted
+     */
+    public abstract Path getPath(String path);
+
+    /**
+     * Returns a {@code PathMatcher} that performs match operations on the
+     * {@code String} representation of {@link Path} objects by interpreting a
+     * given pattern.
+     *
+     * The {@code syntaxAndPattern} parameter identifies the syntax and the
+     * pattern and takes the form:
+     * <blockquote>
+     * <i>syntax</i><b>:</b><i>pattern</i>
+     * </blockquote>
+     * where {@code ':'} stands for itself.
+     *
+     * <p> A {@code FileSystem} implementation supports the "{@code glob}" and
+     * "{@code regex}" syntaxes, and may support others. The value of the syntax
+     * component is compared without regard to case.
+     *
+     * <p> When the syntax is "{@code glob}" then the {@code String}
+     * representation of the path is matched using a limited pattern language
+     * that resembles regular expressions but with a simpler syntax. For example:
+     *
+     * <blockquote>
+     * <table border="0">
+     * <tr>
+     *   <td>{@code *.java}</td>
+     *   <td>Matches a path that represents a file name ending in {@code .java}</td>
+     * </tr>
+     * <tr>
+     *   <td>{@code *.*}</td>
+     *   <td>Matches file names containing a dot</td>
+     * </tr>
+     * <tr>
+     * <tr>
+     *   <td>{@code *.{java,class}}</td>
+     *   <td>Matches file names ending with {@code .java} or {@code .class}</td>
+     * </tr>
+     * <tr>
+     *   <td>{@code foo.?}</td>
+     *   <td>Matches file names starting with {@code foo.} and a single
+     *   character extension</td>
+     * </tr>
+     * <tr>
+     *   <td><tt>&#47;home&#47;*&#47;*</tt>
+     *   <td>Matches <tt>&#47;home&#47;gus&#47;data</tt> on UNIX platforms</td>
+     * </tr>
+     * <tr>
+     *   <td><tt>&#47;home&#47;**</tt>
+     *   <td>Matches <tt>&#47;home&#47;gus</tt> and
+     *   <tt>&#47;home&#47;gus&#47;data</tt> on UNIX platforms</td>
+     * </tr>
+     * <tr>
+     *   <td><tt>C:&#92;&#92;*</tt>
+     *   <td>Matches <tt>C:&#92;foo</tt> and <tt>C:&#92;bar</tt> on the Windows
+     *   platform (note that the backslash is escaped; as a string literal in the
+     *   Java Language the pattern would be <tt>"C:&#92;&#92;&#92;&#92*"</tt>) </td>
+     * </tr>
+     *
+     * </table>
+     * </blockquote>
+     *
+     * <p> The following rules are used to interpret glob patterns:
+     *
+     * <p> <ul>
+     *   <li><p> The {@code *} character matches zero or more {@link Character
+     *   characters} of a {@link Path#getName(int) name} component without
+     *   crossing directory boundaries. </p></li>
+     *
+     *   <li><p> The {@code **} characters matches zero or more {@link Character
+     *   characters} crossing directory boundaries. </p></li>
+     *
+     *   <li><p> The {@code ?} character matches exactly one character of a
+     *   name component.</p></li>
+     *
+     *   <li><p> The backslash character ({@code \}) is used to escape characters
+     *   that would otherwise be interpreted as special characters. The expression
+     *   {@code \\} matches a single backslash and "\{" matches a left brace
+     *   for example.  </p></li>
+     *
+     *   <li><p> The {@code [ ]} characters are a <i>bracket expression</i> that
+     *   match a single character of a name component out of a set of characters.
+     *   For example, {@code [abc]} matches {@code "a"}, {@code "b"}, or {@code "c"}.
+     *   The hyphen ({@code -}) may be used to specify a range so {@code [a-z]}
+     *   specifies a range that matches from {@code "a"} to {@code "z"} (inclusive).
+     *   These forms can be mixed so [abce-g] matches {@code "a"}, {@code "b"},
+     *   {@code "c"}, {@code "e"}, {@code "f"} or {@code "g"}. If the character
+     *   after the {@code [} is a {@code !} then it is used for negation so {@code
+     *   [!a-c]} matches any character except {@code "a"}, {@code "b"}, or {@code
+     *   "c"}.
+     *   <p> Within a bracket expression the {@code *}, {@code ?} and {@code \}
+     *   characters match themselves. The ({@code -}) character matches itself if
+     *   it is the first character within the brackets, or the first character
+     *   after the {@code !} if negating.</p></li>
+     *
+     *   <li><p> The {@code { }} characters are a group of subpatterns, where
+     *   the group matches if any subpattern in the group matches. The {@code ","}
+     *   character is used to separate the subpatterns. Groups cannot be nested.
+     *   </p></li>
+     *
+     *   <li><p> All other characters match themselves in an implementation
+     *   dependent manner. This includes characters representing any {@link
+     *   FileSystem#getSeparator name-separators}. </p></li>
+     *
+     *   <li><p> The matching of {@link Path#getRoot root} components is highly
+     *   implementation-dependent and is not specified. </p></li>
+     *
+     * </ul>
+     *
+     * <p> When the syntax is "{@code regex}" then the pattern component is a
+     * regular expression as defined by the {@link java.util.regex.Pattern}
+     * class.
+     *
+     * <p>  For both the glob and regex syntaxes, the matching details, such as
+     * whether the matching is case sensitive, are implementation-dependent
+     * and therefore not specified.
+     *
+     * @param   syntaxAndPattern
+     *          The syntax and pattern
+     *
+     * @return  A path matcher that may be used to match paths against the pattern
+     *
+     * @throws  IllegalArgumentException
+     *          If the parameter does not take the form: {@code syntax:pattern}
+     * @throws  java.util.regex.PatternSyntaxException
+     *          If the pattern is invalid
+     * @throws  UnsupportedOperationException
+     *          If the pattern syntax is not known to the implementation
+     *
+     * @see Path#newDirectoryStream(String)
+     */
+    public abstract PathMatcher getPathMatcher(String syntaxAndPattern);
+
+    /**
+     * Returns the {@code UserPrincipalLookupService} for this file system
+     * <i>(optional operation)</i>. The resulting lookup service may be used to
+     * lookup user or group names.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to make "joe" the owner of a file:
+     * <pre>
+     *     Path file = ...
+     *     UserPrincipal joe = file.getFileSystem().getUserPrincipalLookupService()
+     *         .lookupPrincipalByName("joe");
+     *     Attributes.setOwner(file, joe);
+     * </pre>
+     *
+     * @throws  UnsupportedOperationException
+     *          If this {@code FileSystem} does not does have a lookup service
+     *
+     * @return  The {@code UserPrincipalLookupService} for this file system
+     */
+    public abstract UserPrincipalLookupService getUserPrincipalLookupService();
+
+    /**
+     * Constructs a new {@link WatchService} <i>(optional operation)</i>.
+     *
+     * <p> This method constructs a new watch service that may be used to watch
+     * registered objects for changes and events.
+     *
+     * @return  a new watch service
+     *
+     * @throws  UnsupportedOperationException
+     *          If this {@code FileSystem} does not support watching file system
+     *          objects for changes and events. This exception is not thrown
+     *          by {@code FileSystems} created by the default provider.
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract WatchService newWatchService() throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/FileSystemAlreadyExistsException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Runtime exception thrown when an attempt is made to create a file system that
+ * already exists.
+ */
+
+public class FileSystemAlreadyExistsException
+    extends RuntimeException
+{
+    static final long serialVersionUID = -5438419127181131148L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public FileSystemAlreadyExistsException() {
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   msg
+     *          The detail message
+     */
+    public FileSystemAlreadyExistsException(String msg) {
+        super(msg);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/FileSystemException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.io.IOException;
+
+/**
+ * Thrown when a file system operation fails on one or two files. This class is
+ * the general class for file system exceptions.
+ *
+ * @since 1.7
+ */
+
+public class FileSystemException
+    extends IOException
+{
+    static final long serialVersionUID = -3055425747967319812L;
+
+    private final String file;
+    private final String other;
+
+    /**
+     * Constructs an instance of this class. This constructor should be used
+     * when an operation involving one file fails and there isn't any additional
+     * information to explain the reason.
+     *
+     * @param   file
+     *          A string identifying the file or {@code null} if not known.
+     */
+    public FileSystemException(String file) {
+        super((String)null);
+        this.file = file;
+        this.other = null;
+    }
+
+    /**
+     * Constructs an instance of this class. This constructor should be used
+     * when an operation involving two files fails, or there is additional
+     * information to explain the reason.
+     *
+     * @param   file
+     *          A string identifying the file or {@code null} if not known.
+     * @param   other
+     *          A string identifying the other file or {@code null} if there
+     *          isn't another file or if not known
+     * @param   reason
+     *          A reason message with additional information or {@code null}
+     */
+    public FileSystemException(String file, String other, String reason) {
+        super(reason);
+        this.file = file;
+        this.other = other;
+    }
+
+    /**
+     * Returns the file used to create this exception.
+     *
+     * @return  The file (can be {@code null})
+     */
+    public String getFile() {
+        return file;
+    }
+
+    /**
+     * Returns the other file used to create this exception.
+     *
+     * @return  The other file (can be {@code null})
+     */
+    public String getOtherFile() {
+        return other;
+    }
+
+    /**
+     * Returns the string explaining why the file system operation failed.
+     *
+     * @return  The string explaining why the file system operation failed
+     */
+    public String getReason() {
+        return super.getMessage();
+    }
+
+    /**
+     * Returns the detail message string.
+     */
+    @Override
+    public String getMessage() {
+        if (file == null && other == null)
+            return getReason();
+        StringBuilder sb = new StringBuilder();
+        if (file != null)
+            sb.append(file);
+        if (other != null) {
+            sb.append(" -> ");
+            sb.append(other);
+        }
+        if (getReason() != null) {
+            sb.append(": ");
+            sb.append(getReason());
+        }
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/FileSystemNotFoundException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Runtime exception thrown when a file system cannot be found.
+ */
+
+public class FileSystemNotFoundException
+    extends RuntimeException
+{
+    static final long serialVersionUID = 7999581764446402397L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public FileSystemNotFoundException() {
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   msg
+     *          The detail message
+     */
+    public FileSystemNotFoundException(String msg) {
+        super(msg);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/FileSystems.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,413 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.spi.FileSystemProvider;
+import java.net.URI;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.*;
+import java.lang.reflect.Constructor;
+
+/**
+ * Factory methods for file systems. This class defines the {@link #getDefault
+ * getDefault} method to get the default file system and factory methods to
+ * construct other types of file systems.
+ *
+ * <p> The first invocation of any of the methods defined by this class causes
+ * the default {@link FileSystemProvider provider} to be loaded. The default
+ * provider, identified by the URI scheme "file", creates the {@link FileSystem}
+ * that provides access to the file systems accessible to the Java virtual
+ * machine. If the process of loading or initializing the default provider fails
+ * then an unspecified error is thrown.
+ *
+ * <p> The first invocation of the {@link FileSystemProvider#installedProviders
+ * installedProviders} method, by way of invoking any of the {@code
+ * newFileSystem} methods defined by this class, locates and loads all
+ * installed file system providers. Installed providers are loaded using the
+ * service-provider loading facility defined by the {@link ServiceLoader} class.
+ * Installed providers are loaded using the system class loader. If the
+ * system class loader cannot be found then the extension class loader is used;
+ * if there is no extension class loader then the bootstrap class loader is used.
+ * Providers 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.FileSystemProvider}
+ * in the resource directory {@code META-INF/services}, and the file lists one or
+ * more fully-qualified names of concrete subclass of {@link FileSystemProvider}
+ * that have a zero argument constructor.
+ * The ordering that installed providers are located is implementation specific.
+ * If a provider is instantiated and its {@link FileSystemProvider#getScheme()
+ * getScheme} returns the same URI scheme of a provider that was previously
+ * instantiated then the most recently instantiated duplicate is discarded. URI
+ * schemes are compared without regard to case. During construction a provider
+ * may safely access files associated with the default provider but care needs
+ * to be taken to avoid circular loading of other installed providers. If
+ * circular loading of installed providers is detected then an unspecified error
+ * is thrown.
+ *
+ * <p> This class also defines factory methods that allow a {@link ClassLoader}
+ * to be specified when locating a provider. As with installed providers, the
+ * provider classes are identified by placing the provider configuration file
+ * in the resource directory {@code META-INF/services}.
+ *
+ * <p> If a thread initiates the loading of the installed file system providers
+ * and another thread invokes a method that also attempts to load the providers
+ * then the method will block until the loading completes.
+ *
+ * @since 1.7
+ */
+
+public final class FileSystems {
+    private FileSystems() {
+    }
+
+    // lazy initialization of default file system
+    private static class DefaultFileSystemHolder {
+        static final FileSystem defaultFileSystem = defaultFileSystem();
+
+        // returns default file system
+        private static FileSystem defaultFileSystem() {
+            // load default provider
+            FileSystemProvider provider = AccessController
+                .doPrivileged(new PrivilegedAction<FileSystemProvider>() {
+                    public FileSystemProvider run() {
+                        return getDefaultProvider();
+                    }
+                });
+
+            // return file system
+            return provider.getFileSystem(URI.create("file:///"));
+        }
+
+        // returns default provider
+        private static FileSystemProvider getDefaultProvider() {
+            FileSystemProvider provider = sun.nio.fs.DefaultFileSystemProvider.create();
+
+            // if the property java.nio.file.spi.DefaultFileSystemProvider is
+            // set then its value is the name of the default provider (or a list)
+            String propValue = System
+                .getProperty("java.nio.file.spi.DefaultFileSystemProvider");
+            if (propValue != null) {
+                for (String cn: propValue.split(",")) {
+                    try {
+                        Class<?> c = Class
+                            .forName(cn, true, ClassLoader.getSystemClassLoader());
+                        Constructor<?> ctor = c
+                            .getDeclaredConstructor(FileSystemProvider.class);
+                        provider = (FileSystemProvider)ctor.newInstance(provider);
+
+                        // must be "file"
+                        if (!provider.getScheme().equals("file"))
+                            throw new Error("Default provider must use scheme 'file'");
+
+                    } catch (Exception x) {
+                        throw new Error(x);
+                    }
+                }
+            }
+            return provider;
+        }
+    }
+
+    /**
+     * Returns the default {@code FileSystem}. The default file system creates
+     * objects that provide access to the file systems accessible to the Java
+     * virtual machine. The <em>working directory</em> of the file system is
+     * the current user directory, named by the system property {@code user.dir}.
+     * This allows for interoperability with the {@link java.io.File java.io.File}
+     * class.
+     *
+     * <p> The first invocation of any of the methods defined by this class
+     * locates the default {@link FileSystemProvider provider} object. Where the
+     * system property {@code java.nio.file.spi.DefaultFileSystemProvider} is
+     * not defined then the default provider is a system-default provider that
+     * is invoked to create the default file system.
+     *
+     * <p> If the system property {@code java.nio.file.spi.DefaultFileSystemProvider}
+     * is defined then it is taken to be a list of one or more fully-qualified
+     * names of concrete provider classes identified by the URI scheme
+     * {@code "file"}. Where the property is a list of more than one name then
+     * the names are separated by a comma. Each class is loaded, using the system
+     * class loader, and instantiated by invoking a one argument constructor
+     * whose formal parameter type is {@code FileSystemProvider}. The providers
+     * are loaded and instantiated in the order they are listed in the property.
+     * If this process fails or a provider's scheme is not equal to {@code "file"}
+     * then an unspecified error is thrown. URI schemes are normally compared
+     * without regard to case but for the default provider, the scheme is
+     * required to be {@code "file"}. The first provider class is instantiated
+     * by invoking it with a reference to the system-default provider.
+     * The second provider class is instantiated by invoking it with a reference
+     * 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.
+     *
+     * <p> Subsequent invocations of this method return the file system that was
+     * returned by the first invocation.
+     *
+     * @return  the default file system
+     */
+    public static FileSystem getDefault() {
+        return DefaultFileSystemHolder.defaultFileSystem;
+    }
+
+    /**
+     * Returns a reference to an existing {@code FileSystem}.
+     *
+     * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
+     * installed} providers to locate the provider that is identified by the URI
+     * {@link URI#getScheme scheme} of the given URI. URI schemes are compared
+     * without regard to case. The exact form of the URI is highly provider
+     * dependent. If found, the provider's {@link FileSystemProvider#getFileSystem
+     * getFileSystem} method is invoked to obtain a reference to the {@code
+     * FileSystem}.
+     *
+     * <p> 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).
+     *
+     * <p> If a security manager is installed then a provider implementation
+     * may require to check a permission before returning a reference to an
+     * existing file system. In the case of the {@link FileSystems#getDefault
+     * default} file system, no permission check is required.
+     *
+     * @throws  IllegalArgumentException
+     *          If the pre-conditions for the {@code uri} parameter aren't met
+     * @throws  FileSystemNotFoundException
+     *          If the file system, identified by the URI, does not exist
+     * @throws  ProviderNotFoundException
+     *          If a provider supporting the URI scheme is not installed
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission.
+     */
+    public static FileSystem getFileSystem(URI uri) {
+        String scheme = uri.getScheme();
+        for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
+            if (scheme.equalsIgnoreCase(provider.getScheme())) {
+                return provider.getFileSystem(uri);
+            }
+        }
+        throw new ProviderNotFoundException("Provider \"" + scheme + "\" not found");
+    }
+
+    /**
+     * Constructs a new file system that is identified by a {@link URI}
+     *
+     * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
+     * installed} providers to locate the provider that is identified by the URI
+     * {@link URI#getScheme scheme} of the given URI. URI schemes are compared
+     * without regard to case. The exact form of the URI is highly provider
+     * dependent. If found, the provider's {@link FileSystemProvider#newFileSystem(URI,Map)
+     * newFileSystem(URI,Map)} method is invoked to construct the new file system.
+     *
+     * <p> 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.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose there is a provider identified by the scheme {@code "memory"}
+     * installed:
+     * <pre>
+     *   Map&lt;String,String&gt; env = new HashMap&lt;String,String&gt;();
+     *   env.put("capacity", "16G");
+     *   env.put("blockSize", "4k");
+     *   FileSystem fs = FileSystems.newFileSystem(URI.create("memory:///?name=logfs"), env);
+     * </pre>
+     *
+     * @param   uri
+     *          The URI identifying the file system
+     * @param   env
+     *          A map of provider specific properties to configure the file system;
+     *          may be empty
+     *
+     * @return  A new file system
+     *
+     * @throws  IllegalArgumentException
+     *          If the pre-conditions for the {@code uri} parameter aren't met,
+     *          or the {@code env} parameter does not contain properties required
+     *          by the provider, or a property value is invalid
+     * @throws  FileSystemAlreadyExistsException
+     *          If the file system has already been created
+     * @throws  ProviderNotFoundException
+     *          If a provider supporting the URI scheme is not installed
+     * @throws  IOException
+     *          An I/O error occurs creating the file system
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission required by the file system provider implementation
+     */
+    public static FileSystem newFileSystem(URI uri, Map<String,?> env)
+        throws IOException
+    {
+        return newFileSystem(uri, env, null);
+    }
+
+    /**
+     * Constructs a new file system that is identified by a {@link URI}
+     *
+     * <p> This method first attempts to locate an installed provider in exactly
+     * the same manner as the {@link #newFileSystem(URI,Map) newFileSystem(URI,Map)}
+     * method. If none of the installed providers support the URI scheme then an
+     * attempt is made to locate the provider using the given class loader. If a
+     * provider supporting the URI scheme is located then its {@link
+     * FileSystemProvider#newFileSystem(URI,Map) newFileSystem(URI,Map)} is
+     * invoked to construct the new file system.
+     *
+     * @param   uri
+     *          The URI identifying the file system
+     * @param   env
+     *          A map of provider specific properties to configure the file system;
+     *          may be empty
+     * @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 pre-conditions for the {@code uri} parameter aren't met,
+     *          or the {@code env} parameter does not contain properties required
+     *          by the provider, or a property value is invalid
+     * @throws  FileSystemAlreadyExistsException
+     *          If the URI scheme identifies an installed provider and the file
+     *          system has already been created
+     * @throws  ProviderNotFoundException
+     *          If a provider supporting the URI scheme is not found
+     * @throws  ServiceConfigurationError
+     *          When an error occurs while loading a service provider
+     * @throws  IOException
+     *          An I/O error occurs creating the file system
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission required by the file system provider implementation
+     */
+    public static FileSystem newFileSystem(URI uri, Map<String,?> env, ClassLoader loader)
+        throws IOException
+    {
+        String scheme = uri.getScheme();
+
+        // check installed providers
+        for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
+            if (scheme.equalsIgnoreCase(provider.getScheme())) {
+                return provider.newFileSystem(uri, env);
+            }
+        }
+
+        // if not found, use service-provider loading facility
+        if (loader != null) {
+            ServiceLoader<FileSystemProvider> sl = ServiceLoader
+                .load(FileSystemProvider.class, loader);
+            for (FileSystemProvider provider: sl) {
+                if (scheme.equalsIgnoreCase(provider.getScheme())) {
+                    return provider.newFileSystem(uri, env);
+                }
+            }
+        }
+
+        throw new ProviderNotFoundException("Provider \"" + scheme + "\" not found");
+    }
+
+    /**
+     * Constructs a new {@code FileSystem} to access the contents of a file as a
+     * file system.
+     *
+     * <p> 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.
+     *
+     * <p> 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.
+     *
+     * @param   file
+     *          A reference to a file
+     * @param   env
+     *          A map of provider specific properties to configure the file system;
+     *          may be empty
+     * @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
+     *          When an error occurs while loading a service provider
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission.
+     */
+    public static FileSystem newFileSystem(FileRef file,
+                                           Map<String,?> env,
+                                           ClassLoader loader)
+        throws IOException
+    {
+        if (file == null)
+            throw new NullPointerException();
+
+        // check installed providers
+        for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
+            try {
+                return provider.newFileSystem(file, env);
+            } catch (UnsupportedOperationException uoe) {
+            }
+        }
+
+        // if not found, use service-provider loading facility
+        if (loader != null) {
+            ServiceLoader<FileSystemProvider> sl = ServiceLoader
+                .load(FileSystemProvider.class, loader);
+            for (FileSystemProvider provider: sl) {
+                try {
+                    return provider.newFileSystem(file, env);
+                } catch (UnsupportedOperationException uoe) {
+                }
+            }
+        }
+
+        throw new ProviderNotFoundException("Provider not found");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/FileTreeWalker.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Simple file tree walker that works in a similar manner to nftw(3C).
+ *
+ * @see Files#walkFileTree
+ */
+
+class FileTreeWalker {
+    private final boolean followLinks;
+    private final boolean detectCycles;
+    private final LinkOption[] linkOptions;
+    private final FileVisitor<? super Path> visitor;
+
+    FileTreeWalker(Set<FileVisitOption> options, FileVisitor<? super Path> visitor) {
+        boolean fl = false;
+        boolean dc = false;
+        for (FileVisitOption option: options) {
+            switch (option) {
+                case FOLLOW_LINKS  : fl = true; break;
+                case DETECT_CYCLES : dc = true; break;
+                default:
+                    if (option == null)
+                        throw new NullPointerException("Visit options contains 'null'");
+                    throw new AssertionError("Should not get here");
+            }
+        }
+        this.followLinks = fl;
+        this.detectCycles = fl | dc;
+        this.linkOptions = (fl) ? new LinkOption[0] :
+            new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+        this.visitor = visitor;
+    }
+
+    /**
+     * Walk file tree starting at the given file
+     */
+    void walk(Path start, int maxDepth) {
+        FileVisitResult result = walk(start,
+                                      maxDepth,
+                                      new ArrayList<AncestorDirectory>());
+        if (result == null) {
+            throw new NullPointerException("Visitor returned 'null'");
+        }
+    }
+
+    /**
+     * @param   file
+     *          The directory to visit
+     * @param   path
+     *          list of directories that is relative path from starting file
+     * @param   depth
+     *          Depth remaining
+     * @param   ancestors
+     *          use when cycle detection is enabled
+     */
+    private FileVisitResult walk(Path file,
+                                 int depth,
+                                 List<AncestorDirectory> ancestors)
+    {
+        // depth check
+        if (depth-- < 0)
+            return FileVisitResult.CONTINUE;
+
+        BasicFileAttributes attrs = null;
+        IOException exc = null;
+
+        // attempt to get attributes of file. If fails and we are following
+        // links then a link target might not exist so get attributes of link
+        try {
+            try {
+                attrs = Attributes.readBasicFileAttributes(file, linkOptions);
+            } catch (IOException x1) {
+                if (followLinks) {
+                    try {
+                        attrs = Attributes
+                            .readBasicFileAttributes(file, LinkOption.NOFOLLOW_LINKS);
+                    } catch (IOException x2) {
+                        exc = x2;
+                    }
+                } else {
+                    exc = x1;
+                }
+            }
+        } catch (SecurityException x) {
+            return FileVisitResult.CONTINUE;
+        }
+
+        // unable to get attributes of file
+        if (exc != null) {
+            return visitor.visitFileFailed(file, exc);
+        }
+
+        // file is not a directory so invoke visitFile method
+        if (!attrs.isDirectory()) {
+            return visitor.visitFile(file, attrs);
+        }
+
+        // check for cycles
+        if (detectCycles) {
+            Object key = attrs.fileKey();
+
+            // if this directory and ancestor has a file key then we compare
+            // them; otherwise we use less efficient isSameFile test.
+            for (AncestorDirectory ancestor: ancestors) {
+                Object ancestorKey = ancestor.fileKey();
+                if (key != null && ancestorKey != null) {
+                    if (key.equals(ancestorKey)) {
+                        // cycle detected
+                        return visitor.visitFile(file, attrs);
+                    }
+                } else {
+                    try {
+                        if (file.isSameFile(ancestor.file())) {
+                            // cycle detected
+                            return visitor.visitFile(file, attrs);
+                        }
+                    } catch (IOException x) {
+                        // ignore
+                    } catch (SecurityException x) {
+                        // ignore
+                    }
+                }
+            }
+
+            ancestors.add(new AncestorDirectory(file, key));
+        }
+
+        // visit directory
+        try {
+            DirectoryStream<Path> stream = null;
+            FileVisitResult result;
+
+            // open the directory
+            try {
+                stream = file.newDirectoryStream();
+            } catch (IOException x) {
+                return visitor.preVisitDirectoryFailed(file, x);
+            } catch (SecurityException x) {
+                // ignore, as per spec
+                return FileVisitResult.CONTINUE;
+            }
+
+            // the exception notified to the postVisitDirectory method
+            IOException ioe = null;
+
+            // invoke preVisitDirectory and then visit each entry
+            try {
+                result = visitor.preVisitDirectory(file);
+                if (result != FileVisitResult.CONTINUE) {
+                    return result;
+                }
+
+                // if an I/O occurs during iteration then a CME is thrown. We
+                // need to distinguish this from a CME thrown by the visitor.
+                boolean inAction = false;
+
+                try {
+                    for (Path entry: stream) {
+                        inAction = true;
+                        result = walk(entry, depth, ancestors);
+                        inAction = false;
+
+                        // returning null will cause NPE to be thrown
+                        if (result == null || result == FileVisitResult.TERMINATE)
+                            return result;
+
+                        // skip remaining siblings in this directory
+                        if (result == FileVisitResult.SKIP_SIBLINGS)
+                            break;
+                    }
+                } catch (ConcurrentModificationException x) {
+                    // if CME thrown because the iteration failed then remember
+                    // the IOException so that it is notified to postVisitDirectory
+                    if (!inAction) {
+                        // iteration failed
+                        Throwable t = x.getCause();
+                        if (t instanceof IOException)
+                            ioe = (IOException)t;
+                    }
+                    if (ioe == null)
+                        throw x;
+                }
+            } finally {
+                try {
+                    stream.close();
+                } catch (IOException x) { }
+            }
+
+            // invoke postVisitDirectory last
+            return visitor.postVisitDirectory(file, ioe);
+
+        } finally {
+            // remove key from trail if doing cycle detection
+            if (detectCycles) {
+                ancestors.remove(ancestors.size()-1);
+            }
+        }
+    }
+
+    private static class AncestorDirectory {
+        private final FileRef dir;
+        private final Object key;
+        AncestorDirectory(FileRef dir, Object key) {
+            this.dir = dir;
+            this.key = key;
+        }
+        FileRef file() {
+            return dir;
+        }
+        Object fileKey() {
+            return key;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/FileVisitOption.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Defines the file tree traversal options.
+ *
+ * @since 1.7
+ *
+ * @see Files#walkFileTree
+ */
+
+public enum FileVisitOption {
+    /**
+     * Follow symbolic links.
+     */
+    FOLLOW_LINKS,
+    /**
+     * Detect cycles in the file tree.
+     */
+    DETECT_CYCLES;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/FileVisitResult.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * The result type of a {@link FileVisitor FileVisitor}.
+ *
+ * @since 1.7
+ *
+ * @see Files#walkFileTree
+ */
+
+public enum FileVisitResult {
+    /**
+     * Continue. When returned from a {@link FileVisitor#preVisitDirectory
+     * preVisitDirectory} method then the entries in the directory should also
+     * be visited.
+     */
+    CONTINUE,
+    /**
+     * Terminate.
+     */
+    TERMINATE,
+    /**
+     * Continue without visiting the entries in this directory. This result
+     * is only meaningful when returned from the {@link
+     * FileVisitor#preVisitDirectory preVisitDirectory} method; otherwise
+     * this result type is the same as returning {@link #CONTINUE}.
+     */
+    SKIP_SUBTREE,
+    /**
+     * Continue without visiting the <em>siblings</em> of this file or directory.
+     * If returned from the {@link FileVisitor#preVisitDirectory
+     * preVisitDirectory} method then the entries in the directory are also
+     * skipped and the {@link FileVisitor#postVisitDirectory postVisitDirectory}
+     * method is not invoked.
+     */
+    SKIP_SIBLINGS;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/FileVisitor.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.attribute.BasicFileAttributes;
+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.
+ *
+ * <p> <b>Usage Examples:</b>
+ * Suppose we want to delete a file tree. In that case, each directory should
+ * be deleted after the entries in the directory are deleted.
+ * <pre>
+ *     Path start = ...
+ *     Files.walkFileTree(start, new SimpleFileVisitor&lt;Path&gt;() {
+ *         &#64;Override
+ *         public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ *             try {
+ *                 file.delete(false);
+ *             } catch (IOException exc) {
+ *                 // failed to delete
+ *             }
+ *             return FileVisitResult.CONTINUE;
+ *         }
+ *         &#64;Override
+ *         public FileVisitResult postVisitDirectory(Path dir, IOException e) {
+ *             if (e == null) {
+ *                 try {
+ *                     dir.delete(false);
+ *                 } catch (IOException exc) {
+ *                     // failed to delete
+ *                 }
+ *             } else {
+ *                 // directory iteration failed
+ *             }
+ *             return FileVisitResult.CONTINUE;
+ *         }
+ *     });
+ * </pre>
+ * <p> Furthermore, suppose we want to copy a file tree rooted at a source
+ * directory to a target location. In that case, symbolic links should be
+ * followed and the target directory should be created before the entries in
+ * the directory are copied.
+ * <pre>
+ *     final Path source = ...
+ *     final Path target = ...
+ *
+ *     Files.walkFileTree(source, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
+ *         new SimpleFileVisitor&lt;Path&gt;() {
+ *             &#64;Override
+ *             public FileVisitResult preVisitDirectory(Path dir) {
+ *                 try {
+ *                     dir.copyTo(target.resolve(source.relativize(dir)));
+ *                 } catch (FileAlreadyExistsException e) {
+ *                      // ignore
+ *                 } catch (IOException e) {
+ *                     // copy failed, skip rest of directory and descendants
+ *                     return SKIP_SUBTREE;
+ *                 }
+ *                 return CONTINUE;
+ *             }
+ *             &#64;Override
+ *             public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ *                 try {
+ *                     file.copyTo(target.resolve(source.relativize(file)));
+ *                 } catch (IOException e) {
+ *                     // copy failed
+ *                 }
+ *                 return CONTINUE;
+ *             }
+ *         });
+ * </pre>
+ *
+ * @since 1.7
+ */
+
+public interface FileVisitor<T extends FileRef> {
+
+    /**
+     * Invoked for a directory before entries in the directory are visited.
+     *
+     * <p> If this method returns {@link FileVisitResult#CONTINUE CONTINUE},
+     * then entries in the directory are visited. If this method returns {@link
+     * FileVisitResult#SKIP_SUBTREE SKIP_SUBTREE} or {@link
+     * FileVisitResult#SKIP_SIBLINGS SKIP_SIBLINGS} then entries in the
+     * directory (and any descendants) will not be visited.
+     *
+     * @param   dir
+     *          A reference to the directory
+     *
+     * @return  the visit result
+     */
+    FileVisitResult preVisitDirectory(T dir);
+
+    /**
+     * Invoked for a directory that could not be opened.
+     *
+     * @param   dir
+     *          A reference to the directory
+     * @param   exc
+     *          The I/O exception thrown from the attempt to open the directory
+     *
+     * @return  the visit result
+     */
+    FileVisitResult preVisitDirectoryFailed(T dir, IOException exc);
+
+    /**
+     * Invoked for a file in a directory.
+     *
+     * @param   file
+     *          A reference to the file
+     * @param   attrs
+     *          The file's basic attributes
+     *
+     * @return  the visit result
+     */
+    FileVisitResult visitFile(T file, BasicFileAttributes attrs);
+
+    /**
+     * Invoked for a file when its basic file attributes could not be read.
+     *
+     * @param   file
+     *          A reference to the file
+     * @param   exc
+     *          The I/O exception thrown from the attempt to read the file
+     *          attributes
+     *
+     * @return  the visit result
+     */
+    FileVisitResult visitFileFailed(T file, IOException exc);
+
+    /**
+     * Invoked for a directory after entries in the directory, and all of their
+     * descendants, have been visited. This method is also invoked when iteration
+     * of the directory completes prematurely (by a {@link #visitFile visitFile}
+     * method returning {@link FileVisitResult#SKIP_SIBLINGS SKIP_SIBLINGS},
+     * or an I/O error when iterating over the directory).
+     *
+     * @param   dir
+     *          A reference to the directory
+     * @param   exc
+     *          {@code null} if the iteration of the directory completes without
+     *          an error; otherwise the I/O exception that caused the iteration
+     *          of the directory to complete prematurely
+     *
+     * @return  the visit result
+     */
+    FileVisitResult postVisitDirectory(T dir, IOException exc);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/Files.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,406 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.spi.FileTypeDetector;
+import java.io.IOException;
+import java.util.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Utility methods for files and directories.
+ *
+ * @since 1.7
+ */
+
+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<FileTypeDetector> installeDetectors =
+            loadInstalledDetectors();
+
+        // loads all installed file type detectors
+        private static List<FileTypeDetector> loadInstalledDetectors() {
+            return AccessController
+                .doPrivileged(new PrivilegedAction<List<FileTypeDetector>>() {
+                    @Override public List<FileTypeDetector> run() {
+                        List<FileTypeDetector> list = new ArrayList<FileTypeDetector>();
+                        ServiceLoader<FileTypeDetector> loader = ServiceLoader
+                            .load(FileTypeDetector.class, ClassLoader.getSystemClassLoader());
+                        for (FileTypeDetector detector: loader) {
+                            list.add(detector);
+                        }
+                        return list;
+                }});
+        }
+    }
+
+    /**
+     * Probes the content type of a file.
+     *
+     * <p> 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.
+     *
+     * <p> 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.
+     *
+     * <p> 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 <a href="http://www.ietf.org/rfc/rfc2045.txt"><i>RFC&nbsp;2045:
+     * Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet
+     * Message Bodies</i></a>. The string is guaranteed to be parsable according
+     * to the grammar in the RFC.
+     *
+     * @param   file
+     *          The file reference
+     *
+     * @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.
+     *
+     * @see DirectoryStreamFilters#newContentTypeFilter
+     */
+    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;
+        }
+
+        // fallback to default
+        return DefaultFileTypeDetectorHolder.defaultFileTypeDetector
+            .probeContentType(file);
+    }
+
+    /**
+     * Invokes a {@link FileAction} for each entry in a directory accepted
+     * by a given {@link java.nio.file.DirectoryStream.Filter filter}.
+     *
+     * <p> This method opens the given directory and invokes the file action's
+     * {@link FileAction#invoke invoke} method for each entry accepted by the
+     * filter. When iteration is completed then the directory is closed. If the
+     * {@link DirectoryStream#close close} method throws an {@code IOException}
+     * then it is silently ignored.
+     *
+     * <p> If the {@code FileAction}'s {@code invoke} method terminates due
+     * to an uncaught {@link IOException}, {@code Error} or {@code RuntimeException}
+     * then the exception is propagated by this method after closing the
+     * directory.
+     *
+     * @param   dir
+     *          The directory
+     * @param   filter
+     *          The filter
+     * @param   action
+     *          The {@code FileAction} to invoke for each accepted entry
+     *
+     * @throws  NotDirectoryException
+     *          If the {@code dir} parameter is not a directory <i>(optional
+     *          specific exception)</i>
+     * @throws  IOException
+     *          If an I/O error occurs or the {@code invoke} method terminates
+     *          due to an uncaught {@code IOException}
+     * @throws  SecurityException
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String) checkRead} method is invoked
+     *          to check read access to the directory.
+     */
+    public static void withDirectory(Path dir,
+                                     DirectoryStream.Filter<? super Path> filter,
+                                     FileAction<? super Path> action)
+        throws IOException
+    {
+        // explicit null check required in case directory is empty
+        if (action == null)
+            throw new NullPointerException();
+
+        DirectoryStream<Path> stream = dir.newDirectoryStream(filter);
+        try {
+            // set to true when invoking the action so as to distinguish a
+            // CME thrown by the iteration from a CME thrown by the invoke
+            boolean inAction = false;
+            try {
+                for (Path entry: stream) {
+                    inAction = true;
+                    action.invoke(entry);
+                    inAction = false;
+                }
+            } catch (ConcurrentModificationException cme) {
+                if (!inAction) {
+                    Throwable cause = cme.getCause();
+                    if (cause instanceof IOException)
+                        throw (IOException)cause;
+                }
+                throw cme;
+            }
+        } finally {
+            try {
+                stream.close();
+            } catch (IOException x) { }
+        }
+    }
+
+    /**
+     * Invokes a {@link FileAction} for each entry in a directory with a
+     * file name that matches a given pattern.
+     *
+     * <p> This method opens the given directory and invokes the file action's
+     * {@link FileAction#invoke invoke} method for each entry that matches the
+     * given pattern. When iteration is completed then the directory is closed.
+     * If the {@link DirectoryStream#close close} method throws an {@code
+     * IOException} then it is silently ignored.
+     *
+     * <p> If the {@code FileAction}'s {@code invoke} method terminates due
+     * to an uncaught {@link IOException}, {@code Error} or {@code RuntimeException}
+     * then the exception is propagated by this method after closing the
+     * directory.
+     *
+     * <p> The globbing pattern language supported by this method is as
+     * specified by the {@link FileSystem#getPathMatcher getPathMatcher} method.
+     *
+     * @param   dir
+     *          The directory
+     * @param   glob
+     *          The globbing pattern
+     * @param   action
+     *          The {@code FileAction} to invoke for each entry
+     *
+     * @throws  NotDirectoryException
+     *          If the {@code dir} parameter is not a directory <i>(optional
+     *          specific exception)</i>
+     * @throws  IOException
+     *          If an I/O error occurs or the {@code invoke} method terminates
+     *          due to an uncaught {@code IOException}
+     * @throws  SecurityException
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String) checkRead} method is invoked
+     *          to check read access to the directory.
+     */
+    public static void withDirectory(Path dir,
+                                     String glob,
+                                     FileAction<? super Path> action)
+        throws IOException
+    {
+        if (glob == null)
+            throw new NullPointerException("'glob' is null");
+        final PathMatcher matcher = dir.getFileSystem().getPathMatcher("glob:" + glob);
+        DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
+            @Override
+            public boolean accept(Path entry)  {
+                return matcher.matches(entry.getName());
+            }
+        };
+        withDirectory(dir, filter, action);
+    }
+
+    /**
+     * Invokes a {@link FileAction} for all entries in a directory.
+     *
+     * <p> This method works as if invoking it were equivalent to evaluating the
+     * expression:
+     * <blockquote><pre>
+     * withDirectory(dir, "*", action)
+     * </pre></blockquote>
+     *
+     * @param   dir
+     *          The directory
+     * @param   action
+     *          The {@code FileAction} to invoke for each entry
+     *
+     * @throws  NotDirectoryException
+     *          If the {@code dir} parameter is not a directory <i>(optional
+     *          specific exception)</i>
+     * @throws  IOException
+     *          If an I/O error occurs or the {@code invoke} method terminates
+     *          due to an uncaught {@code IOException}
+     * @throws  SecurityException
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String) checkRead} method is invoked
+     *          to check read access to the directory.
+     */
+    public static void withDirectory(Path dir, FileAction<? super Path> action)
+        throws IOException
+    {
+        withDirectory(dir, "*", action);
+    }
+
+    /**
+     * Walks a file tree.
+     *
+     * <p> This method walks a file tree rooted at a given starting file. The
+     * file tree traversal is <em>depth-first</em> with the given {@link
+     * FileVisitor} invoked for each file encountered. File tree traversal
+     * completes when all accessible files in the tree have been visited, a
+     * visitor returns a result of {@link FileVisitResult#TERMINATE TERMINATE},
+     * or the visitor terminates due to an uncaught {@code Error} or {@code
+     * RuntimeException}.
+     *
+     * <p> For each file encountered this method attempts to gets 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,
+     * due to an I/O exception, then the {@link FileVisitor#visitFileFailed
+     * visitFileFailed} method is invoked with the I/O exception.
+     *
+     * <p> Where the file is a directory, this method attempts to open it by
+     * invoking its {@link Path#newDirectoryStream newDirectoryStream} method.
+     * Where the directory could not be opened, due to an {@code IOException},
+     * then the {@link FileVisitor#preVisitDirectoryFailed preVisitDirectoryFailed}
+     * method is invoked with the I/O exception, after which, the file tree walk
+     * continues, by default, at the next <em>sibling</em> of the directory.
+     *
+     * <p> Where the directory is opened successfully, then the entries in the
+     * directory, and their <em>descendants</em> are visited. When all entries
+     * have been visited, or an I/O error occurs during iteration of the
+     * directory, then the directory is closed and the visitor's {@link
+     * FileVisitor#postVisitDirectory postVisitDirectory} method is invoked.
+     * The file tree walk then continues, by default, at the next <em>sibling</em>
+     * of the directory.
+     *
+     * <p> By default, symbolic links are not automatically followed by this
+     * method. If the {@code options} parameter contains the {@link
+     * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then symbolic links are
+     * followed. When following links, and the attributes of the target cannot
+     * be read, then this method attempts to get the {@code BasicFileAttributes}
+     * of the link. If they can be read then the {@code visitFile} method is
+     * invoked with the attributes of the link (otherwise the {@code visitFileFailed}
+     * method is invoked as specified above).
+     *
+     * <p> If the {@code options} parameter contains the {@link
+     * FileVisitOption#DETECT_CYCLES DETECT_CYCLES} or {@link
+     * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} options then this method keeps
+     * track of directories visited so that cycles can be detected. A cycle
+     * 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 FileRef#isSameFile
+     * isSameFile} method to test if a directory is the same file as an
+     * ancestor. When a cycle is detected the {@link FileVisitor#visitFile
+     * visitFile} is invoked with the attributes of the directory. The {@link
+     * java.nio.file.attribute.BasicFileAttributes#isDirectory isDirectory}
+     * method may be used to test if the file is a directory and that a cycle is
+     * detected. The {@code preVisitDirectory} and {@code postVisitDirectory}
+     * methods are not invoked.
+     *
+     * <p> The {@code maxDepth} parameter is the maximum number of levels of
+     * directories to visit. A value of {@code 0} means that only the starting
+     * file is visited, unless denied by the security manager. A value of
+     * {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all
+     * levels should be visited.
+     *
+     * <p> If a visitor returns a result of {@code null} then {@code
+     * NullPointerException} is thrown.
+     *
+     * <p> When a security manager is installed and it denies access to a file
+     * (or directory), then it is ignored and the visitor is not invoked for
+     * that file (or directory).
+     *
+     * @param   start
+     *          The starting file
+     * @param   options
+     *          Options to configure the traversal
+     * @param   maxDepth
+     *          The maximum number of directory levels to visit
+     * @param   visitor
+     *          The file visitor to invoke for each file
+     *
+     * @throws  IllegalArgumentException
+     *          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.
+     */
+    public static void walkFileTree(Path start,
+                                    Set<FileVisitOption> options,
+                                    int maxDepth,
+                                    FileVisitor<? super Path> visitor)
+    {
+        if (maxDepth < 0)
+            throw new IllegalArgumentException("'maxDepth' is negative");
+        new FileTreeWalker(options, visitor).walk(start, maxDepth);
+    }
+
+    /**
+     * Walks a file tree.
+     *
+     * <p> This method works as if invoking it were equivalent to evaluating the
+     * expression:
+     * <blockquote><pre>
+     * walkFileTree(start, EnumSet.noneOf(FileVisitOption.class), Integer.MAX_VALUE, visitor)
+     * </pre></blockquote>
+     *
+     * @param   start
+     *          The starting file
+     * @param   visitor
+     *          The file visitor to invoke for each file
+     *
+     * @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.
+     */
+    public static void walkFileTree(Path start, FileVisitor<? super Path> visitor) {
+        walkFileTree(start,
+                     EnumSet.noneOf(FileVisitOption.class),
+                     Integer.MAX_VALUE,
+                     visitor);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/InvalidPathException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Unchecked exception thrown when path string cannot be converted into a
+ * {@link Path} because the path string contains invalid characters, or
+ * the path string is invalid for other file system specific reasons.
+ */
+
+public class InvalidPathException
+    extends IllegalArgumentException
+{
+    static final long serialVersionUID = 4355821422286746137L;
+
+    private String input;
+    private int index;
+
+    /**
+     * Constructs an instance from the given input string, reason, and error
+     * index.
+     *
+     * @param  input   The input string
+     * @param  reason  A string explaining why the input was rejected
+     * @param  index   The index at which the error occurred,
+     *                 or <tt>-1</tt> if the index is not known
+     *
+     * @throws  NullPointerException
+     *          If either the input or reason strings are <tt>null</tt>
+     *
+     * @throws  IllegalArgumentException
+     *          If the error index is less than <tt>-1</tt>
+     */
+    public InvalidPathException(String input, String reason, int index) {
+        super(reason);
+        if ((input == null) || (reason == null))
+            throw new NullPointerException();
+        if (index < -1)
+            throw new IllegalArgumentException();
+        this.input = input;
+        this.index = index;
+    }
+
+    /**
+     * Constructs an instance from the given input string and reason.  The
+     * resulting object will have an error index of <tt>-1</tt>.
+     *
+     * @param  input   The input string
+     * @param  reason  A string explaining why the input was rejected
+     *
+     * @throws  NullPointerException
+     *          If either the input or reason strings are <tt>null</tt>
+     */
+    public InvalidPathException(String input, String reason) {
+        this(input, reason, -1);
+    }
+
+    /**
+     * Returns the input string.
+     *
+     * @return  The input string
+     */
+    public String getInput() {
+        return input;
+    }
+
+    /**
+     * Returns a string explaining why the input string was rejected.
+     *
+     * @return  The reason string
+     */
+    public String getReason() {
+        return super.getMessage();
+    }
+
+    /**
+     * Returns an index into the input string of the position at which the
+     * error occurred, or <tt>-1</tt> if this position is not known.
+     *
+     * @return  The error index
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * Returns a string describing the error.  The resulting string
+     * consists of the reason string followed by a colon character
+     * (<tt>':'</tt>), a space, and the input string.  If the error index is
+     * defined then the string <tt>" at index "</tt> followed by the index, in
+     * decimal, is inserted after the reason string and before the colon
+     * character.
+     *
+     * @return  A string describing the error
+     */
+    public String getMessage() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(getReason());
+        if (index > -1) {
+            sb.append(" at index ");
+            sb.append(index);
+        }
+        sb.append(": ");
+        sb.append(input);
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/LinkOption.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Defines the options as to how symbolic links are handled.
+ *
+ * @since 1.7
+ */
+
+public enum LinkOption implements OpenOption, CopyOption {
+    /**
+     * Do not follow symbolic links.
+     *
+     * @see FileRef#getFileAttributeView(Class,LinkOption[])
+     * @see Path#copyTo
+     * @see SecureDirectoryStream#newByteChannel
+     */
+    NOFOLLOW_LINKS;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/LinkPermission.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.security.BasicPermission;
+
+/**
+ * The {@code Permission} class for link creation operations.
+ *
+ * <p> The following table provides a summary description of what the permission
+ * allows, and discusses the risks of granting code the permission.
+ *
+ * <table border=1 cellpadding=5
+ *        summary="Table shows permission target name, what the permission allows, and associated risks">
+ * <tr>
+ * <th>Permission Target Name</th>
+ * <th>What the Permission Allows</th>
+ * <th>Risks of Allowing this Permission</th>
+ * </tr>
+ * <tr>
+ *   <td>hard</td>
+ *   <td> Ability to add an existing file to a directory. This is sometimes
+ *   known as creating a link, or hard link. </td>
+ *   <td> Extreme care should be taken when granting this permission. It allows
+ *   linking to any file or directory in the file system thus allowing the
+ *   attacker to access to all files. </td>
+ * </tr>
+ * <tr>
+ *   <td>symbolic</td>
+ *   <td> Ability to create symbolic links. </td>
+ *   <td> Extreme care should be taken when granting this permission. It allows
+ *   linking to any file or directory in the file system thus allowing the
+ *   attacker to access to all files. </td>
+ * </tr>
+ * </table>
+ *
+ * @since 1.7
+ *
+ * @see Path#createLink
+ * @see Path#createSymbolicLink
+ */
+public final class LinkPermission extends BasicPermission {
+    static final long serialVersionUID = -1441492453772213220L;
+
+    private void checkName(String name) {
+        if (!name.equals("hard") && !name.equals("symbolic")) {
+            throw new IllegalArgumentException("name: " + name);
+        }
+    }
+
+    /**
+     * Constructs a {@code LinkPermission} with the specified name.
+     *
+     * @param   name
+     *          The name of the permission. It must be "hard" or "symbolic".
+     *
+     * @throws  IllegalArgumentException
+     *          If name is empty or invalid.
+     */
+    public LinkPermission(String name) {
+        super(name);
+        checkName(name);
+    }
+
+    /**
+     * Constructs a {@code LinkPermission} with the specified name.
+     *
+     * @param   name
+     *          The name of the permission; must be "hard" or "symbolic".
+     * @param   actions
+     *          The actions for the permission; must be the empty string or
+     *          {@code null}
+     *
+     * @throws  IllegalArgumentException
+     *          If name is empty or invalid.
+     */
+    public LinkPermission(String name, String actions) {
+        super(name);
+        checkName(name);
+        if (actions != null && actions.length() > 0) {
+            throw new IllegalArgumentException("actions: " + actions);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/NoSuchFileException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when an attempt is made to access a file that does
+ * not exist.
+ *
+ * @since 1.7
+ */
+
+public class NoSuchFileException
+    extends FileSystemException
+{
+    static final long serialVersionUID = -1390291775875351931L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          A string identifying the file or {@code null} if not known.
+     */
+    public NoSuchFileException(String file) {
+        super(file);
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          A string identifying the file or {@code null} if not known.
+     * @param   other
+     *          A string identifying the other file or {@code null} if not known.
+     * @param   reason
+     *          A reason message with additional information or {@code null}
+     */
+    public NoSuchFileException(String file, String other, String reason) {
+        super(file, other, reason);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/NotDirectoryException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when a file system operation, intended for a
+ * directory, fails because the file is not a directory.
+ *
+ * @since 1.7
+ */
+
+public class NotDirectoryException
+    extends FileSystemException
+{
+    private static final long serialVersionUID = -9011457427178200199L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          A string identifying the file or {@code null} if not known.
+     */
+    public NotDirectoryException(String file) {
+        super(file);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/NotLinkException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when a file system operation fails because a file
+ * is not a link.
+ *
+ * @since 1.7
+ */
+
+public class NotLinkException
+    extends FileSystemException
+{
+    static final long serialVersionUID = -388655596416518021L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          A string identifying the file or {@code null} if not known.
+     */
+    public NotLinkException(String file) {
+        super(file);
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          A string identifying the file or {@code null} if not known.
+     * @param   other
+     *          A string identifying the other file or {@code null} if not known.
+     * @param   reason
+     *          A reason message with additional information or {@code null}
+     */
+    public NotLinkException(String file, String other, String reason) {
+        super(file, other, reason);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/OpenOption.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * An object that configures how to open or create a file.
+ *
+ * <p> Objects of this type are used by methods such as {@link
+ * Path#newOutputStream(OpenOption[]) newOutputStream}, {@link
+ * FileRef#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.
+ *
+ * <p> The {@link StandardOpenOption} enumeration type defines the
+ * <i>standard</i> options.
+ *
+ * @since 1.7
+ */
+
+public interface OpenOption {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/Path.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,1612 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.attribute.*;
+import java.nio.channels.*;
+import java.io.*;
+import java.net.URI;
+import java.util.*;
+
+/**
+ * A file reference that locates a file using a system dependent path. The file
+ * is not required to exist.
+ *
+ * <p> On many platforms a <em>path</em> is the means to locate and access files
+ * in a file system. A path is hierarchical and composed of a sequence of
+ * directory names separated by a special separator or delimiter.
+ *
+ * <h4>Path operations</h4>
+ *
+ * <p> A system dependent path represented by this class is conceptually a
+ * sequence of name elements and optionally a <em>root component</em>. The name
+ * that is <em>farthest</em> 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.
+ *
+ * <p> 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.
+ *
+ * <h4>File operations</h4>
+ *
+ * <p> A {@code Path} is either <em>absolute</em> or <em>relative</em>. 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.
+ *
+ * <p> In addition to the operations defined by the {@link FileRef} interface,
+ * this class defines the following operations:
+ *
+ * <ul>
+ *   <li><p> Files may be {@link #createFile(FileAttribute[]) created}, or
+ *     directories may be {@link #createDirectory(FileAttribute[]) created}.
+ *     </p></li>
+ *   <li><p> Directories can be {@link #newDirectoryStream opened} so as to
+ *      iterate over the entries in the directory. </p></li>
+ *   <li><p> Files can be {@link #copyTo(Path,CopyOption[]) copied} or
+ *     {@link #moveTo(Path,CopyOption[]) moved}. </p></li>
+ *   <li><p> Symbolic-links may be {@link #createSymbolicLink created}, or the
+ *     target of a link may be {@link #readSymbolicLink read}. </p></li>
+ *   <li><p> {@link #newInputStream InputStream} or {@link #newOutputStream
+ *     OutputStream} streams can be created to allow for interoperation with the
+ *     <a href="../../../java/io/package-summary.html">{@code java.io}</a> package
+ *     where required. </li></p>
+ *   <li><p> The {@link #toRealPath real} path of an existing file may be
+ *     obtained. </li></p>
+ * </ul>
+ *
+ * <p> 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.
+ *
+ * <h4>File attributes</h4>
+ *
+ * The <a href="attribute/package-summary.html">{@code java.nio.file.attribute}</a>
+ * package provides access to file attributes or <em>meta-data</em> 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 <em>basic</em> meta-data are obtained, in bulk, by
+ * invoking the {@link Attributes#readBasicFileAttributes
+ * Attributes.readBasicFileAttributes} method:
+ * <pre>
+ *     Path file = ...
+ *     BasicFileAttributes attrs = Attributes.readBasicFileAttributes(file);
+ * </pre>
+ *
+ * <a name="interop"><h4>Interoperability</h4></a>
+ *
+ * <p> Paths created by file systems 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.
+ *
+ * <p> 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.
+ *
+ * <h4>Concurrency</h4></a>
+ *
+ * <p> Instances of this class are immutable and safe for use by multiple concurrent
+ * threads.
+ *
+ * @since 1.7
+ */
+
+public abstract class Path
+    implements FileRef, Comparable<Path>, Iterable<Path>, 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();
+
+    /**
+     * Tells whether or not this path is absolute.
+     *
+     * <p> 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();
+
+    /**
+     * Returns the root component of this path as a {@code Path} object,
+     * or {@code null} if this path does not have a root component.
+     *
+     * @return  A path representing the root component of this path,
+     *          or {@code null}
+     */
+    public abstract Path getRoot();
+
+    /**
+     * Returns the name of the file or directory denoted by this path. The
+     * file name is the <em>farthest</em> 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();
+
+    /**
+     * Returns the <em>parent path</em>, or {@code null} if this path does not
+     * have a parent.
+     *
+     * <p> The parent of this path object consists of this path's root
+     * component, if any, and each element in the path except for the
+     * <em>farthest</em> from the root in the directory hierarchy. This method
+     * does not access the file system; the path or its parent may not exist.
+     * Furthermore, this method does not eliminate special names such as "."
+     * and ".." that may be used in some implementations. On UNIX for example,
+     * the parent of "{@code /a/b/c}" is "{@code /a/b}", and the parent of
+     * {@code "x/y/.}" is "{@code x/y}". This method may be used with the {@link
+     * #normalize normalize} method, to eliminate redundant names, for cases where
+     * <em>shell-like</em> navigation is required.
+     *
+     * <p> If this path has one or more elements, and no root component, then
+     * this method is equivalent to evaluating the expression:
+     * <blockquote><pre>
+     * subpath(0,&nbsp;getNameCount()-1);
+     * </pre></blockquote>
+     *
+     * @return  A path representing the path's parent
+     */
+    public abstract Path getParent();
+
+    /**
+     * Returns the number of name elements in the path.
+     *
+     * @return  The number of elements in the path, or {@code 0} if this path
+     *          only represents a root component
+     */
+    public abstract int getNameCount();
+
+   /**
+     * Returns a name element of this path.
+     *
+     * <p> The {@code index} parameter is the index of the name element to return.
+     * The element that is <em>closest</em> to the root in the directory hierarchy
+     * has index {@code 0}. The element that is <em>farthest</em> from the root
+     * has index {@link #getNameCount count}{@code -1}.
+     *
+     * @param   index
+     *          The index of the element
+     *
+     * @return  The name element
+     *
+     * @throws  IllegalArgumentException
+     *          If {@code index} is negative, {@code index} is greater than or
+     *          equal to the number of elements, or this path has zero name
+     *          elements.
+     */
+    public abstract Path getName(int index);
+
+    /**
+     * Returns a relative {@code Path} that is a subsequence of the name
+     * elements of this path.
+     *
+     * <p> The {@code beginIndex} and {@code endIndex} parameters specify the
+     * subsequence of name elements. The name that is <em>closest</em> to the root
+     * in the directory hierarchy has index {@code 0}. The name that is
+     * <em>farthest</em> from the root has index {@link #getNameCount
+     * count}{@code -1}. The returned {@code Path} object has the name elements
+     * that begin at {@code beginIndex} and extend to the element at index {@code
+     * endIndex-1}.
+     *
+     * @param   beginIndex
+     *          The index of the first element, inclusive
+     * @param   endIndex
+     *          The index of the last element, exclusive
+     *
+     * @return  A new {@code Path} object that is a subsequence of the name
+     *          elements in this {@code Path}
+     *
+     * @throws  IllegalArgumentException
+     *          If {@code beginIndex} is negative, or greater than or equal to
+     *          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);
+
+    /**
+     * Tests if this path starts with the given path.
+     *
+     * <p> This path <em>starts</em> with the given path if this path's root
+     * component <em>starts</em> with the root component of the given path,
+     * and this path starts with the same name elements as the given path.
+     * If the given path has more name elements than this path then {@code false}
+     * is returned.
+     *
+     * <p> Whether or not the root component of this path starts with the root
+     * component of the given path is file system specific. If this path does
+     * not have a root component and the given path has a root component then
+     * this path does not start with the given path.
+     *
+     * @param   other
+     *          The given path
+     *
+     * @return  {@code true} if this path starts with the given path; otherwise
+     *          {@code false}
+     */
+    public abstract boolean startsWith(Path other);
+
+    /**
+     * Tests if this path ends with the given path.
+     *
+     * <p> If the given path has <em>N</em> elements, and no root component,
+     * and this path has <em>N</em> or more elements, then this path ends with
+     * the given path if the last <em>N</em> elements of each path, starting at
+     * the element farthest from the root, are equal.
+     *
+     * <p> If the given path has a root component then this path ends with the
+     * given path if the root component of this path <em>ends with</em> the root
+     * component of the given path, and the corresponding elements of both paths
+     * are equal. Whether or not the root component of this path ends with the
+     * root component of the given path is file system specific. If this path
+     * does not have a root component and the given path has a root component
+     * then this path does not end with the given path.
+     *
+     * @param   other
+     *          The given path
+     *
+     * @return  {@code true} if this path ends with the given path; otherwise
+     *          {@code false}
+     */
+    public abstract boolean endsWith(Path other);
+
+    /**
+     * Returns a path that is this path with redundant name elements eliminated.
+     *
+     * <p> The precise definition of this method is implementation dependent but
+     * in general it derives from this path, a path that does not contain
+     * <em>redundant</em> name elements. In many file systems, the "{@code .}"
+     * and "{@code ..}" are special names used to indicate the current directory
+     * and parent directory. In such file systems all occurrences of "{@code .}"
+     * are considered redundant. If a "{@code ..}" is preceded by a
+     * non-"{@code ..}" name then both names are considered redundant (the
+     * process to identify such names is repeated until is it no longer
+     * applicable).
+     *
+     * <p> This method does not access the file system; the path may not locate
+     * a file that exists. Eliminating "{@code ..}" and a preceding name from a
+     * 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.
+     *
+     * @see #getParent
+     * @see #toRealPath
+     */
+    public abstract Path normalize();
+
+    // -- resolution and relativization --
+
+    /**
+     * Resolve the given path against this path.
+     *
+     * <p> 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 <em>joins</em>
+     * 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}
+     *
+     * @return  The resulting path
+     *
+     * @see #relativize
+     */
+    public abstract 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.
+     *
+     * @param   other
+     *          The path string to resolve against this path
+     *
+     * @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);
+
+    /**
+     * Constructs a relative path between this path and a given path.
+     *
+     * <p> Relativization is the inverse of {@link #resolve(Path) resolution}.
+     * This method attempts to construct a {@link #isAbsolute relative} path
+     * that when {@link #resolve(Path) resolved} against this path, yields a
+     * path that locates the same file as the given path. For example, on UNIX,
+     * if this path is {@code "/a/b"} and the given path is {@code "/a/b/c/d"}
+     * then the resulting relative path would be {@code "c/d"}. Where this
+     * path and the given path do not have a {@link #getRoot root} component,
+     * then a relative path can be constructed. A relative path cannot be
+     * 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.
+     *
+     * <p> For any two paths <i>p</i> and <i>q</i>, where <i>q</i> does not have
+     * a root component,
+     * <blockquote>
+     *   <i>p</i><tt>.relativize(</tt><i>p</i><tt>.resolve(</tt><i>q</i><tt>)).equals(</tt><i>q</i><tt>)</tt>
+     * </blockquote>
+     *
+     * <p> 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
+     * 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
+     * dependent if {@code "a/b/../x"} would locate the same file as {@code "/a/x"}.
+     *
+     * @param   other
+     *          The resulting path
+     *
+     * @return  The resulting relative path, or {@code null} 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.
+     *
+     * <p> The {@code failIfNotExists} parameter determines how the method
+     * behaves when the file does not exist. When {@code true}, and the file
+     * does not exist, then the method fails. When {@code false} then the method
+     * does not fail.
+     *
+     * <p> As with the {@link FileRef#delete delete()} method, 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 link is
+     * deleted and not the final target of the link.
+     *
+     * <p> 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.
+     *
+     * <p> 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   failIfNotExists
+     *          {@code true} if the method should fail when the file does not
+     *          exist
+     *
+     * @throws  NoSuchFileException
+     *          If the value of the {@code failIfNotExists} is {@code true} and
+     *          the file does not exist <i>(optional specific exception)</i>
+     * @throws  DirectoryNotEmptyException
+     *          If the file is a directory and could not otherwise be deleted
+     *          because the directory is not empty <i>(optional specific
+     *          exception)</i>
+     * @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(boolean failIfNotExists) throws IOException;
+
+    /**
+     * Creates a symbolic link to a target <i>(optional operation)</i>.
+     *
+     * <p> 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.
+     *
+     * <p> 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.
+     *
+     * <p> 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 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 <i>(optional specific
+     *          exception)</i>
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the the default provider, and a security manager
+     *          is installed, it denies {@link LinkPermission}<tt>("symbolic")</tt>
+     *          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 <i>(optional
+     * operation)</i>.
+     *
+     * <p> 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 <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the the default provider, and a security manager
+     *          is installed, it denies {@link LinkPermission}<tt>("hard")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to both this path and the path of the
+     *          existing file
+     *
+     * @see BasicFileAttributes#linkCount
+     */
+    public abstract Path createLink(Path existing) throws IOException;
+
+    /**
+     * Reads the target of a symbolic link <i>(optional operation)</i>.
+     *
+     * <p> If the file system supports <a href="package-summary.html#links">symbolic
+     * links</a> then this method is used read the target of the link, failing
+     * if the file is not a 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 link <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the 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;
+
+    /**
+     * Returns a URI to represent this path.
+     *
+     * <p> This method constructs a hierarchical {@link URI} that is absolute
+     * with a non-empty path component. Its {@link URI#getScheme() scheme} is
+     * equal to the URI scheme that identifies the provider. The exact form of
+     * the other URI components is highly provider dependent. In particular, it
+     * is implementation dependent if its query, fragment, and authority
+     * components are defined or undefined.
+     *
+     * <p> For the default provider the {@link URI#getPath() path} component
+     * will represent the {@link #toAbsolutePath absolute} path; the query,
+     * fragment components are undefined. Whether the authority component is
+     * defined or not is implementation dependent. There is no guarantee that
+     * the {@code URI} may be used to construct a {@link java.io.File java.io.File}.
+     * In particular, if this path represents a Universal Naming Convention (UNC)
+     * path, then the UNC server name may be encoded in the authority component
+     * of the resulting URI. In the case of the default provider, and the file
+     * exists, and it can be determined that the file is a directory, then the
+     * resulting {@code URI} will end with a slash.
+     *
+     * <p> The default provider provides a similar <em>round-trip</em> guarantee
+     * to the {@link java.io.File} class. For a given {@code Path} <i>p</i> it
+     * is guaranteed that
+     * <blockquote><tt>
+     * {@link Paths#get(URI) Paths.get}(</tt><i>p</i><tt>.toUri()).equals(</tt><i>p</i>
+     * <tt>.{@link #toAbsolutePath() toAbsolutePath}())</tt>
+     * </blockquote>
+     * so long as the original {@code Path}, the {@code URI}, and the new {@code
+     * Path} are all created in (possibly different invocations of) the same
+     * Java virtual machine. Whether other providers make any guarantees is
+     * provider specific and therefore unspecified.
+     *
+     * <p> When a file system is constructed to access the contents of a file
+     * as a file system then it is highly implementation specific if the returned
+     * URI represents the given path in the file system or it represents a
+     * <em>compound</em> URI that encodes the URI of the enclosing file system.
+     * A format for compound URIs is not defined in this release; such a scheme
+     * may be added in a future release.
+     *
+     * @return  An absolute, hierarchical URI with a non-empty path component
+     *
+     * @throws  IOError
+     *          If an I/O error occurs obtaining the absolute path, or where a
+     *          file system is constructed to access the contents of a file as
+     *          a file system, the URI of the enclosing file system cannot be
+     *          obtained.
+     *
+     * @throws  SecurityException
+     *          In the case of the the default provider, and a security manager
+     *          is installed, the {@link #toAbsolutePath toAbsolutePath} method
+     *          throws a security exception.
+     */
+    public abstract URI toUri();
+
+    /**
+     * Returns a {@code Path} object representing the absolute path of this
+     * path.
+     *
+     * <p> If this path is already {@link Path#isAbsolute absolute} then this
+     * method simply returns this path. Otherwise, this method resolves the path
+     * in an implementation dependent manner, typically by resolving the path
+     * against a file system default directory. Depending on the implementation,
+     * this method may throw an I/O error if the file system is not accessible.
+     *
+     * @return  A {@code Path} object representing the absolute path
+     *
+     * @throws  IOError
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the the default provider, and a security manager
+     *          is installed, its {@link SecurityManager#checkPropertyAccess(String)
+     *          checkPropertyAccess} method is invoked to check access to the
+     *          system property {@code user.dir}
+     */
+    public abstract Path toAbsolutePath();
+
+    /**
+     * Returns the <em>real</em> path of an existing file.
+     *
+     * <p> 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
+     * 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
+     * actual case. Additionally, the resulting path has redundant name
+     * elements removed.
+     *
+     * <p> If this path is relative then its absolute path is first obtained,
+     * as if by invoking the {@link #toAbsolutePath toAbsolutePath} method.
+     *
+     * <p> The {@code resolveLinks} parameter specifies if symbolic links
+     * should be resolved. This parameter is ignored when symbolic links are
+     * not supported. Where supported, and the parameter has the value {@code
+     * true} then symbolic links are resolved to their final target. Where the
+     * parameter has the value {@code false} then this method does not resolve
+     * symbolic links. Some implementations allow special names such as
+     * "{@code ..}" to refer to the parent directory. When deriving the <em>real
+     * path</em>, and a "{@code ..}" (or equivalent) is preceded by a
+     * non-"{@code ..}" name then an implementation will typically causes both
+     * names to be removed. When not resolving symbolic links and the preceding
+     * name is a symbolic link then the names are only removed if it guaranteed
+     * that the resulting path will locate the same file as this path.
+     *
+     * @return  An absolute path represent the <em>real</em> path of the file
+     *          located by this object
+     *
+     * @throws  IOException
+     *          If the file does not exist or an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the the default provider, and a security manager
+     *          is installed, its {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file, and where
+     *          this path is not absolute, its {@link SecurityManager#checkPropertyAccess(String)
+     *          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.
+     *
+     * <p> 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 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
+     * <i>file-tree</i> where required.
+     *
+     * <p> The {@code options} parameter is an array of options and may contain
+     * any of the following:
+     *
+     * <table border=1 cellpadding=5 summary="">
+     * <tr> <th>Option</th> <th>Description</th> </tr>
+     * <tr>
+     *   <td> {@link StandardCopyOption#REPLACE_EXISTING REPLACE_EXISTING} </td>
+     *   <td> 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 is replaced (not the target of
+     *     the link. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardCopyOption#COPY_ATTRIBUTES COPY_ATTRIBUTES} </td>
+     *   <td> 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. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} </td>
+     *   <td> Symbolic-links are not followed. If the file, located by this path,
+     *     is a symbolic-link then the link is copied rather than the target of
+     *     the link. 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 link. </td>
+     * </tr>
+     * </table>
+     *
+     * <p> An implementation of this interface may support additional
+     * implementation specific options.
+     *
+     * <p> 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
+     *          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 <i>(optional specific exception)</i>
+     * @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.
+     *
+     * <p> 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 link is moved and
+     * not the target of the link. 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 <i>file tree</i> 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.
+     *
+     * <p> The {@code options} parameter is an array of options and may contain
+     * any of the following:
+     *
+     * <table border=1 cellpadding=5 summary="">
+     * <tr> <th>Option</th> <th>Description</th> </tr>
+     * <tr>
+     *   <td> {@link StandardCopyOption#REPLACE_EXISTING REPLACE_EXISTING} </td>
+     *   <td> 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 is replaced and not the target of
+     *     the link. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardCopyOption#ATOMIC_MOVE ATOMIC_MOVE} </td>
+     *   <td> 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. </td>
+     * </table>
+     *
+     * <p> An implementation of this interface may support additional
+     * implementation specific options.
+     *
+     * <p> 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
+     *          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
+     *          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.
+     *
+     * <p> 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. The {@link Files#withDirectory Files.withDirectory} utility
+     * method is useful for cases where a task is performed on each accepted
+     * entry in a directory. This method closes the directory when iteration is
+     * complete (or an error occurs).
+     *
+     * <p> 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 <i>(optional specific exception)</i>
+     * @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<Path> 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
+     * <em>globbing</em> pattern.
+     *
+     * <p> For example, suppose we want to iterate over the files ending with
+     * ".java" in a directory:
+     * <pre>
+     *     Path dir = ...
+     *     DirectoryStream&lt;Path&gt; stream = dir.newDirectoryStream("*.java");
+     * </pre>
+     *
+     * <p> The globbing pattern is specified by the {@link
+     * FileSystem#getPathMatcher getPathMatcher} method.
+     *
+     * <p> 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.
+     *
+     * <p> 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  UnsupportedOperationException
+     *          If the pattern syntax is not known to the implementation
+     * @throws  NotDirectoryException
+     *          If the file could not otherwise be opened because it is not
+     *          a directory <i>(optional specific exception)</i>
+     * @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<Path> 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 {@link DirectoryStreamFilters}
+     * class defines factory methods that create useful filters.
+     *
+     * <p> 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. The {@link Files#withDirectory Files.withDirectory} utility
+     * method is useful for cases where a task is performed on each accepted
+     * entry in a directory. This method closes the directory when iteration is
+     * complete (or an error occurs).
+     *
+     * <p> Where the filter terminates due to an uncaught error or runtime
+     * exception then it propogated to the caller of the iterator's {@link
+     * Iterator#hasNext() hasNext} or {@link Iterator#next() next} methods.
+     *
+     * <p> 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}.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to iterate over the files in a directory that are
+     * larger than 8K.
+     * <pre>
+     *     DirectoryStream.Filter&lt;Path&gt; filter = new DirectoryStream.Filter&lt;Path&gt;() {
+     *         public boolean accept(Path file) {
+     *             try {
+     *                 long size = Attributes.readBasicFileAttributes(file).size();
+     *                 return (size > 8192L);
+     *             } catch (IOException e) {
+     *                 // failed to get size
+     *                 return false;
+     *             }
+     *         }
+     *     };
+     *     Path dir = ...
+     *     DirectoryStream&lt;Path&gt; stream = dir.newDirectoryStream(filter);
+     * </pre>
+     * @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 <i>(optional specific exception)</i>
+     * @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<Path> newDirectoryStream(DirectoryStream.Filter<? super Path> filter)
+        throws IOException;
+
+    /**
+     * Creates a new and empty file, failing if the file already exists.
+     *
+     * <p> 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.
+     *
+     * <p> 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
+     *          <i>(optional specific exception)</i>
+     * @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;
+
+    /**
+     * Creates a new directory.
+     *
+     * <p> 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.
+     *
+     * <p> 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
+     *
+     * @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 <i>(optional specific exception)</i>
+     * @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.
+     */
+    public abstract Path createDirectory(FileAttribute<?>... attrs)
+        throws IOException;
+
+    /**
+     * Opens or creates a file, returning a seekable byte channel to access the
+     * file.
+     *
+     * <p> 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.
+     *
+     * <p> In the addition to {@code READ} and {@code WRITE}, the following
+     * options may be present:
+     *
+     * <table border=1 cellpadding=5 summary="">
+     * <tr> <th>Option</th> <th>Description</th> </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#APPEND APPEND} </td>
+     *   <td> 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. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} </td>
+     *   <td> 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. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#CREATE_NEW CREATE_NEW} </td>
+     *   <td> 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. </td>
+     * </tr>
+     * <tr>
+     *   <td > {@link StandardOpenOption#CREATE CREATE} </td>
+     *   <td> 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. </td>
+     * </tr>
+     * <tr>
+     *   <td > {@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} </td>
+     *   <td> When this option is present then the implementation makes a
+     *   <em>best effort</em> attempt to delete the file when closed by the
+     *   {@link SeekableByteChannel#close close} method. If the {@code close}
+     *   method is not invoked then a <em>best effort</em> attempt is made to
+     *   delete the file when the Java virtual machine terminates. </td>
+     * </tr>
+     * <tr>
+     *   <td>{@link StandardOpenOption#SPARSE SPARSE} </td>
+     *   <td> When creating a new file this option is a <em>hint</em> that the
+     *   new file will be sparse. This option is ignored when not creating
+     *   a new file. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#SYNC SYNC} </td>
+     *   <td> Requires that every update to the file's content or metadata be
+     *   written synchronously to the underlying storage device. (see <a
+     *   href="package-summary.html#integrity"> Synchronized I/O file
+     *   integrity</a>). </td>
+     * <tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#DSYNC DSYNC} </td>
+     *   <td> Requires that every update to the file's content be written
+     *   synchronously to the underlying storage device. (see <a
+     *   href="package-summary.html#integrity"> Synchronized I/O file
+     *   integrity</a>). </td>
+     * </tr>
+     * </table>
+     *
+     * <p> An implementation may also support additional implementation specific
+     * options.
+     *
+     * <p> The {@code attrs} parameter is an optional array of file {@link
+     * FileAttribute file-attributes} to set atomically when a new file is created.
+     *
+     * <p> In the case of the default provider, the returned seekable byte channel
+     * is a {@link FileChannel}.
+     *
+     * <p> <b>Usage Examples:</b>
+     * <pre>
+     *     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&lt;Set&lt;PosixFilePermission&gt;&gt; perms = ...
+     *     SeekableByteChannel sbc = file.newByteChannel(EnumSet.of(CREATE_NEW,READ,WRITE), perms);
+     * </pre>
+     *
+     * @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
+     *          <i>(optional specific exception)</i>
+     * @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<? extends OpenOption> options,
+                                                       FileAttribute<?>... attrs)
+        throws IOException;
+
+    /**
+     * Opens or creates a file, returning a seekable byte channel to access the
+     * file.
+     *
+     * <p> This method extends the options defined by the {@code FileRef}
+     * interface and to the options specified by the {@link
+     * #newByteChannel(Set,FileAttribute[]) newByteChannel} method
+     * except that the options are specified by an array. In the case of the
+     * default provider, the returned seekable byte channel is a {@link
+     * FileChannel}.
+     *
+     * @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
+     *          <i>(optional specific exception)</i>
+     * @throws  IOException                 {@inheritDoc}
+     * @throws  SecurityException           {@inheritDoc}
+     */
+    @Override
+    public abstract SeekableByteChannel newByteChannel(OpenOption... options)
+        throws IOException;
+
+    /**
+     * Opens the file located by this path for reading, returning an input
+     * stream to read bytes 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.
+     *
+     * @return  An input stream to read bytes from the 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 the file.
+     */
+    public abstract InputStream newInputStream() throws IOException;
+
+    /**
+     * Opens or creates the file located by this path for writing, returning an
+     * output stream to write bytes to the file.
+     *
+     * <p> 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. If no open options are present
+     * then this method creates a new file for writing or truncates an existing
+     * file.
+     *
+     * <p> The resulting stream will not be buffered. The stream will be safe
+     * for access by multiple concurrent threads.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we wish to open a log file for writing so that we append to the
+     * file if it already exists, or create it when it doesn't exist.
+     * <pre>
+     *     Path logfile = ...
+     *     OutputStream out = new BufferedOutputStream(logfile.newOutputStream(CREATE, APPEND));
+     * </pre>
+     *
+     * @param   options
+     *          Options specifying how the file is opened
+     *
+     * @return  a new seekable byte channel
+     *
+     * @throws  IllegalArgumentException
+     *          If {@code options} contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          If an unsupported open 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.
+     */
+    public abstract OutputStream newOutputStream(OpenOption... options)
+        throws IOException;
+
+    /**
+     * Opens or creates the file located by this path for writing, returning an
+     * output stream to write bytes to the file.
+     *
+     * <p> This method opens or creates a file in exactly the manner specified
+     * by the {@link Path#newByteChannel(Set,FileAttribute[]) newByteChannel}
+     * method except that {@code options} parameter may not contain the {@link
+     * StandardOpenOption#READ READ} option. If no open options are present
+     * then this method creates a new file for writing or truncates an existing
+     * file.
+     *
+     * <p> 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
+     * @param   attrs
+     *          An optional list of file attributes to set atomically when
+     *          creating the file
+     *
+     * @return  A new output stream
+     *
+     * @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  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.
+     */
+    public abstract OutputStream newOutputStream(Set<? extends OpenOption> options,
+                                                 FileAttribute<?>... attrs)
+        throws IOException;
+
+    /**
+     * Tells whether or not the file located by this object is considered
+     * <em>hidden</em>. 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.
+     *
+     * <p> 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;
+
+    /**
+     * Tests whether the file located by this path exists.
+     *
+     * <p> 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.
+     *
+     * <p> 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.
+     *
+     * <p> 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.
+     *
+     * <p> 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();
+
+    // -- watchable --
+
+    /**
+     * Registers the file located by this path with a watch service.
+     *
+     * <p> 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:
+     * <ul>
+     *   <li>{@link StandardWatchEventKind#ENTRY_CREATE ENTRY_CREATE} -
+     *       entry created or moved into the directory</li>
+     *   <li>{@link StandardWatchEventKind#ENTRY_DELETE ENTRY_DELETE} -
+     *        entry deleted or moved out of the directory</li>
+     *   <li>{@link StandardWatchEventKind#ENTRY_MODIFY ENTRY_MODIFY} -
+     *        entry in directory was modified</li>
+     * </ul>
+     *
+     * <p> The {@link WatchEvent#context context} for these events is the
+     * relative path between the directory located by this path, and the path
+     * that locates the directory entry that is created, deleted, or modified.
+     *
+     * <p> The set of events may include additional implementation specific
+     * event that are not defined by the enum {@link StandardWatchEventKind}
+     *
+     * <p> The {@code modifiers} parameter is an array of <em>modifiers</em>
+     * that qualify how the directory is registered. This release does not
+     * define any <em>standard</em> modifiers. The array may contain
+     * implementation specific modifiers.
+     *
+     * <p> 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
+     * on the existence of the link after it is registered.
+     *
+     * @param   watcher
+     *          The watch service to which this object is to be registered
+     * @param   events
+     *          The events for which this object should be registered
+     * @param   modifiers
+     *          The modifiers, if any, that modify how the object is registered
+     *
+     * @return  A key representing the registration of this object with the
+     *          given watch service
+     *
+     * @throws  UnsupportedOperationException
+     *          If unsupported events or modifiers are specified
+     * @throws  IllegalArgumentException
+     *          If an invalid combination of events or modifiers is specified
+     * @throws  ClosedWatchServiceException
+     *          If the watch service is closed
+     * @throws  NotDirectoryException
+     *          If the file is registered to watch the entries in a directory
+     *          and the file is not a directory  <i>(optional specific exception)</i>
+     * @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.
+     */
+    @Override
+    public abstract WatchKey register(WatchService watcher,
+                                      WatchEvent.Kind<?>[] events,
+                                      WatchEvent.Modifier... modifiers)
+        throws IOException;
+
+    /**
+     * Registers the file located by this path with a watch service.
+     *
+     * <p> An invocation of this method behaves in exactly the same way as the
+     * invocation
+     * <pre>
+     *     watchable.{@link #register(WatchService,WatchEvent.Kind[],WatchEvent.Modifier[]) register}(watcher, events, new WatchEvent.Modifier[0]);
+     * </pre>
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we wish to register a directory for entry create, delete, and modify
+     * events:
+     * <pre>
+     *     Path dir = ...
+     *     WatchService watcher = ...
+     *
+     *     WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
+     * </pre>
+     * @param   watcher
+     *          The watch service to which this object is to be registered
+     * @param   events
+     *          The events for which this object should be registered
+     *
+     * @return  A key representing the registration of this object with the
+     *          given watch service
+     *
+     * @throws  UnsupportedOperationException
+     *          If unsupported events are specified
+     * @throws  IllegalArgumentException
+     *          If an invalid combination of events is specified
+     * @throws  ClosedWatchServiceException
+     *          If the watch service is closed
+     * @throws  NotDirectoryException
+     *          If the file is registered to watch the entries in a directory
+     *          and the file is not a directory  <i>(optional specific exception)</i>
+     * @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.
+     */
+    @Override
+    public abstract WatchKey register(WatchService watcher,
+                                      WatchEvent.Kind<?>... events)
+        throws IOException;
+
+    // -- Iterable --
+
+    /**
+     * Returns an iterator over the name elements of this path.
+     *
+     * <p> The first element returned by the iterator represents the name
+     * element that is closest to the root in the directory hierarchy, the
+     * second element is the next closest, and so on. The last element returned
+     * is the name of the file or directory denoted by this path. The {@link
+     * #getRoot root} component, if present, is not returned by the iterator.
+     *
+     * @return  An iterator over the name elements of this path.
+     */
+    @Override
+    public abstract Iterator<Path> iterator();
+
+    // -- compareTo/equals/hashCode --
+
+    /**
+     * Compares two abstract paths lexicographically. The ordering defined by
+     * this method is provider specific, and in the case of the default
+     * provider, platform specific. This method does not access the file system
+     * and neither file is required to exist.
+     *
+     * @param   other  The path compared to this path.
+     *
+     * @return  Zero if the argument is {@link #equals equal} to this path, a
+     *          value less than zero if this path is lexicographically less than
+     *          the argument, or a value greater than zero if this path is
+     *          lexicographically greater than the argument
+     */
+    @Override
+    public abstract int compareTo(Path other);
+
+    /**
+     * Tests this path for equality with the given object.
+     *
+     * <p> If the given object is not a Path, or is a Path associated with a
+     * different provider, then this method immediately returns {@code false}.
+     *
+     * <p> 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.
+     *
+     * <p> This method satisfies the general contract of the {@link
+     * java.lang.Object#equals(Object) Object.equals} method. </p>
+     *
+     * @param   ob
+     *          The object to which this object is to be compared
+     *
+     * @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 ob);
+
+    /**
+     * Computes a hash code for this path.
+     *
+     * <p> The hash code is based upon the components of the path, and
+     * satisfies the general contract of the {@link Object#hashCode
+     * Object.hashCode} method.
+     *
+     * @return  The hash-code value for this Path
+     */
+    @Override
+    public abstract int hashCode();
+
+    /**
+     * Returns the string representation of this path.
+     *
+     * <p> If this path was created by converting a path string using the
+     * {@link FileSystem#getPath getPath} method then the path string returned
+     * by this method may differ from the original String used to create the path.
+     *
+     * <p> The returned path string uses the default name {@link
+     * FileSystem#getSeparator separator} to separate names in the path.
+     *
+     * @return  The string representation of this path
+     */
+    @Override
+    public abstract String toString();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/PathMatcher.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * An interface that is implemented by objects that perform match operations on
+ * paths.
+ *
+ * @since 1.7
+ *
+ * @see FileSystem#getPathMatcher
+ * @see Path#newDirectoryStream(String)
+ */
+
+public interface PathMatcher {
+    /**
+     * Tells if given path matches this matcher's pattern.
+     *
+     * @param   path
+     *          The path to match
+     *
+     * @return  {@code true} if, and only if, the path matches this
+     *          matcher's pattern
+     */
+    boolean matches(Path path);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/Paths.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.spi.FileSystemProvider;
+import java.net.URI;
+
+/**
+ * This class consists exclusively of static methods that return a {@link Path}
+ * by converting a path string or {@link URI}.
+ *
+ * @since 1.7
+ */
+
+public class Paths {
+    private Paths() { }
+
+    /**
+     * Constructs a {@code Path} by converting the given path string.
+     *
+     * <p> The {@code Path} is obtained by invoking the {@link FileSystem#getPath
+     * getPath} method of the {@link FileSystems#getDefault default} {@link
+     * FileSystem}.
+     *
+     * @param   path
+     *          The path string to convert
+     *
+     * @return  The resulting {@code Path}
+     *
+     * @throws  InvalidPathException
+     *          If the path string cannot be converted to a {@code Path}
+     *
+     * @see FileSystem#getPath
+     */
+    public static Path get(String path) {
+        return FileSystems.getDefault().getPath(path);
+    }
+
+    /**
+     * Converts the given URI to a {@link Path} object.
+     *
+     * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
+     * installed} providers to locate the provider that is identified by the
+     * URI {@link URI#getScheme scheme} of the given URI. URI schemes are
+     * compared without regard to case. If the provider is found then its {@link
+     * FileSystemProvider#getPath getPath} method is invoked to convert the
+     * URI.
+     *
+     * <p> In the case of the default provider, identified by the URI scheme
+     * "file", the given URI has a non-empty path component, and undefined query
+     * and fragment components. Whether the authority component may be present
+     * is platform specific. The returned {@code Path} is associated with the
+     * {@link FileSystems#getDefault default} file system.
+     *
+     * <p> The default provider provides a similar <em>round-trip</em> guarantee
+     * to the {@link java.io.File} class. For a given {@code Path} <i>p</i> it
+     * is guaranteed that
+     * <blockquote><tt>
+     * Paths.get(</tt><i>p</i><tt>.{@link Path#toUri() toUri}()).equals(</tt>
+     * <i>p</i><tt>.{@link Path#toAbsolutePath() toAbsolutePath}())</tt>
+     * </blockquote>
+     * so long as the original {@code Path}, the {@code URI}, and the new {@code
+     * Path} are all created in (possibly different invocations of) the same
+     * Java virtual machine. Whether other providers make any guarantees is
+     * provider specific and therefore unspecified.
+     *
+     * @param   uri
+     *          The URI to convert
+     *
+     * @return  The resulting {@code Path}
+     *
+     * @throws  IllegalArgumentException
+     *          If preconditions on the {@code uri} parameter do not hold. The
+     *          format of the URI is provider specific.
+     * @throws  FileSystemNotFoundException
+     *          If the file system identified by the URI does not exist or the
+     *          provider identified by the URI's scheme component is not installed
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission to access the file system
+     */
+    public static Path get(URI uri) {
+        String scheme =  uri.getScheme();
+        if (scheme == null)
+            throw new IllegalArgumentException("Missing scheme");
+
+        // check for default provider to avoid loading of installed providers
+        if (scheme.equalsIgnoreCase("file"))
+            return FileSystems.getDefault().provider().getPath(uri);
+
+        // try to find provider
+        for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
+            if (provider.getScheme().equalsIgnoreCase(scheme)) {
+                return provider.getPath(uri);
+            }
+        }
+
+        throw new FileSystemNotFoundException("Provider \"" + scheme + "\" not installed");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/ProviderMismatchException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Unchecked exception thrown when an attempt is made to invoke a method on an
+ * object created by one file system provider with a parameter created by a
+ * different file system provider.
+ */
+public class ProviderMismatchException
+    extends java.lang.IllegalArgumentException
+{
+    static final long serialVersionUID = 4990847485741612530L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ProviderMismatchException() {
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   msg
+     *          The detail message
+     */
+    public ProviderMismatchException(String msg) {
+        super(msg);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/ProviderNotFoundException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Runtime exception thrown when a provider of the required type cannot be found.
+ */
+
+public class ProviderNotFoundException
+    extends RuntimeException
+{
+    static final long serialVersionUID = -1880012509822920354L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ProviderNotFoundException() {
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   msg
+     *          The detail message
+     */
+    public ProviderNotFoundException(String msg) {
+        super(msg);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/ReadOnlyFileSystemException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Unchecked exception thrown when an attempt is made to update an object
+ * associated with a {@link FileSystem#isReadOnly() read-only} {@code FileSystem}.
+ */
+
+public class ReadOnlyFileSystemException
+    extends UnsupportedOperationException
+{
+    static final long serialVersionUID = -6822409595617487197L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ReadOnlyFileSystemException() {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/SecureDirectoryStream.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,324 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classname" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package java.nio.file;
+
+import java.nio.file.attribute.*;
+import java.nio.channels.SeekableByteChannel;
+import java.util.Set;
+import java.io.IOException;
+
+/**
+ * A {@code DirectoryStream} that defines operations on files that are located
+ * relative to an open directory. A {@code SecureDirectoryStream} is intended
+ * for use by sophisticated or security sensitive applications requiring to
+ * traverse file trees or otherwise operate on directories in a race-free manner.
+ * Race conditions can arise when a sequence of file operations cannot be
+ * carried out in isolation. Each of the file operations defined by this
+ * interface specify a relative {@link Path}. All access to the file is relative
+ * to the open directory irrespective of if the directory is moved or replaced
+ * by an attacker while the directory is open. A {@code SecureDirectoryStream}
+ * may also be used as a virtual <em>working directory</em>.
+ *
+ * <p> 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
+ * newDirectoryStream} method will be a {@code SecureDirectoryStream} and must
+ * be cast to that type in order to invoke the methods defined by this interface.
+ *
+ * <p> As specified by {@code DirectoryStream}, the iterator's {@link
+ * java.util.Iterator#remove() remove} method removes the directory entry for
+ * the last element returned by the iterator. In the case of a {@code
+ * SecureDirectoryStream} the {@code remove} method behaves as if by invoking
+ * the {@link #deleteFile deleteFile} or {@link #deleteDirectory deleteDirectory}
+ * methods defined by this interface. The {@code remove} may require to examine
+ * the file to determine if the file is a directory, and consequently, it may
+ * not be atomic with respect to other file system operations.
+ *
+ * <p> In the case of the default {@link java.nio.file.spi.FileSystemProvider
+ * provider}, and a security manager is set, then the permission checks are
+ * performed using the path obtained by resolving the given relative path
+ * against the <i>original path</i> of the directory (irrespective of if the
+ * directory is moved since it was opened).
+ *
+ * @since   1.7
+ */
+
+public abstract class SecureDirectoryStream
+    implements DirectoryStream<Path>
+{
+    /**
+     * 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.
+     *
+     * <p> This method works in exactly the manner specified by the {@link
+     * Path#newDirectoryStream 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 {@code followLinks} parameter
+     * determines if links should be followed. If this parameter is {@code
+     * false} and the file is a symbolic link then this method fails (by
+     * throwing an I/O exception).
+     *
+     * <p> The new directory stream, once created, is not dependent upon the
+     * directory stream used to create it. Closing this directory stream has no
+     * effect upon newly created directory stream.
+     *
+     * @param   path
+     *          The path to the directory to open
+     * @param   followLinks
+     *          {@code true} if the links should be followed
+     * @param   filter
+     *          The directory stream filter or {@code null}.
+     *
+     * @return  A new and open {@code SecureDirectoryStream} object
+     *
+     * @throws  ClosedDirectoryStreamException
+     *          If the directory stream is closed
+     * @throws  NotDirectoryException
+     *          If the file could not otherwise be opened because it is not
+     *          a directory <i>(optional specific exception)</i>
+     * @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 SecureDirectoryStream newDirectoryStream(Path path,
+                                                             boolean followLinks,
+                                                             DirectoryStream.Filter<? super Path> filter)
+        throws IOException;
+
+    /**
+     * Opens or creates a file in this directory, returning a seekable byte
+     * channel to access the file.
+     *
+     * <p> This method works in exactly the manner specified by the {@link
+     * Path#newByteChannel Path.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
+     * LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} option may be used to
+     * ensure that this method fails if the file is a symbolic link.
+     *
+     * <p> The channel, once created, is not dependent upon the directory stream
+     * used to create it. Closing this directory stream has no effect upon the
+     * channel.
+     *
+     * @param   path
+     *          The path of the file to open open or create
+     * @param   options
+     *          Options specifying how the file is opened
+     * @param   attrs
+     *          An optional list of attributes to set atomically when creating
+     *          the file
+     *
+     * @throws  ClosedDirectoryStreamException
+     *          If the directory stream is closed
+     * @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
+     *          <i>(optional specific exception)</i>
+     * @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(Path path,
+                                                       Set<? extends OpenOption> options,
+                                                       FileAttribute<?>... attrs)
+        throws IOException;
+
+    /**
+     * Deletes a file.
+     *
+     * <p> Unlike the {@link FileRef#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 is
+     * deleted (not the final target of the link). When the parameter is a
+     * relative path then the file to delete is relative to this open directory.
+     *
+     * @param   path
+     *          The path of the file to delete
+     *
+     * @throws  ClosedDirectoryStreamException
+     *          If the directory stream is closed
+     * @throws  NoSuchFileException
+     *          If the the file does not exist <i>(optional specific exception)</i>
+     * @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) checkDelete}
+     *          method is invoked to check delete access to the file
+     */
+    public abstract void deleteFile(Path path) throws IOException;
+
+    /**
+     * Deletes a directory.
+     *
+     * <p> Unlike the {@link FileRef#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
+     * directory to delete is relative to this open directory.
+     *
+     * @param   path
+     *          The path of the directory to delete
+     *
+     * @throws  ClosedDirectoryStreamException
+     *          If the directory stream is closed
+     * @throws  NoSuchFileException
+     *          If the the directory does not exist <i>(optional specific exception)</i>
+     * @throws  DirectoryNotEmptyException
+     *          If the directory could not otherwise be deleted because it is
+     *          not empty <i>(optional specific exception)</i>
+     * @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) checkDelete}
+     *          method is invoked to check delete access to the directory
+     */
+    public abstract void deleteDirectory(Path path) throws IOException;
+
+    /**
+     * Move a file from this directory to another directory.
+     *
+     * <p> This method works in a similar manner to {@link Path#moveTo moveTo}
+     * 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
+     * absolute} path then it locates the source file. If the parameter is a
+     * relative path then it is located relative to this open directory. If
+     * the {@code targetpath} parameter is absolute then it locates the target
+     * file (the {@code targetdir} parameter is ignored). If the parameter is
+     * a relative path it is located relative to the open directory identified
+     * by the {@code targetdir} parameter. In all cases, if the target file
+     * exists then it is implementation specific if it is replaced or this
+     * method fails.
+     *
+     * @param   srcpath
+     *          The name of the file to move
+     * @param   targetdir
+     *          The destination directory
+     * @param   targetpath
+     *          The name to give the file in the destination directory
+     *
+     * @throws  ClosedDirectoryStreamException
+     *          If this or the target directory stream is closed
+     * @throws  FileAlreadyExistsException
+     *          The file already exists in the target directory and cannot
+     *          be replaced <i>(optional specific exception)</i>
+     * @throws  AtomicMoveNotSupportedException
+     *          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 srcpath, SecureDirectoryStream targetdir, Path targetpath)
+        throws IOException;
+
+    /**
+     * Returns a new file attribute view to access the file attributes of this
+     * directory.
+     *
+     * <p> The resulting file attribute view can be used to read or update the
+     * attributes of this (open) directory. The {@code type} parameter specifies
+     * the type of the attribute view and the method returns an instance of that
+     * type if supported. Invoking this method to obtain a {@link
+     * BasicFileAttributeView} always returns an instance of that class that is
+     * bound to this open directory.
+     *
+     * <p> The state of resulting file attribute view is intimately connected
+     * to this directory stream. Once the directory stream is {@link #close closed},
+     * then all methods to read or update attributes will throw {@link
+     * ClosedDirectoryStreamException ClosedDirectoryStreamException}.
+     *
+     * @param   type
+     *          The {@code Class} object corresponding to the file attribute view
+     *
+     * @return  A new file attribute view of the specified type bound to
+     *          this directory stream, or {@code null} if the attribute view
+     *          type is not available
+     */
+    public abstract <V extends FileAttributeView> V getFileAttributeView(Class<V> type);
+
+    /**
+     * Returns a new file attribute view to access the file attributes of a file
+     * in this directory.
+     *
+     * <p> The resulting file attribute view can be used to read or update the
+     * attributes of file in this directory. The {@code type} parameter specifies
+     * the type of the attribute view and the method returns an instance of that
+     * type if supported. Invoking this method to obtain a {@link
+     * BasicFileAttributeView} always returns an instance of that class that is
+     * bound to the file in the directory.
+     *
+     * <p> The state of resulting file attribute view is intimately connected
+     * to this directory stream. Once the directory stream {@link #close closed},
+     * then all methods to read or update attributes will throw {@link
+     * ClosedDirectoryStreamException ClosedDirectoryStreamException}. The
+     * file is not required to exist at the time that the file attribute view
+     * is created but methods to read or update attributes of the file will
+     * fail when invoked and the file does not exist.
+     *
+     * @param   path
+     *          The path of 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 new file attribute view of the specified type bound to a
+     *          this directory stream, or {@code null} if the attribute view
+     *          type is not available
+     *
+     */
+    public abstract <V extends FileAttributeView> V getFileAttributeView(Path path,
+                                                                         Class<V> type,
+                                                                         LinkOption... options);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/SimpleFileVisitor.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.attribute.BasicFileAttributes;
+import java.io.IOException;
+import java.io.IOError;
+
+/**
+ * A simple visitor of files with default behavior to visit all files and to
+ * re-throw I/O errors.
+ *
+ * <p> Methods in this class may be overridden subject to their general contract.
+ *
+ * @param   <T>     The type of reference to the files
+ *
+ * @since 1.7
+ */
+
+public class SimpleFileVisitor<T extends FileRef> implements FileVisitor<T> {
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected SimpleFileVisitor() {
+    }
+
+    /**
+     * Invoked for a directory before entries in the directory are visited.
+     *
+     * <p> Unless overridden, this method returns {@link FileVisitResult#CONTINUE
+     * CONTINUE}.
+     */
+    @Override
+    public FileVisitResult preVisitDirectory(T dir) {
+        return FileVisitResult.CONTINUE;
+    }
+
+    /**
+     * Invoked for a directory that could not be opened.
+     *
+     * <p> Unless overridden, this method throws {@link IOError} with the I/O
+     * exception as cause.
+     *
+     * @throws  IOError
+     *          With the I/O exception thrown when the attempt to open the
+     *          directory failed
+     */
+    @Override
+    public FileVisitResult preVisitDirectoryFailed(T dir, IOException exc) {
+        throw new IOError(exc);
+    }
+
+    /**
+     * Invoked for a file in a directory.
+     *
+     * <p> Unless overridden, this method returns {@link FileVisitResult#CONTINUE
+     * CONTINUE}.
+     */
+    @Override
+    public FileVisitResult visitFile(T file, BasicFileAttributes attrs) {
+        return FileVisitResult.CONTINUE;
+    }
+
+    /**
+     * Invoked for a file when its basic file attributes could not be read.
+     *
+     * <p> Unless overridden, this method throws {@link IOError} with the I/O
+     * exception as cause.
+     *
+     * @throws  IOError
+     *          With the I/O exception thrown when the attempt to read the file
+     *          attributes failed
+     */
+    @Override
+    public FileVisitResult visitFileFailed(T file, IOException exc) {
+        throw new IOError(exc);
+    }
+
+    /**
+     * Invoked for a directory after entries in the directory, and all of their
+     * descendants, have been visited.
+     *
+     * <p> Unless overridden, this method returns {@link FileVisitResult#CONTINUE
+     * CONTINUE} if the directory iteration completes without an I/O exception;
+     * otherwise this method throws {@link IOError} with the I/O exception as
+     * cause.
+     *
+     * @throws  IOError
+     *          If iteration of the directory completed prematurely due to an
+     *          I/O error
+     */
+    @Override
+    public FileVisitResult postVisitDirectory(T dir, IOException exc) {
+        if (exc != null)
+            throw new IOError(exc);
+        return FileVisitResult.CONTINUE;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/StandardCopyOption.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Defines the standard copy options.
+ *
+ * @since 1.7
+ */
+
+public enum StandardCopyOption implements CopyOption {
+    /**
+     * Replace an existing file if it exists.
+     */
+    REPLACE_EXISTING,
+    /**
+     * Copy attributes to the new file.
+     */
+    COPY_ATTRIBUTES,
+    /**
+     * Move the file as an atomic file system operation.
+     */
+    ATOMIC_MOVE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/StandardOpenOption.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Defines the standard open options.
+ *
+ * @since 1.7
+ */
+
+public enum StandardOpenOption implements OpenOption {
+    /**
+     * Open for read access.
+     */
+    READ,
+
+    /**
+     * Open for write access.
+     */
+    WRITE,
+
+    /**
+     * If the file is opened for {@link #WRITE} access then bytes will be written
+     * to the end of the file rather than the beginning.
+     *
+     * <p> If the file is opened for write access by other programs, then it
+     * is file system specific if writing to the end of the file is atomic.
+     */
+    APPEND,
+
+    /**
+     * If the file already exists and it is opened for {@link #WRITE}
+     * access, then its length is truncated to 0. This option is ignored
+     * if the file is opened only for {@link #READ} access.
+     */
+    TRUNCATE_EXISTING,
+
+    /**
+     * Create a new file if it does not exist.
+     * This option is ignored if the {@link #CREATE_NEW} option is also set.
+     * 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.
+     */
+    CREATE,
+
+    /**
+     * Create a new file, failing if the file already exists.
+     * 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.
+     */
+    CREATE_NEW,
+
+    /**
+     * Delete on close. When this option is present then the implementation
+     * makes a <em>best effort</em> attempt to delete the file when closed
+     * by the appropriate {@code close} method. If the {@code close} method is
+     * not invoked then a <em>best effort</em> attempt is made to delete the
+     * file when the Java virtual machine terminates (either normally, as
+     * defined by the Java Language Specification, or where possible, abnormally).
+     * This option is primarily intended for use with <em>work files</em> that
+     * are used solely by a single instance of the Java virtual machine. This
+     * option is not recommended for use when opening files that are open
+     * concurrently by other entities. Many of the details as to when and how
+     * the file is deleted are implementation specific and therefore not
+     * specified. In particular, an implementation may be unable to guarantee
+     * that it deletes the expected file when replaced by an attacker while the
+     * file is open. Consequently, security sensitive applications should take
+     * care when using this option.
+     *
+     * <p> For security reasons, this option may imply the {@link
+     * LinkOption#NOFOLLOW_LINKS} option. In other words, if the option is present
+     * when opening an existing file that is a symbolic link then it may fail
+     * (by throwing {@link java.io.IOException}).
+     */
+    DELETE_ON_CLOSE,
+
+    /**
+     * Sparse file. When used with the {@link #CREATE_NEW} option then this
+     * option provides a <em>hint</em> that the new file will be sparse. The
+     * option is ignored when the file system does not support the creation of
+     * sparse files.
+     */
+    SPARSE,
+
+    /**
+     * Requires that every update to the file's content or metadata be written
+     * synchronously to the underlying storage device.
+     *
+     * @see <a href="package-summary.html#integrity">Synchronized I/O file integrity</a>
+     */
+    SYNC,
+
+    /**
+     * Requires that every update to the file's content be written
+     * synchronously to the underlying storage device.
+     *
+     * @see <a href="package-summary.html#integrity">Synchronized I/O file integrity</a>
+     */
+    DSYNC;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/StandardWatchEventKind.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Defines the <em>standard</em> event kinds.
+ *
+ * @since 1.7
+ */
+
+public class StandardWatchEventKind {
+    private StandardWatchEventKind() { }
+
+    /**
+     * A special event to indicate that events may have been lost or
+     * discarded.
+     *
+     * <p> The {@link WatchEvent#context context} for this event is
+     * implementation specific and may be {@code null}. The event {@link
+     * WatchEvent#count count} may be greater than {@code 1}.
+     *
+     * @see WatchService
+     */
+    public static final WatchEvent.Kind<Void> OVERFLOW =
+        new StdWatchEventKind<Void>("OVERFLOW", Void.class);
+
+    /**
+     * Directory entry created.
+     *
+     * <p> When a directory is registered for this event then the {@link WatchKey}
+     * is queued when it is observed that an entry is created in the directory
+     * or renamed into the directory. The event {@link WatchEvent#count count}
+     * for this event is always {@code 1}.
+     */
+    public static final WatchEvent.Kind<Path> ENTRY_CREATE =
+        new StdWatchEventKind<Path>("ENTRY_CREATE", Path.class);
+
+    /**
+     * Directory entry deleted.
+     *
+     * <p> When a directory is registered for this event then the {@link WatchKey}
+     * is queued when it is observed that an entry is deleted or renamed out of
+     * the directory. The event {@link WatchEvent#count count} for this event
+     * is always {@code 1}.
+     */
+    public static final WatchEvent.Kind<Path> ENTRY_DELETE =
+        new StdWatchEventKind<Path>("ENTRY_DELETE", Path.class);
+
+    /**
+     * Directory entry modified.
+     *
+     * <p> When a directory is registered for this event then the {@link WatchKey}
+     * is queued when it is observed that an entry in the directory has been
+     * modified. The event {@link WatchEvent#count count} for this event is
+     * {@code 1} or greater.
+     */
+    public static final WatchEvent.Kind<Path> ENTRY_MODIFY =
+        new StdWatchEventKind<Path>("ENTRY_MODIFY", Path.class);
+
+    private static class StdWatchEventKind<T> implements WatchEvent.Kind<T> {
+        private final String name;
+        private final Class<T> type;
+        StdWatchEventKind(String name, Class<T> type) {
+            this.name = name;
+            this.type = type;
+        }
+        @Override public String name() { return name; }
+        @Override public Class<T> type() { return type; }
+        @Override public String toString() { return name; }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/WatchEvent.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * An event or a repeated event for an object that is registered with a {@link
+ * WatchService}.
+ *
+ * <p> An event is classified by its {@link #kind() kind} and has a {@link
+ * #count() count} to indicate the number of times that the event has been
+ * observed. This allows for efficient representation of repeated events. The
+ * {@link #context() context} method returns any context associated with
+ * the event. In the case of a repeated event then the context is the same for
+ * all events.
+ *
+ * <p> Watch events are immutable and safe for use by multiple concurrent
+ * threads.
+ *
+ * @param   <T>     The type of the context object associated with the event
+ *
+ * @since 1.7
+ */
+
+public abstract class WatchEvent<T> {
+
+    /**
+     * An event kind, for the purposes of identification.
+     *
+     * @since 1.7
+     * @see StandardWatchEventKind
+     */
+    public static interface Kind<T> {
+        /**
+         * Returns the name of the event kind.
+         */
+        String name();
+
+        /**
+         * Returns the type of the {@link WatchEvent#context context} value.
+         */
+        Class<T> 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}.
+     *
+     * <p> This release does not define any <em>standard</em> modifiers.
+     *
+     * @since 1.7
+     * @see Watchable#register
+     */
+    public static interface Modifier {
+        /**
+         * Returns the name of the modifier.
+         */
+        String name();
+    }
+
+    /**
+     * Returns the event kind.
+     *
+     * @return  The event kind
+     */
+    public abstract Kind<T> kind();
+
+    /**
+     * Returns the event count. If the event count is greater than {@code 1}
+     * then this is a repeated event.
+     *
+     * @return  The event count
+     */
+    public abstract int count();
+
+    /**
+     * Returns the context for the event.
+     *
+     * <p> In the case of {@link StandardWatchEventKind#ENTRY_CREATE ENTRY_CREATE},
+     * {@link StandardWatchEventKind#ENTRY_DELETE ENTRY_DELETE}, and {@link
+     * StandardWatchEventKind#ENTRY_MODIFY ENTRY_MODIFY} events the context is
+     * a {@code Path} that is the {@link Path#relativize relative} path between
+     * the directory registered with the watch service, and the entry that is
+     * created, deleted, or modified.
+     *
+     * @return  The event context; may be {@code null}
+     */
+    public abstract T context();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/WatchKey.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.util.List;
+
+/**
+ * A token representing the registration of a {@link Watchable watchable} object
+ * with a {@link WatchService}.
+ *
+ * <p> A watch key is created when a watchable object is registered with a watch
+ * service. The key remains {@link #isValid valid} until:
+ * <ol>
+ *   <li> It is cancelled, explicitly, by invoking its {@link #cancel cancel}
+ *     method, or</li>
+ *   <li> Cancelled implicitly, because the object is no longer accessible,
+ *     or </li>
+ *   <li> By {@link WatchService#close closing} the watch service. </li>
+ * </ol>
+ *
+ * <p> A watch key has a state. When initially created the key is said to be
+ * <em>ready</em>. When an event is detected then the key is <em>signalled</em>
+ * and queued so that it can be retrieved by invoking the watch service's {@link
+ * WatchService#poll() poll} or {@link WatchService#take() take} methods. Once
+ * signalled, a key remains in this state until its {@link #reset reset} method
+ * is invoked to return the key to the ready state. Events detected while the
+ * key is in the signalled state are queued but do not cause the key to be
+ * re-queued for retrieval from the watch service. Events are retrieved by
+ * invoking the key's {@link #pollEvents pollEvents} method. This method
+ * retrieves and removes all events accumulated for the object. When initially
+ * created, a watch key has no pending events. Typically events are retrieved
+ * when the key is in the signalled state leading to the following idiom:
+ *
+ * <pre>
+ *     for (;;) {
+ *         // retrieve key
+ *         WatchKey key = watcher.take();
+ *
+ *         // process events
+ *         for (WatchEvent&lt;?&gt; event: key.pollEvents()) {
+ *             :
+ *         }
+ *
+ *         // reset the key
+ *         boolean valid = key.reset();
+ *         if (!valid) {
+ *             // object no longer registered
+ *         }
+ *     }
+ * </pre>
+ *
+ * <p> Watch keys are safe for use by multiple concurrent threads. Where there
+ * are several threads retrieving signalled keys from a watch service then care
+ * should be taken to ensure that the {@code reset} method is only invoked after
+ * the events for the object have been processed. This ensures that one thread
+ * is processing the events for an object at any time.
+ *
+ * @since 1.7
+ */
+
+public abstract class WatchKey {
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected WatchKey() { }
+
+    /**
+     * Tells whether or not this watch key is valid.
+     *
+     * <p> A watch key is valid upon creation and remains until it is cancelled,
+     * or its watch service is closed.
+     *
+     * @return  {@code true} if, and only if, this watch key is valid
+     */
+    public abstract boolean isValid();
+
+    /**
+     * Retrieves and removes all pending events for this watch key, returning
+     * a {@code List} of the events that were retrieved.
+     *
+     * <p> Note that this method does not wait if there are no events pending.
+     *
+     * @return  The list of the events retrieved
+     */
+    public abstract List<WatchEvent<?>> pollEvents();
+
+    /**
+     * Resets this watch key.
+     *
+     * <p> If this watch key has been cancelled or this watch key is already in
+     * the ready state then invoking this method has no effect. Otherwise
+     * if there are pending events for the object then this watch key is
+     * immediately re-queued to the watch service. If there are no pending
+     * events then the watch key is put into the ready state and will remain in
+     * that state until an event is detected or the watch key is cancelled.
+     *
+     * @return  {@code true} if the watch key is valid and has been reset;
+     *          {@code false} if the watch key could not be reset because it is
+     *          no longer {@link #isValid valid}
+     */
+    public abstract boolean reset();
+
+    /**
+     * Cancels the registration with the watch service. Upon return the watch key
+     * will be invalid. If the watch key is enqueued, waiting to be retrieved
+     * from the watch service, then it will remain in the queue until it is
+     * removed. Pending events, if any, remain pending and may be retrieved by
+     * invoking the {@link #pollEvents pollEvents} method event after the key is
+     * cancelled.
+     *
+     * <p> 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();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/WatchService.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A watch service that <em>watches</em> registered objects for changes and
+ * events. For example a file manager may use a watch service to monitor a
+ * directory for changes so that it can update its display of the list of files
+ * when files are created or deleted.
+ *
+ * <p> A {@link Watchable} object is registered with a watch service by invoking
+ * its {@link Watchable#register register} method, returning a {@link WatchKey}
+ * to represent the registration. When an event for an object is detected the
+ * key is <em>signalled</em>, and if not currently signalled, it is queued to
+ * the watch service so that it can be retrieved by consumers that invoke the
+ * {@link #poll() poll} or {@link #take() take} methods to retrieve keys
+ * and process events. Once the events have been processed the consumer
+ * invokes the key's {@link WatchKey#reset reset} method to reset the key which
+ * allows the key to be signalled and re-queued with further events.
+ *
+ * <p> Registration with a watch service is cancelled by invoking the key's
+ * {@link WatchKey#cancel cancel} method. A key that is queued at the time that
+ * it is cancelled remains in the queue until it is retrieved. Depending on the
+ * object, a key may be cancelled automatically. For example, suppose a
+ * directory is watched and the watch service detects that it has been deleted
+ * or its file system is no longer accessible. When a key is cancelled in this
+ * manner it is signalled and queued, if not currently signalled. To ensure
+ * that the consumer is notified the return value from the {@code reset}
+ * method indicates if the key is valid.
+ *
+ * <p> A watch service is safe for use by multiple concurrent consumers. To
+ * ensure that only one consumer processes the events for a particular object at
+ * any time then care should be taken to ensure that the key's {@code reset}
+ * method is only invoked after its events have been processed. The {@link
+ * #close close} method may be invoked at any time to close the service causing
+ * any threads waiting to retrieve keys, to throw {@code
+ * ClosedWatchServiceException}.
+ *
+ * <p> File systems may report events faster than they can be retrieved or
+ * processed and an implementation may impose an unspecified limit on the number
+ * of events that it may accumulate. Where an implementation <em>knowingly</em>
+ * discards events then it arranges for the key's {@link WatchKey#pollEvents
+ * pollEvents} method to return an element with an event type of {@link
+ * StandardWatchEventKind#OVERFLOW OVERFLOW}. This event can be used by the
+ * consumer as a trigger to re-examine the state of the object.
+ *
+ * <p> When an event is reported to indicate that a file in a watched directory
+ * has been modified then there is no guarantee that the program (or programs)
+ * that have modified the file have completed. Care should be taken to coordinate
+ * access with other programs that may be updating the file.
+ * The {@link java.nio.channels.FileChannel FileChannel} class defines methods
+ * to lock regions of a file against access by other programs.
+ *
+ * <h4>Platform dependencies</h4>
+ *
+ * <p> The implementation that observes events from the file system is intended
+ * to map directly on to the native file event notification facility where
+ * available, or to use a primitive mechanism, such as polling, when a native
+ * facility is not available. Consequently, many of the details on how events
+ * are detected, their timeliness, and whether their ordering is preserved are
+ * highly implementation specific. For example, when a file in a watched
+ * directory is modified then it may result in a single {@link
+ * StandardWatchEventKind#ENTRY_MODIFY ENTRY_MODIFY} event in some
+ * implementations but several events in other implementations. Short-lived
+ * files (meaning files that are deleted very quickly after they are created)
+ * may not be detected by primitive implementations that periodically poll the
+ * file system to detect changes.
+ *
+ * <p> If a watched file is not located on a local storage device then it is
+ * implementation specific if changes to the file can be detected. In particular,
+ * it is not required that changes to files carried out on remote systems be
+ * detected.
+ *
+ * @since 1.7
+ *
+ * @see FileSystem#newWatchService
+ */
+
+public abstract class WatchService
+    implements Closeable
+{
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected WatchService() { }
+
+    /**
+     * Closes this watch service.
+     *
+     * <p> If a thread is currently blocked in the {@link #take take} or {@link
+     * #poll(long,TimeUnit) poll} methods waiting for a key to be queued then
+     * it immediately receives a {@link ClosedWatchServiceException}. Any
+     * valid keys associated with this watch service are {@link WatchKey#isValid
+     * invalidated}.
+     *
+     * <p> After a watch service is closed, any further attempt to invoke
+     * operations upon it will throw {@link ClosedWatchServiceException}.
+     * If this watch service is already closed then invoking this method
+     * has no effect.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    @Override
+    public abstract void close() throws IOException;
+
+    /**
+     * Retrieves and removes the next watch key, or {@code null} if none are
+     * present.
+     *
+     * @return  The next watch key, or {@code null}
+     *
+     * @throws  ClosedWatchServiceException
+     *          If this watch service is closed
+     */
+    public abstract WatchKey poll();
+
+    /**
+     * Retrieves and removes the next watch key, waiting if necessary up to the
+     * specified wait time if none are yet present.
+     *
+     * @param   timeout
+     *          how to wait before giving up, in units of unit
+     * @param   unit
+     *          a {@code TimeUnit} determining how to interpret the timeout
+     *          parameter
+     *
+     * @return  The next watch key, or {@code null}
+     *
+     * @throws  ClosedWatchServiceException
+     *          If this watch service is closed, or it is closed while waiting
+     *          for the next key
+     * @throws  InterruptedException
+     *          If interrupted while waiting
+     */
+    public abstract WatchKey poll(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves and removes next watch key, waiting if none are yet present.
+     *
+     * @return  The next watch key
+     *
+     * @throws  ClosedWatchServiceException
+     *          If this watch service is closed, or it is closed while waiting
+     *          for the next key
+     * @throws  InterruptedException
+     *          If interrupted while waiting
+     */
+    public abstract WatchKey take() throws InterruptedException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/Watchable.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+import java.io.IOException;
+
+/**
+ * An object that may be registered with a watch service so that it can be
+ * <em>watched</em> for changes and events.
+ *
+ * <p> This interface defines the {@link #register register} method to register
+ * the object with a {@link WatchService} returning a {@link WatchKey} to
+ * represent the registration. An object may be registered with more than one
+ * watch service. Registration with a watch service is cancelled by invoking the
+ * key's {@link WatchKey#cancel cancel} method.
+ *
+ * @since 1.7
+ *
+ * @see Path#register
+ */
+
+public interface Watchable {
+
+    /**
+     * Registers an object with a watch service.
+     *
+     * <p> If the file system object identified by this object is currently
+     * registered with the watch service then the watch key, representing that
+     * registration, is returned after changing the event set or modifiers to
+     * those specified by the {@code events} and {@code modifiers} parameters.
+     * Changing the event set does not cause pending events for the object to be
+     * discarded. Objects are automatically registered for the {@link
+     * StandardWatchEventKind#OVERFLOW OVERFLOW} event. This event is not
+     * required to be present in the array of events.
+     *
+     * <p> Otherwise the file system object has not yet been registered with the
+     * given watch service, so it is registered and the resulting new key is
+     * returned.
+     *
+     * <p> Implementations of this interface should specify the events they
+     * support.
+     *
+     * @param   watcher
+     *          The watch service to which this object is to be registered
+     * @param   events
+     *          The events for which this object should be registered
+     * @param   modifiers
+     *          The modifiers, if any, that modify how the object is registered
+     *
+     * @return  A key representing the registration of this object with the
+     *          given watch service
+     *
+     * @throws  UnsupportedOperationException
+     *          If unsupported events or modifiers are specified
+     * @throws  IllegalArgumentException
+     *          If an invalid of combination of events are modifiers are specified
+     * @throws  ClosedWatchServiceException
+     *          If the watch service is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission required to monitor this object. Implementations of
+     *          this interface should specify the permission checks.
+     */
+    WatchKey register(WatchService watcher,
+                      WatchEvent.Kind<?>[] events,
+                      WatchEvent.Modifier... modifiers)
+        throws IOException;
+
+
+    /**
+     * Registers an object with a watch service.
+     *
+     * <p> An invocation of this method behaves in exactly the same way as the
+     * invocation
+     * <pre>
+     *     watchable.{@link #register(WatchService,WatchEvent.Kind[],WatchEvent.Modifier[]) register}(watcher, events, new WatchEvent.Modifier[0]);
+     * </pre>
+     *
+     * @param   watcher
+     *          The watch service to which this object is to be registered
+     * @param   events
+     *          The events for which this object should be registered
+     *
+     * @return  A key representing the registration of this object with the
+     *          given watch service
+     *
+     * @throws  UnsupportedOperationException
+     *          If unsupported events are specified
+     * @throws  IllegalArgumentException
+     *          If an invalid of combination of events are specified
+     * @throws  ClosedWatchServiceException
+     *          If the watch service is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission required to monitor this object. Implementations of
+     *          this interface should specify the permission checks.
+     */
+    WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events)
+        throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/AclEntry.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,394 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.util.*;
+
+/**
+ * An entry in an access control list (ACL).
+ *
+ * <p> The ACL entry represented by this class is based on the ACL model
+ * specified in <a href="http://www.ietf.org/rfc/rfc3530.txt"><i>RFC&nbsp;3530:
+ * Network File System (NFS) version 4 Protocol</i></a>. Each entry has four
+ * components as follows:
+ *
+ * <ol>
+ *    <li><p> The {@link #type() type} component determines if the entry
+ *    grants or denies access. </p></li>
+ *
+ *    <li><p> The {@link #principal() principal} component, sometimes called the
+ *    "who" component, is a {@link UserPrincipal} corresponding to the identity
+ *    that the entry grants or denies access
+ *    </p></li>
+ *
+ *    <li><p> The {@link #permissions permissions} component is a set of
+ *    {@link AclEntryPermission permissions}
+ *    </p></li>
+ *
+ *    <li><p> The {@link #flags flags} component is a set of {@link AclEntryFlag
+ *    flags} to indicate how entries are inherited and propagated </p></li>
+ * </ol>
+ *
+ * <p> ACL entries are created using an associated {@link Builder} object by
+ * invoking its {@link Builder#build build} method.
+ *
+ * <p> ACL entries are immutable and are safe for use by multiple concurrent
+ * threads.
+ *
+ * @since 1.7
+ */
+
+public final class AclEntry {
+
+    private final AclEntryType type;
+    private final UserPrincipal who;
+    private final Set<AclEntryPermission> perms;
+    private final Set<AclEntryFlag> flags;
+
+    // cached hash code
+    private volatile int hash;
+
+    // private constructor
+    private AclEntry(AclEntryType type,
+                     UserPrincipal who,
+                     Set<AclEntryPermission> perms,
+                     Set<AclEntryFlag> flags)
+    {
+        this.type = type;
+        this.who = who;
+        this.perms = perms;
+        this.flags = flags;
+    }
+
+    /**
+     * A builder of {@link AclEntry} objects.
+     *
+     * <p> A {@code Builder} object is obtained by invoking one of the {@link
+     * AclEntry#newBuilder newBuilder} methods defined by the {@code AclEntry}
+     * class.
+     *
+     * <p> Builder objects are mutable and are not safe for use by multiple
+     * concurrent threads without appropriate synchronization.
+     *
+     * @since 1.7
+     */
+    public static final class Builder {
+        private AclEntryType type;
+        private UserPrincipal who;
+        private Set<AclEntryPermission> perms;
+        private Set<AclEntryFlag> flags;
+
+        private Builder(AclEntryType type,
+                        UserPrincipal who,
+                        Set<AclEntryPermission> perms,
+                        Set<AclEntryFlag> flags)
+        {
+            assert perms != null && flags != null;
+            this.type = type;
+            this.who = who;
+            this.perms = perms;
+            this.flags = flags;
+        }
+
+        /**
+         * Constructs an {@link AclEntry} from the components of this builder.
+         * The type and who components are required to have been set in order
+         * to construct an {@code AclEntry}.
+         *
+         * @return  A new ACL entry
+         *
+         * @throws  IllegalStateException
+         *          If the type or who component have not been set.
+         */
+        public AclEntry build() {
+            if (type == null)
+                throw new IllegalStateException("Missing type component");
+            if (who == null)
+                throw new IllegalStateException("Missing who component");
+            return new AclEntry(type, who, perms, flags);
+        }
+
+        /**
+         * Sets the type component of this builder.
+         *
+         * @return  This builder
+         */
+        public Builder setType(AclEntryType type) {
+            if (type == null)
+                throw new NullPointerException();
+            this.type = type;
+            return this;
+        }
+
+        /**
+         * Sets the principal component of this builder.
+         *
+         * @return  This builder
+         */
+        public Builder setPrincipal(UserPrincipal who) {
+            if (who == null)
+                throw new NullPointerException();
+            this.who = who;
+            return this;
+        }
+
+        // check set only contains elements of the given type
+        private static void checkSet(Set<?> set, Class<?> type) {
+            for (Object e: set) {
+                if (e == null)
+                    throw new NullPointerException();
+                type.cast(e);
+            }
+        }
+
+        /**
+         * Sets the permissions component of this builder. On return, the
+         * permissions component of this builder is a copy of the given set.
+         *
+         * @return  This builder
+         *
+         * @throws  ClassCastException
+         *          If the sets contains elements that are not of type {@code
+         *          AclEntryPermission}
+         */
+        public Builder setPermissions(Set<AclEntryPermission> perms) {
+            // copy and check for erroneous elements
+            perms = new HashSet<AclEntryPermission>(perms);
+            checkSet(perms, AclEntryPermission.class);
+            this.perms = perms;
+            return this;
+        }
+
+        /**
+         * Sets the permissions component of this builder. On return, the
+         * permissions component of this builder is a copy of the permissions in
+         * the given array.
+         *
+         * @return  This builder
+         */
+        public Builder setPermissions(AclEntryPermission... perms) {
+            Set<AclEntryPermission> set =
+                new HashSet<AclEntryPermission>(perms.length);
+            // copy and check for null elements
+            for (AclEntryPermission p: perms) {
+                if (p == null)
+                    throw new NullPointerException();
+                set.add(p);
+            }
+            this.perms = set;
+            return this;
+        }
+
+        /**
+         * Sets the flags component of this builder. On return, the flags
+         * component of this builder is a copy of the given set.
+         *
+         * @return  This builder
+         *
+         * @throws  ClassCastException
+         *          If the sets contains elements that are not of type {@code
+         *          AclEntryFlag}
+         */
+        public Builder setFlags(Set<AclEntryFlag> flags) {
+            // copy and check for erroneous elements
+            flags = new HashSet<AclEntryFlag>(flags);
+            checkSet(flags, AclEntryFlag.class);
+            this.flags = flags;
+            return this;
+        }
+
+        /**
+         * Sets the flags component of this builder. On return, the flags
+         * component of this builder is a copy of the flags in the given
+         * array.
+         *
+         * @return  This builder
+         */
+        public Builder setFlags(AclEntryFlag... flags) {
+            Set<AclEntryFlag> set = new HashSet<AclEntryFlag>(flags.length);
+            // copy and check for null elements
+            for (AclEntryFlag f: flags) {
+                if (f == null)
+                    throw new NullPointerException();
+                set.add(f);
+            }
+            this.flags = set;
+            return this;
+        }
+    }
+
+    /**
+     * Constructs a new builder. The initial value of the type and who
+     * components is {@code null}. The initial value of the permissions and
+     * flags components is the empty set.
+     *
+     * @return  A new builder
+     */
+    public static Builder newBuilder() {
+        Set<AclEntryPermission> perms = Collections.emptySet();
+        Set<AclEntryFlag> flags = Collections.emptySet();
+        return new Builder(null, null, perms, flags);
+    }
+
+    /**
+     * Constructs a new builder with the components of an existing ACL entry.
+     *
+     * @param   entry
+     *          An ACL entry
+     *
+     * @return  A new builder
+     */
+    public static Builder newBuilder(AclEntry entry) {
+        return new Builder(entry.type, entry.who, entry.perms, entry.flags);
+    }
+
+    /**
+     * Returns the ACL entry type.
+     */
+    public AclEntryType type() {
+        return type;
+    }
+
+    /**
+     * Returns the principal component.
+     */
+    public UserPrincipal principal() {
+        return who;
+    }
+
+    /**
+     * Returns a copy of the permissions component.
+     *
+     * <p> The returned set is a modifiable copy of the permissions.
+     */
+    public Set<AclEntryPermission> permissions() {
+        return new HashSet<AclEntryPermission>(perms);
+    }
+
+    /**
+     * Returns a copy of the flags component.
+     *
+     * <p> The returned set is a modifiable copy of the flags.
+     */
+    public Set<AclEntryFlag> flags() {
+        return new HashSet<AclEntryFlag>(flags);
+    }
+
+    /**
+     * Compares the specified object with this ACL entry for equality.
+     *
+     * <p> If the given object is not an {@code AclEntry} then this method
+     * immediately returns {@code false}.
+     *
+     * <p> For two ACL entries to be considered equals requires that they are
+     * both the same type, their who components are equal, their permissions
+     * components are equal, and their flags components are equal.
+     *
+     * <p> This method satisfies the general contract of the {@link
+     * java.lang.Object#equals(Object) Object.equals} method. </p>
+     *
+     * @param   ob   The object to which this object is to be compared
+     *
+     * @return  {@code true} if, and only if, the given object is an AclEntry that
+     *          is identical to this AclEntry
+     */
+    @Override
+    public boolean equals(Object ob) {
+        if (ob == this)
+            return true;
+        if (ob == null || !(ob instanceof AclEntry))
+            return false;
+        AclEntry other = (AclEntry)ob;
+        if (this.type != other.type)
+            return false;
+        if (!this.who.equals(other.who))
+            return false;
+        if (!this.perms.equals(other.perms))
+            return false;
+        if (!this.flags.equals(other.flags))
+            return false;
+        return true;
+    }
+
+    private static int hash(int h, Object o) {
+        return h * 127 + o.hashCode();
+    }
+
+    /**
+     * Returns the hash-code value for this ACL entry.
+     *
+     * <p> This method satisfies the general contract of the {@link
+     * Object#hashCode method}.
+     */
+    @Override
+    public int hashCode() {
+        // return cached hash if available
+        if (hash != 0)
+            return hash;
+        int h = type.hashCode();
+        h = hash(h, who);
+        h = hash(h, perms);
+        h = hash(h, flags);
+        hash = h;
+        return hash;
+    }
+
+    /**
+     * Returns the string representation of this ACL entry.
+     *
+     * @return  The string representation of this entry
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+
+        // who
+        sb.append(who.getName());
+        sb.append(':');
+
+        // permissions
+        for (AclEntryPermission perm: perms) {
+            sb.append(perm.name());
+            sb.append('/');
+        }
+        sb.setLength(sb.length()-1); // drop final slash
+        sb.append(':');
+
+        // flags
+        if (!flags.isEmpty()) {
+            for (AclEntryFlag flag: flags) {
+                sb.append(flag.name());
+                sb.append('/');
+            }
+            sb.setLength(sb.length()-1);  // drop final slash
+            sb.append(':');
+        }
+
+        // type
+        sb.append(type.name());
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/AclEntryFlag.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * Defines the flags for used by the flags component of an ACL {@link AclEntry
+ * entry}.
+ *
+ * <p> In this release, this class does not define flags related to {@link
+ * AclEntryType#AUDIT} and {@link AclEntryType#ALARM} entry types.
+ *
+ * @since 1.7
+ */
+
+public enum AclEntryFlag {
+
+    /**
+     * Can be placed on a directory and indicates that the ACL entry should be
+     * added to each new non-directory file created.
+     */
+    FILE_INHERIT,
+
+    /**
+     * Can be placed on a directory and indicates that the ACL entry should be
+     * added to each new directory created.
+     */
+    DIRECTORY_INHERIT,
+
+    /**
+     * Can be placed on a directory to indicate that the ACL entry should not
+     * be placed on the newly created directory which is inheritable by
+     * subdirectories of the created directory.
+     */
+    NO_PROPAGATE_INHERIT,
+
+    /**
+     * Can be placed on a directory but does not apply to the directory,
+     * only to newly created files/directories as specified by the
+     * {@link #FILE_INHERIT} and {@link #DIRECTORY_INHERIT} flags.
+     */
+    INHERIT_ONLY;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/AclEntryPermission.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * Defines the permissions for use with the permissions component of an ACL
+ * {@link AclEntry entry}.
+ *
+ * @since 1.7
+ */
+
+public enum AclEntryPermission {
+
+    /**
+     * Permission to read the data of the file.
+     */
+    READ_DATA,
+
+    /**
+     * Permission to modify the file's data.
+     */
+    WRITE_DATA,
+
+    /**
+     * Permission to append data to a file.
+     */
+    APPEND_DATA,
+
+    /**
+     * Permission to read the named attributes of a file.
+     *
+     * <p> <a href="http://www.ietf.org/rfc/rfc3530.txt">RFC&nbsp;3530: Network
+     * File System (NFS) version 4 Protocol</a> defines <em>named attributes</em>
+     * as opaque files associated with a file in the file system.
+     */
+    READ_NAMED_ATTRS,
+
+    /**
+     * Permission to write the named attributes of a file.
+     *
+     * <p> <a href="http://www.ietf.org/rfc/rfc3530.txt">RFC&nbsp;3530: Network
+     * File System (NFS) version 4 Protocol</a> defines <em>named attributes</em>
+     * as opaque files associated with a file in the file system.
+     */
+    WRITE_NAMED_ATTRS,
+
+    /**
+     * Permission to execute a file.
+     */
+    EXECUTE,
+
+    /**
+     * Permission to delete a file or directory within a directory.
+     */
+    DELETE_CHILD,
+
+    /**
+     * The ability to read (non-acl) file attributes.
+     */
+    READ_ATTRIBUTES,
+
+    /**
+     * The ability to write (non-acl) file attributes.
+     */
+    WRITE_ATTRIBUTES,
+
+    /**
+     * Permission to delete the file.
+     */
+    DELETE,
+
+    /**
+     * Permission to read the ACL attribute.
+     */
+    READ_ACL,
+
+    /**
+     * Permission to write the ACL attribute.
+     */
+    WRITE_ACL,
+
+    /**
+     * Permission to change the owner.
+     */
+    WRITE_OWNER,
+
+    /**
+     * Permission to access file locally at the server with synchronous reads
+     * and writes.
+     */
+    SYNCHRONIZE;
+
+    /**
+     * Permission to list the entries of a directory (equal to {@link #READ_DATA})
+     */
+    public static final AclEntryPermission LIST_DIRECTORY = READ_DATA;
+
+    /**
+     * Permission to add a new file to a directory (equal to {@link #WRITE_DATA})
+     */
+    public static final AclEntryPermission ADD_FILE = WRITE_DATA;
+
+    /**
+     * Permission to create a subdirectory to a directory (equal to {@link #APPEND_DATA})
+     */
+    public static final AclEntryPermission ADD_SUBDIRECTORY = APPEND_DATA;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/AclEntryType.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * A typesafe enumeration of the access control entry types.
+ *
+ * @since 1.7
+ */
+
+public enum AclEntryType {
+    /**
+     * Explicitly grants access to a file or directory.
+     */
+    ALLOW,
+
+    /**
+     * Explicitly denies access to a file or directory.
+     */
+    DENY,
+
+    /**
+     * Log, in a system dependent way, the access specified in the
+     * permissions component of the ACL entry.
+     */
+    AUDIT,
+
+    /**
+     * Generate an alarm, in a system dependent way, the access specified in the
+     * permissions component of the ACL entry.
+     */
+    ALARM
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/AclFileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.nio.file.*;
+import java.util.List;
+import java.io.IOException;
+
+/**
+ * A file attribute view that supports reading or updating a file's Access
+ * Control Lists (ACL) or file owner attributes.
+ *
+ * <p> ACLs are used to specify access rights to file system objects. An ACL is
+ * an ordered list of {@link AclEntry access-control-entries}, each specifying a
+ * {@link UserPrincipal} and the level of access for that user principal. This
+ * file attribute view defines the {@link #getAcl() getAcl}, and {@link
+ * #setAcl(List) setAcl} methods to read and write ACLs based on the ACL
+ * model specified in <a href="http://www.ietf.org/rfc/rfc3530.txt"><i>RFC&nbsp;3530:
+ * Network File System (NFS) version 4 Protocol</i></a>. This file attribute view
+ * is intended for file system implementations that support the NFSv4 ACL model
+ * or have a <em>well-defined</em> mapping between the NFSv4 ACL model and the ACL
+ * model used by the file system. The details of such mapping are implementation
+ * dependent and are therefore unspecified.
+ *
+ * <p> This class also extends {@code FileOwnerAttributeView} so as to define
+ * methods to get and set the file owner.
+ *
+ * <p> When a file system provides access to a set of {@link FileStore
+ * file-systems} that are not homogeneous then only some of the file systems may
+ * support ACLs. The {@link FileStore#supportsFileAttributeView
+ * supportsFileAttributeView} method can be used to test if a file system
+ * supports ACLs.
+ *
+ * <a name="interop"><h4>Interoperability</h4></a>
+ *
+ * RFC&nbsp;3530 allows for special user identities to be used on platforms that
+ * support the POSIX defined access permissions. The special user identities
+ * are "{@code OWNER@}", "{@code GROUP@}", and "{@code EVERYONE@}". When both
+ * the {@code AclFileAttributeView} and the {@link PosixFileAttributeView}
+ * are supported then these special user identities may be included in ACL {@link
+ * AclEntry entries} that are read or written. The file system's {@link
+ * UserPrincipalLookupService} may be used to obtain a {@link UserPrincipal}
+ * to represent these special identities by invoking the {@link
+ * UserPrincipalLookupService#lookupPrincipalByName lookupPrincipalByName}
+ * method.
+ *
+ * <p> <b>Usage Example:</b>
+ * Suppose we wish to add an entry to an existing ACL to grant "joe" access:
+ * <pre>
+ *     // lookup "joe"
+ *     UserPrincipal joe = file.getFileSystem().getUserPrincipalLookupService()
+ *         .lookupPrincipalByName("joe");
+ *
+ *     // get view
+ *     AclFileAttributeView view = file.newFileAttributeView(AclFileAttributeView.class);
+ *
+ *     // create ACE to give "joe" read access
+ *     AclEntry entry = AclEntry.newBuilder()
+ *         .setType(AclEntryType.ALLOW)
+ *         .setPrincipal(joe)
+ *         .setPermissions(AclEntryPermission.READ_DATA, AclEntryPermission.READ_ATTRIBUTES)
+ *         .build();
+ *
+ *     // read ACL, insert ACE, re-write ACL
+ *     List&lt;AclEntry&gt acl = view.getAcl();
+ *     acl.add(0, entry);   // insert before any DENY entries
+ *     view.setAcl(acl);
+ * </pre>
+ *
+ * <h4> Dynamic Access </h4>
+ * <p> Where dynamic access to file attributes is required, the attributes
+ * supported by this attribute view are as follows:
+ * <blockquote>
+ * <table border="1" cellpadding="8">
+ *   <tr>
+ *     <th> Name </th>
+ *     <th> Type </th>
+ *   </tr>
+ *   <tr>
+ *     <td> "acl" </td>
+ *     <td> {@link List}&lt;{@link AclEntry}&gt; </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "owner" </td>
+ *     <td> {@link UserPrincipal} </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ *
+ * <p> The {@link #getAttribute getAttribute} or {@link #readAttributes
+ * readAttributes} methods may be used to read the ACL or owner attributes as if
+ * by invoking the {@link #getAcl getAcl} or {@link #getOwner getOwner} methods.
+ *
+ * <p> The {@link #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.
+ *
+ * <h4> Setting the ACL when creating a file </h4>
+ *
+ * <p> 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
+ * FileAttribute#name name} {@code "acl:acl"} and a {@link FileAttribute#value
+ * value} that is the list of {@code AclEntry} objects.
+ *
+ * <p> Where an implementation supports an ACL model that differs from the NFSv4
+ * defined ACL model then setting the initial ACL when creating the file must
+ * translate the ACL to the model supported by the file system. Methods that
+ * create a file should reject (by throwing {@link IOException IOException})
+ * any attempt to create a file that would be less secure as a result of the
+ * translation.
+ *
+ * @since 1.7
+ * @see Attributes#getAcl
+ * @see Attributes#setAcl
+ */
+
+public interface AclFileAttributeView
+    extends FileOwnerAttributeView
+{
+    /**
+     * Returns the name of the attribute view. Attribute views of this type
+     * have the name {@code "acl"}.
+     */
+    @Override
+    String name();
+
+    /**
+     * Reads the access control list.
+     *
+     * <p> When the file system uses an ACL model that differs from the NFSv4
+     * defined ACL model, then this method returns an ACL that is the translation
+     * of the ACL to the NFSv4 ACL model.
+     *
+     * <p> The returned list is modifiable so as to facilitate changes to the
+     * existing ACL. The {@link #setAcl setAcl} method is used to update
+     * the file's ACL attribute.
+     *
+     * @return  An ordered list of {@link AclEntry entries} representing the
+     *          ACL
+     *
+     * @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}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     */
+    List<AclEntry> getAcl() throws IOException;
+
+    /**
+     * Updates (replace) the access control list.
+     *
+     * <p> Where the file system supports Access Control Lists, and it uses an
+     * ACL model that differs from the NFSv4 defined ACL model, then this method
+     * must translate the ACL to the model supported by the file system. This
+     * method should reject (by throwing {@link IOException IOException}) any
+     * attempt to write an ACL that would appear to make the file more secure
+     * than would be the case if the ACL were updated. Where an implementation
+     * does not support a mapping of {@link AclEntryType#AUDIT} or {@link
+     * AclEntryType#ALARM} entries, then this method ignores these entries when
+     * writing the ACL.
+     *
+     * <p> If an ACL entry contains a {@link AclEntry#principal user-principal}
+     * that is not associated with the same provider as this attribute view then
+     * {@link ProviderMismatchException} is thrown. Additional validation, if
+     * any, is implementation dependent.
+     *
+     * <p> If the file system supports other security related file attributes
+     * (such as a file {@link PosixFileAttributes#permissions
+     * access-permissions} for example), the updating the access control list
+     * may also cause these security related attributes to be updated.
+     *
+     * @param   acl
+     *          The new access control list
+     *
+     * @throws  IOException
+     *          If an I/O error occurs or the ACL is invalid
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file.
+     */
+    void setAcl(List<AclEntry> acl) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/AttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.util.*;
+import java.io.IOException;
+
+/**
+ * An object that provides a read-only or updatable <em>view</em> of non-opaque
+ * values associated with an object in a filesystem. This interface is extended
+ * or implemented by specific attribute views that define the attributes
+ * supported by the view. A specific attribute view will typically define
+ * type-safe methods to read or update the attributes that it supports. It also
+ * provides <em>dynamic access</em> where the {@link #readAttributes
+ * readAttributes}, {@link #getAttribute getAttribute} and {@link #setAttribute
+ * setAttributs} methods are used to access the attributes by names defined
+ * by the attribute view. Implementations must ensure that the attribute names
+ * do not contain the colon (':') or comma (',') characters.
+ *
+ * @since 1.7
+ */
+
+public interface AttributeView {
+    /**
+     * Returns the name of the attribute view.
+     */
+    String name();
+
+    /**
+     * Reads the value of an attribute.
+     *
+     * @param   attribute
+     *          The attribute name (case sensitive)
+     *
+     * @return  The value of the attribute, or {@code null} if the attribute is
+     *          not supported
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is set and it denies access
+     */
+    Object getAttribute(String attribute) throws IOException;
+
+    /**
+     * Sets/updates the value of an attribute.
+     *
+     * @param   attribute
+     *          The attribute name (case sensitive)
+     * @param   value
+     *          The attribute value
+     *
+     * @throws  UnsupportedOperationException
+     *          If the attribute is not supported or this attribute view does
+     *          not support updating the value of 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
+     *          If a security manager is set and it denies access
+     */
+    void setAttribute(String attribute, Object value) throws IOException;
+
+    /**
+     * Reads all, or a subset, of the attributes supported by this file attribute
+     * view.
+     *
+     * <p> The {@code first} and {@code rest} parameters are the names of the
+     * attributes to read. If any of the parameters has 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.
+     *
+     * @param   first
+     *          The name of an attribute to read (case sensitive)
+     * @param   rest
+     *          The names of others attributes to read (case sensitive)
+     *
+     * @return  An unmodifiable map of the attributes; may be empty. Its keys are
+     *          the attribute names, its values are the attribute values
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is set and it denies access
+     */
+    Map<String,?> readAttributes(String first, String... rest) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/Attributes.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,703 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 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() {
+    }
+
+    /**
+     * 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;
+    }
+
+    /**
+     * Sets the value of a file attribute.
+     *
+     * <p> The {@code attribute} parameter identifies the attribute to be set
+     * and takes the form:
+     * <blockquote>
+     * [<i>view-name</i><b>:</b>]<i>attribute-name</i>
+     * </blockquote>
+     * where square brackets [...] delineate an optional component and the
+     * character {@code ':'} stands for itself.
+     *
+     * <p> <i>view-name</i> 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. <i>attribute-name</i> is the name of the attribute
+     * within the set.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to set the DOS "hidden" attribute:
+     * <pre>
+     *    Attributes.setAttribute(file, "dos:hidden", true);
+     * </pre>
+     *
+     * @param   file
+     *          A file reference that locates the file
+     * @param   attribute
+     *          The attribute to set
+     * @param   value
+     *          The attribute value
+     *
+     * @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 void setAttribute(FileRef file, String attribute, Object value)
+        throws IOException
+    {
+        String[] s = split(attribute);
+        FileAttributeView view = file.getFileAttributeView(s[0]);
+        if (view == null)
+            throw new UnsupportedOperationException("View '" + s[0] + "' not available");
+        view.setAttribute(s[1], value);
+    }
+
+    /**
+     * Reads the value of a file attribute.
+     *
+     * <p> The {@code attribute} parameter identifies the attribute to be read
+     * and takes the form:
+     * <blockquote>
+     * [<i>view-name</i><b>:</b>]<i>attribute-name</i>
+     * </blockquote>
+     * where square brackets [...] delineate an optional component and the
+     * character {@code ':'} stands for itself.
+     *
+     * <p> <i>view-name</i> 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. <i>attribute-name</i> is the name of the attribute.
+     *
+     * <p> 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.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we require the user ID of the file owner on a system that
+     * supports a "{@code unix}" view:
+     * <pre>
+     *    int uid = (Integer)Attributes.getAttribute(file, "unix:uid");
+     * </pre>
+     *
+     * @param   file
+     *          A file reference that locates 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(FileRef file,
+                                      String attribute,
+                                      LinkOption... options)
+        throws IOException
+    {
+        String[] s = split(attribute);
+        FileAttributeView view = file.getFileAttributeView(s[0], options);
+        if (view != null)
+            return view.getAttribute(s[1]);
+        // view not available
+        return null;
+    }
+
+    /**
+     * Reads a set of file attributes as a bulk operation.
+     *
+     * <p> The {@code attributes} parameter identifies the attributes to be read
+     * and takes the form:
+     * <blockquote>
+     * [<i>view-name</i><b>:</b>]<i>attribute-list</i>
+     * </blockquote>
+     * where square brackets [...] delineate an optional component and the
+     * character {@code ':'} stands for itself.
+     *
+     * <p> <i>view-name</i> 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.
+     *
+     * <p> The <i>attribute-list</i> 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.
+     *
+     * <p> The following examples demonstrate possible values for the {@code
+     * attributes} parameter:
+     *
+     * <blockquote>
+     * <table border="0">
+     * <tr>
+     *   <td> {@code "*"} </td>
+     *   <td> Read all {@link BasicFileAttributes basic-file-attributes}. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@code "size,lastModifiedTime,lastAccessTime"} </td>
+     *   <td> Reads the file size, last modified time, and last access time
+     *     attributes. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@code "posix:*"} </td>
+     *   <td> Read all {@link PosixFileAttributes POSIX-file-attributes}.. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@code "posix:permissions,owner,size"} </td>
+     *   <td> Reads the POSX file permissions, owner, and file size. </td>
+     * </tr>
+     * </table>
+     * </blockquote>
+     *
+     * <p> 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.
+     *
+     * @param   file
+     *          A file reference that locates 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<String,?> readAttributes(FileRef file,
+                                               String attributes,
+                                               LinkOption... options)
+        throws IOException
+    {
+        String[] s = split(attributes);
+        FileAttributeView view = file.getFileAttributeView(s[0], options);
+        if (view != null) {
+            // further split attributes into the first and rest.
+            String[] names = s[1].split(",");
+            int rem = names.length-1;
+            String first = names[0];
+            String[] rest = new String[rem];
+            if (rem > 0) System.arraycopy(names, 1, rest, 0, rem);
+
+            return view.readAttributes(first, rest);
+        }
+        // view not available
+        return Collections.emptyMap();
+    }
+
+    /**
+     * Reads the basic file attributes of a file.
+     *
+     * <p> 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. This option
+     * should be used where there is a need to determine if a file is a
+     * symbolic link:
+     * <pre>
+     *    boolean isSymbolicLink = Attributes.readBasicFileAttributes(file, NOFOLLOW_LINKS).isSymbolicLink();
+     * </pre>
+     *
+     * <p> 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.
+     *
+     * <p> 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.
+     *
+     * <p> 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.
+     *
+     * @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}<tt>("accessUserInformation")</tt>
+     *          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.
+     *
+     * <p> 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 <em>consumer devices</em>. It is
+     * implementation specific if all file attributes are read as an atomic
+     * operation with respect to other file system operations.
+     *
+     * <p> 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.
+     *
+     * @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.
+     *
+     * <p> 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}<tt>("accessUserInformation")</tt>
+     *          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.
+     *
+     * <p> 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}<tt>("accessUserInformation")</tt>
+     *          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).
+     *
+     * <p> 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
+     *  <a href="http://www.ietf.org/rfc/rfc3530.txt"><i>RFC&nbsp;3530</i></a>.
+     *
+     * @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}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     *
+     * @see AclFileAttributeView#getAcl
+     */
+    public static List<AclEntry> 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).
+     *
+     * <p> 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
+     *  <a href="http://www.ietf.org/rfc/rfc3530.txt"><i>RFC&nbsp;3530</i></a>.
+     *
+     * @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}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file.
+     *
+     * @see AclFileAttributeView#setAcl
+     */
+    public static void setAcl(FileRef file, List<AclEntry> acl)
+        throws IOException
+    {
+        AclFileAttributeView view =
+            file.getFileAttributeView(AclFileAttributeView.class);
+        if (view == null)
+            throw new UnsupportedOperationException();
+        view.setAcl(acl);
+    }
+
+    /**
+     * Updates the value of a file's last modified time attribute.
+     *
+     * <p> The time value is measured since the epoch
+     * (00:00:00 GMT, January 1, 1970) and is converted to the precision supported
+     * by the file system. Converting from finer to coarser granularities result
+     * in precision loss.
+     *
+     * <p> If the file system does not support a last modified time attribute then
+     * this method has no effect.
+     *
+     * @param   file
+     *          A file reference that locates the file
+     *
+     * @param   lastModifiedTime
+     *          The new last modified time, or {@code -1L} to update it to
+     *          the current time
+     * @param   unit
+     *          A {@code TimeUnit} determining how to interpret the
+     *          {@code lastModifiedTime} parameter
+     *
+     * @throws  IllegalArgumentException
+     *          If the {@code lastModifiedime} parameter is a negative value other
+     *          than {@code -1L}
+     * @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,
+                                           long lastModifiedTime,
+                                           TimeUnit unit)
+        throws IOException
+    {
+        file.getFileAttributeView(BasicFileAttributeView.class)
+            .setTimes(lastModifiedTime, null, null, unit);
+    }
+
+    /**
+     * Updates the value of a file's last access time attribute.
+     *
+     * <p> The time value is measured since the epoch
+     * (00:00:00 GMT, January 1, 1970) and is converted to the precision supported
+     * by the file system. Converting from finer to coarser granularities result
+     * in precision loss.
+     *
+     * <p> If the file system does not support a last access time attribute then
+     * this method has no effect.
+     *
+     * @param   lastAccessTime
+     *          The new last access time, or {@code -1L} to update it to
+     *          the current time
+     * @param   unit
+     *          A {@code TimeUnit} determining how to interpret the
+     *          {@code lastModifiedTime} parameter
+     *
+     * @throws  IllegalArgumentException
+     *          If the {@code lastAccessTime} parameter is a negative value other
+     *          than {@code -1L}
+     * @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,
+                                         long lastAccessTime,
+                                         TimeUnit unit)
+        throws IOException
+    {
+        file.getFileAttributeView(BasicFileAttributeView.class)
+            .setTimes(null, lastAccessTime, null, unit);
+    }
+
+    /**
+     * Sets a file's POSIX permissions.
+     *
+     * <p> 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}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file.
+     *
+     * @see PosixFileAttributeView#setPermissions
+     */
+    public static void setPosixFilePermissions(FileRef file,
+                                               Set<PosixFilePermission> 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.
+     *
+     * <p> 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();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/BasicFileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.util.concurrent.TimeUnit;
+import java.io.IOException;
+
+/**
+ * A file attribute view that provides a view of a <em>basic set</em> of file
+ * attributes common to many file systems. The basic set of file attributes
+ * consist of <em>mandatory</em> and <em>optional</em> file attributes as
+ * defined by the {@link BasicFileAttributes} interface.
+
+ * <p> The file attributes are retrieved from the file system as a <em>bulk
+ * operation</em> by invoking the {@link #readAttributes() readAttributes} method.
+ * This class also defines the {@link #setTimes setTimes} method to update the
+ * file's time attributes.
+ *
+ * <p> Where dynamic access to file attributes is required, the attributes
+ * supported by this attribute view have the following names and types:
+ * <blockquote>
+ *  <table border="1" cellpadding="8">
+ *   <tr>
+ *     <th> Name </th>
+ *     <th> Type </th>
+ *   </tr>
+ *  <tr>
+ *     <td> "lastModifiedTime" </td>
+ *     <td> {@link Long} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "lastAccessTime" </td>
+ *     <td> {@link Long} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "creationTime" </td>
+ *     <td> {@link Long} </td>
+ *   </tr>
+ *  <tr>
+ *     <td> "resolution" </td>
+ *     <td> {@link java.util.concurrent.TimeUnit} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "size" </td>
+ *     <td> {@link Long} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "isRegularFile" </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "isDirectory" </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "isSymbolicLink" </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "isOther" </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "linkCount" </td>
+ *     <td> {@link Integer} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "fileKey" </td>
+ *     <td> {@link Object} </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ *
+ * <p> The {@link #getAttribute getAttribute} or {@link
+ * #readAttributes(String,String[]) readAttributes(String,String[])} methods may
+ * be used to read any of these attributes as if by invoking the {@link
+ * #readAttributes() readAttributes()} method.
+ *
+ * <p> The {@link #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. In that case, the time
+ * value is interpreted in {@link TimeUnit#MILLISECONDS milliseconds} and
+ * converted to the precision supported by the file system.
+ *
+ * @since 1.7
+ * @see Attributes
+ */
+
+public interface BasicFileAttributeView
+    extends FileAttributeView
+{
+    /**
+     * Returns the name of the attribute view. Attribute views of this type
+     * have the name {@code "basic"}.
+     */
+    @Override
+    String name();
+
+    /**
+     * Reads the basic file attributes as a bulk operation.
+     *
+     * <p> It is implementation specific if all file attributes are read as an
+     * atomic operation with respect to other file system operations.
+     *
+     * @return  The file attributes
+     *
+     * @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
+     */
+    BasicFileAttributes readAttributes() throws IOException;
+
+    /**
+     * Updates any or all of the file's last modified time, last access time,
+     * and create time attributes.
+     *
+     * <p> This method updates the file's timestamp attributes. The values are
+     * measured since the epoch (00:00:00 GMT, January 1, 1970) and converted to
+     * the precision supported by the file system. Converting from finer to
+     * coarser granularities result in precision loss. If a value is larger
+     * than the maximum supported by the file system then the corresponding
+     * timestamp is set to its maximum value.
+     *
+     * <p> If any of the {@code lastModifiedTime}, {@code lastAccessTime},
+     * or {@code createTime} parameters has the value {@code null} then the
+     * corresponding timestamp is not changed. An implementation may require to
+     * read the existing values of the file attributes when only some, but not
+     * all, of the timestamp attributes are updated. Consequently, this method
+     * may not be an atomic operation with respect to other file system
+     * operations. If all of the {@code lastModifiedTime}, {@code
+     * lastAccessTime} and {@code createTime} parameters are {@code null} then
+     * this method has no effect.
+     *
+     * @param   lastModifiedTime
+     *          The new last modified time, or {@code -1L} to update it to
+     *          the current time, or {@code null} to not change the attribute
+     * @param   lastAccessTime
+     *          The last access time, or {@code -1L} to update it to
+     *          the current time, or {@code null} to not change the attribute.
+     * @param   createTime
+     *          The file's create time, or {@code -1L} to update it to
+     *          the current time, or {@code null} to not change the attribute
+     * @param   unit
+     *          A {@code TimeUnit} determining how to interpret the time values
+     *
+     * @throws  IllegalArgumentException
+     *          If any of the parameters is a negative value other than {@code
+     *          -1L}
+     * @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#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the file
+     */
+    void setTimes(Long lastModifiedTime,
+                  Long lastAccessTime,
+                  Long createTime,
+                  TimeUnit unit) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/BasicFileAttributes.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Basic attributes associated with a file in a file system.
+ *
+ * <p> Basic file attributes are attributes that are common to many file systems
+ * and consist of mandatory and optional file attributes as defined by this
+ * interface.
+ *
+ * <p> <b>Usage Example:</b>
+ * <pre>
+ *    FileRef file = ...
+ *    BasicFileAttributes attrs = Attributes.readBasicFileAttributes(file);
+ * </pre>
+ *
+ * @since 1.7
+ *
+ * @see BasicFileAttributeView
+ */
+
+public interface BasicFileAttributes {
+
+    /**
+     * Returns the time of last modification.
+     *
+     * <p> The {@link #resolution() resolution} method returns the {@link TimeUnit}
+     * to interpret the return value of this method.
+     *
+     * @return  A <code>long</code> value representing the time the file was
+     *          last modified since the epoch (00:00:00 GMT, January 1, 1970),
+     *          or {@code -1L} if the attribute is not supported.
+     */
+    long lastModifiedTime();
+
+    /**
+     * Returns the time of last access if supported.
+     *
+     * <p> The {@link #resolution() resolution} method returns the {@link TimeUnit}
+     * to interpret the return value of this method.
+     *
+     * @return  A <code>long</code> value representing the time of last access
+     *          since the epoch (00:00:00 GMT, January 1, 1970), or {@code -1L}
+     *          if the attribute is not supported.
+     */
+    long lastAccessTime();
+
+    /**
+     * Returns the creation time if supported. The creation time is the time
+     * that the file was created.
+     *
+     * <p> The {@link #resolution() resolution} method returns the {@link TimeUnit}
+     * to interpret the return value of this method.
+     *
+     * @return  A <code>long</code> value representing the time the file was
+     *          created since the epoch (00:00:00 GMT, January 1, 1970), or
+     *          {@code -1L} if the attribute is not supported.
+     */
+    long creationTime();
+
+    /**
+     * Returns the {@link TimeUnit} required to interpret the time of last
+     * modification, time of last access, and creation time.
+     *
+     * @return  The {@code TimeUnit} required to interpret the file time stamps
+     */
+    TimeUnit resolution();
+
+    /**
+     * Tells whether the file is a regular file with opaque content.
+     */
+    boolean isRegularFile();
+
+    /**
+     * Tells whether the file is a directory.
+     */
+    boolean isDirectory();
+
+    /**
+     * Tells whether the file is a symbolic-link.
+     */
+    boolean isSymbolicLink();
+
+    /**
+     * Tells whether the file is something other than a regular file, directory,
+     * or link.
+     */
+    boolean isOther();
+
+    /**
+     * Returns the size of the 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.
+     *
+     * @return  The file size, in bytes
+     */
+    long size();
+
+    /**
+     * Returns the number of <em>links</em> to this file.
+     *
+     * <p> On file systems where the same file may be in several directories then
+     * the link count is the number of directory entries for the file. The return
+     * value is {@code 1} on file systems that only allow a file to have a
+     * single name in a single directory.
+     *
+     * @see java.nio.file.Path#createLink
+     */
+    int linkCount();
+
+    /**
+     * Returns an object that uniquely identifies the given file, or {@code
+     * null} if a file key is not available. On some platforms or file systems
+     * it is possible to use an identifier, or a combination of identifiers to
+     * uniquely identify a file. Such identifiers are important for operations
+     * such as file tree traversal in file systems that support <a
+     * href="../package-summary.html#links">symbolic links</a> or file systems
+     * that allow a file to be an entry in more than one directory. On UNIX file
+     * systems, for example, the <em>device ID</em> and <em>inode</em> are
+     * commonly used for such purposes.
+     *
+     * <p> The file key returned by this method can only be guaranteed to be
+     * unique if the file system and files remain static. Whether a file system
+     * re-uses identifiers after a file is deleted is implementation dependent and
+     * therefore unspecified.
+     *
+     * <p> 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.FileRef#isSameFile same} with
+     * non-{@code null} file keys, then their file keys are equal.
+     *
+     * @see java.nio.file.Files#walkFileTree
+     */
+    Object fileKey();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/DosFileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.io.IOException;
+
+/**
+ * A file attribute view that provides a view of the legacy "DOS" file attributes.
+ * These attributes are supported by file systems such as the File Allocation
+ * Table (FAT) format commonly used in <em>consumer devices</em>.
+ *
+ * <p> A {@code DosFileAttributeView} is a {@link BasicFileAttributeView} that
+ * additionally supports access to the set of DOS attribute flags that are used
+ * to indicate if the file is read-only, hidden, a system file, or archived.
+ *
+ * <p> Where dynamic access to file attributes is required, the attributes
+ * supported by this attribute view are as defined by {@code
+ * BasicFileAttributeView}, and in addition, the following attributes are
+ * supported:
+ * <blockquote>
+ * <table border="1" cellpadding="8">
+ *   <tr>
+ *     <th> Name </th>
+ *     <th> Type </th>
+ *   </tr>
+ *   <tr>
+ *     <td> readonly </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> hidden </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> system </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> archive </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ *
+ * <p> The {@link #getAttribute getAttribute} or {@link #readAttributes(String,String[])
+ * readAttributes(String,String[])} methods 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.
+ *
+ * <p> The {@link #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 setReadOnly},
+ * {@link #setHidden setHidden}, {@link #setSystem setSystem}, and {@link
+ * #setArchive setArchive} methods respectively.
+ *
+ * @since 1.7
+ */
+
+public interface DosFileAttributeView
+    extends BasicFileAttributeView
+{
+    /**
+     * Returns the name of the attribute view. Attribute views of this type
+     * have the name {@code "dos"}.
+     */
+    @Override
+    String name();
+
+    /**
+     * @throws  IOException                             {@inheritDoc}
+     * @throws  SecurityException                       {@inheritDoc}
+     */
+    @Override
+    DosFileAttributes readAttributes() throws IOException;
+
+    /**
+     * Updates the value of the read-only attribute.
+     *
+     * <p> It is implementation specific if the attribute can be updated as an
+     * atomic operation with respect to other file system operations. An
+     * implementation may, for example, require to read the existing value of
+     * the DOS attribute in order to update this attribute.
+     *
+     * @param   value
+     *          The new value of the attribute
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default, and a security manager is installed,
+     *          its  {@link SecurityManager#checkWrite(String) checkWrite} method
+     *          is invoked to check write access to the file
+     */
+    void setReadOnly(boolean value) throws IOException;
+
+    /**
+     * Updates the value of the hidden attribute.
+     *
+     * <p> It is implementation specific if the attribute can be updated as an
+     * atomic operation with respect to other file system operations. An
+     * implementation may, for example, require to read the existing value of
+     * the DOS attribute in order to update this attribute.
+     *
+     * @param   value
+     *          The new value of the attribute
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default, and a security manager is installed,
+     *          its  {@link SecurityManager#checkWrite(String) checkWrite} method
+     *          is invoked to check write access to the file
+     */
+    void setHidden(boolean value) throws IOException;
+
+    /**
+     * Updates the value of the system attribute.
+     *
+     * <p> It is implementation specific if the attribute can be updated as an
+     * atomic operation with respect to other file system operations. An
+     * implementation may, for example, require to read the existing value of
+     * the DOS attribute in order to update this attribute.
+     *
+     * @param   value
+     *          The new value of the attribute
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default, and a security manager is installed,
+     *          its  {@link SecurityManager#checkWrite(String) checkWrite} method
+     *          is invoked to check write access to the file
+     */
+    void setSystem(boolean value) throws IOException;
+
+    /**
+     * Updates the value of the archive attribute.
+     *
+     * <p> It is implementation specific if the attribute can be updated as an
+     * atomic operation with respect to other file system operations. An
+     * implementation may, for example, require to read the existing value of
+     * the DOS attribute in order to update this attribute.
+     *
+     * @param   value
+     *          The new value of the attribute
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default, and a security manager is installed,
+     *          its  {@link SecurityManager#checkWrite(String) checkWrite} method
+     *          is invoked to check write access to the file
+     */
+    void setArchive(boolean value) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/DosFileAttributes.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * File attributes associated with a file in a file system that supports
+ * legacy "DOS" attributes.
+ *
+ * <p> The DOS attributes of a file are retrieved using a {@link
+ * DosFileAttributeView} by invoking its {@link DosFileAttributeView#readAttributes
+ * readAttributes} method.
+ *
+ * @since 1.7
+ *
+ * @see Attributes#readDosFileAttributes
+ */
+
+public interface DosFileAttributes
+    extends BasicFileAttributes
+{
+    /**
+     * Returns the value of the read-only attribute.
+     *
+     * <p> This attribute is often used as a simple access control mechanism
+     * to prevent files from being deleted or updated. Whether the file system
+     * or platform does any enforcement to prevent <em>read-only</em> files
+     * from being updated is implementation specific.
+     *
+     * @return  The value of the read-only attribute.
+     */
+    boolean isReadOnly();
+
+    /**
+     * Returns the value of the hidden attribute.
+     *
+     * <p> This attribute is often used to indicate if the file is visible to
+     * users.
+     *
+     * @return  The value of the hidden attribute.
+     */
+    boolean isHidden();
+
+    /**
+     * Returns the value of the archive attribute.
+     *
+     * <p> This attribute is typically used by backup programs.
+     *
+     * @return  The value of the archive attribute.
+     */
+    boolean isArchive();
+
+    /**
+     * Returns the value of the system attribute.
+     *
+     * <p> This attribute is often used to indicate that the file is a component
+     * of the operating system.
+     *
+     * @return  The value of the system attribute.
+     */
+    boolean isSystem();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/FileAttribute.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+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.
+ *
+ * @param <T> The type of the file attribute value
+ *
+ * @since 1.7
+ * @see PosixFilePermissions#asFileAttribute
+ */
+
+public interface FileAttribute<T> {
+    /**
+     * Returns the attribute name.
+     */
+    String name();
+
+    /**
+     * Returns the attribute value.
+     */
+    T value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/FileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * An attribute view that is a read-only or updatable view of non-opaque
+ * values associated with a file in a filesystem. This interface is extended or
+ * implemented by specific file attribute views that define methods to read
+ * and/or update the attributes of a file.
+ *
+ * @since 1.7
+ *
+ * @see java.nio.file.FileRef#getFileAttributeView(Class,java.nio.file.LinkOption[])
+ * @see java.nio.file.FileRef#getFileAttributeView(String,java.nio.file.LinkOption[])
+ */
+
+public interface FileAttributeView
+    extends AttributeView
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.io.IOException;
+
+/**
+ * A file attribute view that supports reading or updating the owner of a file.
+ * This file attribute view is intended for file system implementations that
+ * support a file attribute that represents an identity that is the owner of
+ * the file. Often the owner of a file is the identity of the entity that
+ * created the file.
+ *
+ * <p> The {@link #getOwner getOwner} or {@link #setOwner setOwner} methods may
+ * be used to read or update the owner of the file.
+ *
+ * <p> Where dynamic access to file attributes is required, the owner attribute
+ * is identified by the name {@code "owner"}, and the value of the attribute is
+ * a {@link UserPrincipal}. The {@link #readAttributes readAttributes}, {@link
+ * #getAttribute getAttribute} and {@link #setAttribute setAttributes} methods
+ * may be used to read or update the file owner.
+ *
+ * @since 1.7
+ */
+
+public interface FileOwnerAttributeView
+    extends FileAttributeView
+{
+    /**
+     * Returns the name of the attribute view. Attribute views of this type
+     * have the name {@code "owner"}.
+     */
+    @Override
+    String name();
+
+    /**
+     * Read the file owner.
+     *
+     * <p> It it implementation specific if the file owner can be a {@link
+     * GroupPrincipal group}.
+     *
+     * @return  the file owner
+     *
+     * @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}<tt>("accessUserInformation")</tt> or its
+     *          {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     */
+    UserPrincipal getOwner() throws IOException;
+
+    /**
+     * Updates the file owner.
+     *
+     * <p> It it implementation specific if the file owner can be a {@link
+     * GroupPrincipal group}. To ensure consistent and correct behavior
+     * across platforms it is recommended that this method should only be used
+     * to set the file owner to a user principal that is not a group.
+     *
+     * @param   owner
+     *          The new file owner
+     *
+     * @throws  IOException
+     *          If an I/O error occurs, or the {@code owner} parameter is a
+     *          group and this implementation does not support setting the owner
+     *          to a group
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link
+     *          RuntimePermission}<tt>("accessUserInformation")</tt> or its
+     *          {@link SecurityManager#checkWrite(String) checkWrite} method
+     *          denies write access to the file.
+     */
+    void setOwner(UserPrincipal owner) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/FileStoreAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * An attribute view that is a read-only or updatable view of the attributes of
+ * a {@link java.nio.file.FileStore}.
+ *
+ * @since 1.7
+ */
+
+public interface FileStoreAttributeView
+    extends AttributeView
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.
+ *
+ * <p> Where dynamic access to file attributes is required, the attributes
+ * supported by this attribute view have the following names and types:
+ * <blockquote>
+ * <table border="1" cellpadding="8">
+ *   <tr>
+ *     <th> Name </th>
+ *     <th> Type </th>
+ *   </tr>
+ *  <tr>
+ *     <td> "totalSpace" </td>
+ *     <td> {@link Long} </td>
+ *   </tr>
+ *  <tr>
+ *     <td> "usableSpace" </td>
+ *     <td> {@link Long} </td>
+ *   </tr>
+ *  <tr>
+ *     <td> "unallocatedSpace" </td>
+ *     <td> {@link Long} </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * <p> The {@link #getAttribute getAttribute} or {@link #readAttributes
+ * readAttributes(String,String[])} methods may be used to read any of these
+ * attributes as if by invoking the {@link #readAttributes readAttributes()}
+ * method.
+ *
+ * @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.
+     *
+     * <p> 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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/FileStoreSpaceAttributes.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.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.
+     *
+     * <p> 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.
+     *
+     * <p> 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();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/GroupPrincipal.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * A {@code UserPrincipal} representing a <em>group identity</em>, used to
+ * determine access rights to objects in a file system. The exact definition of
+ * a group is implementation specific, but typically, it represents an identity
+ * created for administrative purposes so as to determine the access rights for
+ * the members of the group. Whether an entity can be a member of multiple
+ * groups, and whether groups can be nested, are implementation specified and
+ * therefore not specified.
+ *
+ * @since 1.7
+ *
+ * @see UserPrincipalLookupService#lookupPrincipalByGroupName
+ */
+
+public interface GroupPrincipal extends UserPrincipal { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.nio.file.*;
+import java.util.Set;
+import java.io.IOException;
+
+/**
+ * A file attribute view that provides a view 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.
+ *
+ * <p> Operating systems that implement the <a href="http://www.opengroup.org">
+ * POSIX</a> family of standards commonly use file systems that have a
+ * file <em>owner</em>, <em>group-owner</em>, and related <em>access
+ * permissions</em>. This file attribute view provides read and write access
+ * to these attributes.
+ *
+ * <p> The {@link #readAttributes() readAttributes} method is used to read the
+ * file's attributes. The file {@link PosixFileAttributes#owner() owner} is
+ * represented by a {@link UserPrincipal} that is the identity of the file owner
+ * for the purposes of access control. The {@link PosixFileAttributes#group()
+ * group-owner}, represented by a {@link GroupPrincipal}, is the identity of the
+ * group owner, where a group is an identity created for administrative purposes
+ * so as to determine the access rights for the members of the group.
+ *
+ * <p> The {@link PosixFileAttributes#permissions() permissions} attribute is a
+ * set of access permissions. This file attribute view provides access to the nine
+ * permission defined by the {@link PosixFilePermission} class.
+ * These nine permission bits determine the <em>read</em>, <em>write</em>, and
+ * <em>execute</em> access for the file owner, group, and others (others
+ * meaning identities other than the owner and members of the group). Some
+ * operating systems and file systems may provide additional permission bits
+ * but access to these other bits is not defined by this class in this release.
+ *
+ * <p> <b>Usage Example:</b>
+ * Suppose we need to print out the owner and access permissions of a file:
+ * <pre>
+ *     FileRef file = ...
+ *     PosixFileAttributes attrs = file.newFileAttributeView(PosixFileAttributeView.class)
+ *         .readAttributes();
+ *     System.out.format("%s %s%n",
+ *         attrs.owner().getName(),
+ *         PosixFilePermissions.toString(attrs.permissions()));
+ * </pre>
+ *
+ * <h4> Dynamic Access </h4>
+ * <p> Where dynamic access to file attributes is required, the attributes
+ * supported by this attribute view are as defined by {@link
+ * BasicFileAttributeView} and {@link FileOwnerAttributeView}, and in addition,
+ * the following attributes are supported:
+ * <blockquote>
+ * <table border="1" cellpadding="8">
+ *   <tr>
+ *     <th> Name </th>
+ *     <th> Type </th>
+ *   </tr>
+ *  <tr>
+ *     <td> "permissions" </td>
+ *     <td> {@link Set}&lt;{@link PosixFilePermission}&gt; </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "group" </td>
+ *     <td> {@link GroupPrincipal} </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ *
+ * <p> The {@link #getAttribute getAttribute} or {@link
+ * #readAttributes(String,String[]) readAttributes(String,String[])} methods 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.
+ *
+ * <p> The {@link #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
+ * #setPermissions setPermissions}, {@link #setOwner setOwner}, and {@link
+ * #setGroup setGroup} methods respectively.
+ *
+ * <h4> Setting Initial Permissions </h4>
+ * <p> 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
+ * 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
+ * asFileAttribute} method to construct a {@code FileAttribute} when creating a
+ * file:
+ *
+ * <pre>
+ *     Path path = ...
+ *     Set&lt;PosixFilePermission&gt; perms =
+ *         EnumSet.of(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ);
+ *     path.createFile(PosixFilePermissions.asFileAttribute(perms));
+ * </pre>
+ *
+ * <p> When the access permissions are set at file creation time then the actual
+ * value of the permissions may differ that the value of the attribute object.
+ * The reasons for this are implementation specific. On UNIX systems, for
+ * example, a process has a <em>umask</em> that impacts the permission bits
+ * of newly created files. Where an implementation supports the setting of
+ * 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.
+ *
+ * @since 1.7
+ *
+ * @see Attributes#readPosixFileAttributes
+ */
+
+public interface PosixFileAttributeView
+    extends BasicFileAttributeView, FileOwnerAttributeView
+{
+    /**
+     * Returns the name of the attribute view. Attribute views of this type
+     * have the name {@code "posix"}.
+     */
+    @Override
+    String name();
+
+    /**
+     * @throws  IOException                {@inheritDoc}
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     */
+    @Override
+    PosixFileAttributes readAttributes() throws IOException;
+
+    /**
+     * Updates the file permissions.
+     *
+     * @param   perms
+     *          The new set of permissions
+     *
+     * @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, a security manager is
+     *          installed, and it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file.
+     */
+    void setPermissions(Set<PosixFilePermission> perms) throws IOException;
+
+    /**
+     * Updates the file group-owner.
+     *
+     * @param   group
+     *          The new file group-owner
+
+     * @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}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file.
+     */
+    void setGroup(GroupPrincipal group) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/PosixFileAttributes.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.util.Set;
+
+/**
+ * File attributes associated with files on file systems used by operating systems
+ * that implement the Portable Operating System Interface (POSIX) family of
+ * standards.
+ *
+ * <p> The POSIX attributes of a file are retrieved using a {@link
+ * PosixFileAttributeView} by invoking its {@link
+ * PosixFileAttributeView#readAttributes readAttributes} method.
+ *
+ * @since 1.7
+ *
+ * @see Attributes#readPosixFileAttributes
+ */
+
+public interface PosixFileAttributes
+    extends BasicFileAttributes
+{
+    /**
+     * Returns the owner of the file.
+     *
+     * @return  The file owner
+     *
+     * @see PosixFileAttributeView#setOwner
+     */
+    UserPrincipal owner();
+
+    /**
+     * Returns the group owner of the file.
+     *
+     * @return  The file group owner
+     *
+     * @see PosixFileAttributeView#setGroup
+     */
+    GroupPrincipal group();
+
+    /**
+     * Returns the permissions of the file. The file permissions are returned
+     * as a set of {@link PosixFilePermission} elements. The returned set is a
+     * copy of the file permissions and is modifiable. This allows the result
+     * to be modified and passed to the {@link PosixFileAttributeView#setPermissions
+     * setPermissions} method to update the file's permissions.
+     *
+     * @return  The file permissions
+     *
+     * @see PosixFileAttributeView#setPermissions
+     */
+    Set<PosixFilePermission> permissions();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/PosixFilePermission.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.util.*;
+
+/**
+ * Defines the bits for use with the {@link PosixFileAttributes#permissions()
+ * permissions} attribute.
+ *
+ * <p> The {@link PosixFileAttributes} class defines method methods for
+ * manipulating {@link Set sets} of permissions.
+ *
+ * @since 1.7
+ */
+
+public enum PosixFilePermission {
+
+    /**
+     * Read permission, owner.
+     */
+    OWNER_READ,
+
+    /**
+     * Write permission, owner.
+     */
+    OWNER_WRITE,
+
+    /**
+     * Execute/search permission, owner.
+     */
+    OWNER_EXECUTE,
+
+    /**
+     * Read permission, group.
+     */
+    GROUP_READ,
+
+    /**
+     * Write permission, group.
+     */
+    GROUP_WRITE,
+
+    /**
+     * Execute/search permission, group.
+     */
+    GROUP_EXECUTE,
+
+    /**
+     * Read permission, others.
+     */
+    OTHERS_READ,
+
+    /**
+     * Write permission, others.
+     */
+    OTHERS_WRITE,
+
+    /**
+     * Execute/search permission, others.
+     */
+    OTHERS_EXECUTE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/PosixFilePermissions.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import static java.nio.file.attribute.PosixFilePermission.*;
+import java.util.*;
+
+/**
+ * This class consists exclusively of static methods that operate on sets of
+ * {@link PosixFilePermission} objects.
+ *
+ * @since 1.7
+ */
+
+public class PosixFilePermissions {
+    private PosixFilePermissions() { }
+
+    // Write string representation of permission bits to {@code sb}.
+    private static void writeBits(StringBuilder sb, boolean r, boolean w, boolean x) {
+        if (r) {
+            sb.append('r');
+        } else {
+            sb.append('-');
+        }
+        if (w) {
+            sb.append('w');
+        } else {
+            sb.append('-');
+        }
+        if (x) {
+            sb.append('x');
+        } else {
+            sb.append('-');
+        }
+    }
+
+    /**
+     * Returns the {@code String} representation of a set of permissions.
+     *
+     * <p> If the set contains {@code null} or elements that are not of type
+     * {@code PosixFilePermission} then these elements are ignored.
+     *
+     * @param   perms
+     *          The set of permissions
+     *
+     * @return  The string representation of the permission set
+     *
+     * @see #fromString
+     */
+    public static String toString(Set<PosixFilePermission> perms) {
+        StringBuilder sb = new StringBuilder(9);
+        writeBits(sb, perms.contains(OWNER_READ), perms.contains(OWNER_WRITE),
+          perms.contains(OWNER_EXECUTE));
+        writeBits(sb, perms.contains(GROUP_READ), perms.contains(GROUP_WRITE),
+          perms.contains(GROUP_EXECUTE));
+        writeBits(sb, perms.contains(OTHERS_READ), perms.contains(OTHERS_WRITE),
+          perms.contains(OTHERS_EXECUTE));
+        return sb.toString();
+    }
+
+    private static boolean isSet(char c, char setValue) {
+        if (c == setValue)
+            return true;
+        if (c == '-')
+            return false;
+        throw new IllegalArgumentException("Invalid mode");
+    }
+    private static boolean isR(char c) { return isSet(c, 'r'); }
+    private static boolean isW(char c) { return isSet(c, 'w'); }
+    private static boolean isX(char c) { return isSet(c, 'x'); }
+
+    /**
+     * Returns the set of permissions corresponding to a given {@code String}
+     * representation.
+     *
+     * <p> The {@code perms} parameter is a {@code String} representing the
+     * permissions. It has 9 characters that are interpreted as three sets of
+     * three. The first set refers to the owner's permissions; the next to the
+     * group permissions and the last to others. Within each set, the first
+     * character is {@code 'r'} to indicate permission to read, the second
+     * character is {@code 'w'} to indicate permission to write, and the third
+     * character is {@code 'x'} for execute permission. Where a permission is
+     * not set then the corresponding character is set to {@code '-'}.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we require the set of permissions that indicate the owner has read,
+     * write, and execute permissions, the group has read and execute permissions
+     * and others have none.
+     * <pre>
+     *   Set&lt;PosixFilePermission&gt; perms = PosixFilePermissions.fromString("rwxr-x---");
+     * </pre>
+     *
+     * @param   perms
+     *          String representing a set of permissions
+     *
+     * @return  The resulting set of permissions
+     *
+     * @throws  IllegalArgumentException
+     *          If the string cannot be converted to a set of permissions
+     *
+     * @see #toString(Set)
+     */
+    public static Set<PosixFilePermission> fromString(String perms) {
+        if (perms.length() != 9)
+            throw new IllegalArgumentException("Invalid mode");
+        Set<PosixFilePermission> result = new HashSet<PosixFilePermission>();
+        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);
+        if (isR(perms.charAt(3))) result.add(GROUP_READ);
+        if (isW(perms.charAt(4))) result.add(GROUP_WRITE);
+        if (isX(perms.charAt(5))) result.add(GROUP_EXECUTE);
+        if (isR(perms.charAt(6))) result.add(OTHERS_READ);
+        if (isW(perms.charAt(7))) result.add(OTHERS_WRITE);
+        if (isX(perms.charAt(8))) result.add(OTHERS_EXECUTE);
+        return result;
+    }
+
+    /**
+     * 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}
+     * methods.
+     *
+     * @param   perms
+     *          The set of permissions
+     *
+     * @return  An attribute encapsulating the given file permissions with
+     *          {@link FileAttribute#name name} {@code "posix:permissions"}
+     *
+     * @throws  ClassCastException
+     *          If the sets contains elements that are not of type {@code
+     *          PosixFilePermission}
+     */
+    public static FileAttribute<Set<PosixFilePermission>>
+        asFileAttribute(Set<PosixFilePermission> perms)
+    {
+        // copy set and check for nulls (CCE will be thrown if an element is not
+        // a PosixFilePermission)
+        perms = new HashSet<PosixFilePermission>(perms);
+        for (PosixFilePermission p: perms) {
+            if (p == null)
+                throw new NullPointerException();
+        }
+        final Set<PosixFilePermission> value = perms;
+        return new FileAttribute<Set<PosixFilePermission>>() {
+            @Override
+            public String name() {
+                return "posix:permissions";
+            }
+            @Override
+            public Set<PosixFilePermission> value() {
+                return Collections.unmodifiableSet(value);
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/UserDefinedFileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.io.IOException;
+
+/**
+ * A file attribute view that provides a view of a file's user-defined
+ * attributes, sometimes known as <em>extended attributes</em>. User-defined
+ * file attributes are used to store metadata with a file that is not meaningful
+ * to the file system. It is primarily intended for file system implementations
+ * that support such a capability directly but may be emulated. The details of
+ * such emulation are highly implementation specific and therefore not specified.
+ *
+ * <p> This {@code FileAttributeView} provides a view of a file's user-defined
+ * attributes as a set of name/value pairs, where the attribute name is
+ * represented by a {@code String}. An implementation may require to encode and
+ * decode from the platform or file system representation when accessing the
+ * attribute. The value has opaque content. This attribute view defines the
+ * {@link #read read} and {@link #write write} methods to read the value into
+ * or write from a {@link ByteBuffer}. This {@code FileAttributeView} is not
+ * intended for use where the size of an attribute value is larger than {@link
+ * Integer#MAX_VALUE}.
+ *
+ * <p> User-defined attributes may be used in some implementations to store
+ * security related attributes so consequently, in the case of the default
+ * provider at least, all methods that access user-defined attributes require the
+ * {@code RuntimePermission("accessUserDefinedAttributes")} permission when a
+ * security manager is installed.
+ *
+ * <p> The {@link java.nio.file.FileStore#supportsFileAttributeView
+ * supportsFileAttributeView} method may be used to test if a specific {@link
+ * java.nio.file.FileStore FileStore} supports the storage of user-defined
+ * attributes.
+ *
+ * <p> Where dynamic access to file attributes is required, the {@link
+ * #getAttribute getAttribute} or {@link #readAttributes(String,String[])
+ * readAttributes(String,String[])} methods may be used to read the attribute
+ * value. The attribute value is returned as a byte array (byte[]). The {@link
+ * #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[]).
+ *
+ * @since 1.7
+ */
+
+public interface UserDefinedFileAttributeView
+    extends FileAttributeView
+{
+    /**
+     * Returns the name of this attribute view. Attribute views of this type
+     * have the name {@code "xattr"}.
+     */
+    @Override
+    String name();
+
+    /**
+     * Returns a list containing the names of the user-defined attributes.
+     *
+     * @return  An unmodifiable list continaing the names of the file's
+     *          user-defined
+     *
+     * @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}<tt>("accessUserDefinedAttributes")</tt>
+     *          or its {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     */
+    List<String> list() throws IOException;
+
+    /**
+     * Returns the size of the value of a user-defined attribute.
+     *
+     * @param   name
+     *          The attribute name
+     *
+     * @return  The size of the attribute value, in bytes.
+     *
+     * @throws  ArithmeticException
+     *          If the size of the attribute is larger than {@link Integer#MAX_VALUE}
+     * @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}<tt>("accessUserDefinedAttributes")</tt>
+     *          or its {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     */
+    int size(String name) throws IOException;
+
+    /**
+     * Read the value of a user-defined attribute into a buffer.
+     *
+     * <p> This method reads the value of the attribute into the given buffer
+     * as a sequence of bytes, failing if the number of bytes remaining in
+     * the buffer is insufficient to read the complete attribute value. The
+     * number of bytes transferred into the buffer is {@code n}, where {@code n}
+     * is the size of the attribute value. The first byte in the sequence is at
+     * index {@code p} and the last byte is at index {@code p + n - 1}, where
+     * {@code p} is the buffer's position. Upon return the buffer's position
+     * will be equal to {@code p + n}; its limit will not have changed.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to read a file's MIME type that is stored as a user-defined
+     * attribute with the name "{@code user.mimetype}".
+     * <pre>
+     *    UserDefinedFileAttributeView view = file
+     *        .getFileAttributeView(UserDefinedFileAttributeView.class);
+     *    String name = "user.mimetype";
+     *    ByteBuffer buf = ByteBuffer.allocate(view.size(name));
+     *    view.read(name, buf);
+     *    buf.flip();
+     *    String value = Charset.defaultCharset().decode(buf).toString();
+     * </pre>
+     *
+     * @param   name
+     *          The attribute name
+     * @param   dst
+     *          The destination buffer
+     *
+     * @return  The number of bytes read, possibly zero
+     *
+     * @throws  IllegalArgumentException
+     *          If the destination buffer is read-only
+     * @throws  IOException
+     *          If an I/O error occurs or there is insufficient space in the
+     *          destination buffer for the attribute value
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link
+     *          RuntimePermission}<tt>("accessUserDefinedAttributes")</tt>
+     *          or its {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     *
+     * @see #size
+     */
+    int read(String name, ByteBuffer dst) throws IOException;
+
+    /**
+     * Writes the value of a user-defined attribute from a buffer.
+     *
+     * <p> This method writes the value of the attribute from a given buffer as
+     * a sequence of bytes. The size of the value to transfer is {@code r},
+     * where {@code r} is the number of bytes remaining in the buffer, that is
+     * {@code src.remaining()}. The sequence of bytes is transferred from the
+     * buffer starting at index {@code p}, where {@code p} is the buffer's
+     * position. Upon return, the buffer's position will be equal to {@code
+     * p + n}, where {@code n} is the number of bytes transferred; its limit
+     * will not have changed.
+     *
+     * <p> If an attribute of the given name already exists then its value is
+     * replaced. If the attribute does not exist then it is created. If it
+     * implementation specific if a test to check for the existence of the
+     * attribute and the creation of attribute are atomic with repect to other
+     * file system activities.
+     *
+     * <p> Where there is insufficient space to store the attribute, or the
+     * attribute name or value exceed an implementation specific maximum size
+     * then an {@code IOException} is thrown.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to write a file's MIME type as a user-defined attribute:
+     * <pre>
+     *    UserDefinedFileAttributeView view = file
+     *        .getFileAttributeView(UserDefinedFileAttributeView.class);
+     *    view.write("user.mimetype", Charset.defaultCharset().encode("text/html"));
+     * </pre>
+     *
+     * @param   name
+     *          The attribute name
+     * @param   src
+     *          The buffer containing the attribute value
+     *
+     * @return  The number of bytes written, possibly zero
+     *
+     * @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}<tt>("accessUserDefinedAttributes")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file.
+     */
+    int write(String name, ByteBuffer src) throws IOException;
+
+    /**
+     * Deletes a user-defined attribute.
+     *
+     * @param   name
+     *          The attribute name
+     *
+     * @throws  IOException
+     *          If an I/O error occurs or the attribute does not exist
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link
+     *          RuntimePermission}<tt>("accessUserDefinedAttributes")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file.
+     */
+    void delete(String name) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/UserPrincipal.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.security.Principal;
+
+/**
+ * A {@code Principal} representing an identity used to determine access rights
+ * to objects in a file system.
+ *
+ * <p> On many platforms and file systems an entity requires appropriate access
+ * rights or permissions in order to access objects in a file system. The
+ * access rights are generally performed by checking the identity of the entity.
+ * For example, on implementations that use Access Control Lists (ACLs) to
+ * enforce privilege separation then a file in the file system may have an
+ * associated ACL that determines the access rights of identities specified in
+ * the ACL.
+ *
+ * <p> A {@code UserPrincipal} object is an abstract representation of an
+ * identity. It has a {@link #getName() name} that is typically the username or
+ * account name that it represents. User principal objects may be obtained using
+ * a {@link UserPrincipalLookupService}, or returned by {@link
+ * FileAttributeView} implementations that provide access to identity related
+ * attributes. For example, the {@link AclFileAttributeView} and {@link
+ * PosixFileAttributeView} provide access to a file's {@link
+ * PosixFileAttributes#owner owner}.
+ *
+ * @since 1.7
+ */
+
+public interface UserPrincipal extends Principal { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/UserPrincipalLookupService.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.io.IOException;
+
+/**
+ * An object to lookup user and group principals by name. A {@link UserPrincipal}
+ * represents an identity that may be used to determine access rights to objects
+ * in a file system. A {@link GroupPrincipal} represents a <em>group identity</em>.
+ * A {@code UserPrincipalLookupService} defines methods to lookup identities by
+ * name or group name (which are typically user or account names). Whether names
+ * and group names are case sensitive or not depends on the implementation.
+ * The exact definition of a group is implementation specific but typically a
+ * group represents an identity created for administrative purposes so as to
+ * determine the access rights for the members of the group. In particular it is
+ * implementation specific if the <em>namespace</em> for names and groups is the
+ * same or is distinct. To ensure consistent and correct behavior across
+ * platforms it is recommended that this API be used as if the namespaces are
+ * distinct. In other words, the {@link #lookupPrincipalByName
+ * lookupPrincipalByName} should be used to lookup users, and {@link
+ * #lookupPrincipalByGroupName lookupPrincipalByGroupName} should be used to
+ * lookup groups.
+ *
+ * @since 1.7
+ *
+ * @see java.nio.file.FileSystem#getUserPrincipalLookupService
+ */
+
+public abstract class UserPrincipalLookupService {
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected UserPrincipalLookupService() {
+    }
+
+    /**
+     * Lookup a user principal by name.
+     *
+     * @param   name
+     *          The string representation of the user principal to lookup
+     *
+     * @return  A user principal
+     *
+     * @throws  UserPrincipalNotFoundException
+     *          The principal does not exist
+     * @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 {@link RuntimePermission}<tt>("lookupUserInformation")</tt>
+     */
+    public abstract UserPrincipal lookupPrincipalByName(String name)
+        throws IOException;
+
+    /**
+     * Lookup a group principal by group name.
+     *
+     * <p> Where an implementation does not support any notion of group then
+     * this method always throws {@link UserPrincipalNotFoundException}. Where
+     * the namespace for user accounts and groups is the same, then this method
+     * is identical to invoking {@link #lookupPrincipalByName
+     * lookupPrincipalByName}.
+     *
+     * @param   group
+     *          The string representation of the group to lookup
+     *
+     * @return  A user principal.
+     *
+     * @throws  UserPrincipalNotFoundException
+     *          The principal does not exist or is not a group
+     * @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 {@link RuntimePermission}<tt>("lookupUserInformation")</tt>
+     */
+    public abstract GroupPrincipal lookupPrincipalByGroupName(String group)
+        throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/UserPrincipalNotFoundException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.io.IOException;
+
+/**
+ * Checked exception thrown when a lookup of {@link UserPrincipal} fails because
+ * the principal does not exist.
+ *
+ * @since 1.7
+ */
+
+public class UserPrincipalNotFoundException
+    extends IOException
+{
+    static final long serialVersionUID = -5369283889045833024L;
+
+    private final String name;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   name
+     *          The principal name; may be {@code null}
+     */
+    public UserPrincipalNotFoundException(String name) {
+        super();
+        this.name = name;
+    }
+
+    /**
+     * Returns the user principal name if this exception was created with the
+     * user principal name that was not found, otherwise <tt>null</tt>.
+     *
+     * @return  The user principal name or {@code null}
+     */
+    public String getName() {
+        return name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/attribute/package-info.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * Interfaces and classes providing access to file and file system attributes.
+ *
+ * <blockquote><table cellspacing=1 cellpadding=0 summary="Attribute views">
+ * <tr><th><p align="left">Attribute views</p></th><th><p align="left">Description</p></th></tr>
+ * <tr><td valign=top><tt><i>{@link java.nio.file.attribute.AttributeView}</i></tt></td>
+ *     <td>Can read or update non-opaque values associated with objects in a file system</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.file.attribute.FileAttributeView}</i></tt></td>
+ *     <td>Can read or update file attributes</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.file.attribute.BasicFileAttributeView}&nbsp;&nbsp;</i></tt></td>
+ *     <td>Can read or update a basic set of file attributes</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.file.attribute.PosixFileAttributeView}&nbsp;&nbsp;</i></tt></td>
+ *     <td>Can read or update POSIX defined file attributes</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.file.attribute.DosFileAttributeView}&nbsp;&nbsp;</i></tt></td>
+ *     <td>Can read or update FAT file attributes</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp<i>{@link java.nio.file.attribute.FileOwnerAttributeView}&nbsp;&nbsp;</i></tt></td>
+ *     <td>Can read or update the owner of a file</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.file.attribute.AclFileAttributeView}&nbsp;&nbsp;</i></tt></td>
+ *     <td>Can read or update Access Control Lists</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.file.attribute.UserDefinedFileAttributeView}&nbsp;&nbsp;</i></tt></td>
+ *     <td>Can read or update user-defined file attributes</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.file.attribute.FileStoreAttributeView}</i></tt></td>
+ *     <td>Can read or update file system attributes</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.file.attribute.FileStoreSpaceAttributeView}&nbsp;&nbsp;</i></tt></td>
+ *     <td>Can read file system <em>space usage</em> related attributes</td></tr>
+ * </table></blockquote>
+ *
+ * <p> An attribute view provides a read-only or updatable view of the non-opaque
+ * values, or <em>metadata</em>, associated with objects in a file system.
+ * 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
+ * <em>type-token</em> 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
+ * a given type is obtained by invoking the {@link
+ * java.nio.file.FileStore#getFileStoreAttributeView} method.
+ *
+ * <p> The {@link java.nio.file.attribute.BasicFileAttributeView}
+ * class defines methods to read and update a <em>basic</em> set of file
+ * attributes that are common to many file systems.
+ *
+ * <p> The {@link java.nio.file.attribute.PosixFileAttributeView}
+ * interface extends {@code BasicFileAttributeView} by defining methods
+ * to access the file attributes commonly used by file systems and operating systems
+ * that implement the Portable Operating System Interface (POSIX) family of
+ * standards.
+ *
+ * <p> The {@link java.nio.file.attribute.DosFileAttributeView}
+ * class extends {@code BasicFileAttributeView} by defining methods to
+ * access the legacy "DOS" file attributes supported on file systems such as File
+ * Allocation Tabl (FAT), commonly used in consumer devices.
+ *
+ * <p> The {@link java.nio.file.attribute.AclFileAttributeView}
+ * class defines methods to read and write the Access Control List (ACL)
+ * file attribute. The ACL model used by this file attribute view is based
+ * on the model defined by <a href="http://www.ietf.org/rfc/rfc3530.txt">
+ * <i>RFC&nbsp;3530: Network File System (NFS) version 4 Protocol</i></a>.
+ *
+ * <p> The {@link java.nio.file.attribute.FileStoreSpaceAttributeView} class
+ * defines methods to read file system space usage related attributes of a file system.
+ *
+ * <p> The {@link java.nio.file.attribute.Attributes} utility class defines
+ * static methods to access file or file system attribute using the above
+ * attribute views.
+ *
+ * <p> In addition to attribute views, this package also defines classes and
+ * interfaces that are used when accessing attributes:
+ *
+ * <ul>
+ *
+ *   <p><li> The {@link java.nio.file.attribute.UserPrincipal} and
+ *   {@link java.nio.file.attribute.GroupPrincipal} interfaces represent an
+ *   identity or group identity. </li>
+ *
+ *   <p><li> The {@link java.nio.file.attribute.UserPrincipalLookupService}
+ *   interface defines methods to lookup user or group principals. </li>
+ *
+ *   <p><li> The {@link java.nio.file.attribute.Attribute} interface
+ *   represents the value of an attribute for cases where the attribute value is
+ *   require to be set atomically when creating an object in the file system. </li>
+ *
+ * </ul>
+ *
+ *
+ * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
+ * or method in any class or interface in this package will cause a {@link
+ * java.lang.NullPointerException NullPointerException} to be thrown.
+ *
+ * @since 1.7
+ */
+
+package java.nio.file.attribute;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/package-info.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * Define interfaces and classes for the Java virtual machine to access files,
+ * file attributes, and file systems.
+ *
+ * <p> The java.nio.file package defines classes to access files and file
+ * 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.
+ *
+ * <a name="links"><h3>Symbolic Links</h3></a>
+ * Many operating systems and file systems support for <em>symbolic links</em>.
+ * A symbolic link is a special file that serves as a reference to another file.
+ * For the most part, symbolic links are transparent to applications and
+ * operations on symbolic links are automatically redirected to the <em>target</em>
+ * of the link. Exceptions to this are when a symbolic link is deleted or
+ * renamed/moved in which case the link is deleted or removed rather than the
+ * 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.
+ *
+ * <a name="interop"><h3>Interoperability</h3></a>
+ * The {@link java.io.File} class defines the {@link java.io.File#toPath
+ * toPath} method to construct a {@link java.nio.file.Path} by converting
+ * the abstract path represented by the {@code java.io.File} object. The resulting
+ * {@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 <a href="Path.html#interop">interoperability</a> between {@code Path}
+ * and {@code java.io.File} objects.
+ *
+ * <h3>Visibility</h3>
+ * The view of the files and file system provided by classes in this package are
+ * guaranteed to be consistent with other views provided by other instances in the
+ * same Java virtual machine.  The view may or may not, however, be consistent with
+ * the view of the file system as seen by other concurrently running programs due
+ * to caching performed by the underlying operating system and delays induced by
+ * 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.
+ *
+ * <a name="integrity"><h3>Synchronized I/O File Integrity</h3></a>
+ * The {@link java.nio.file.StandardOpenOption#SYNC SYNC} and {@link
+ * java.nio.file.StandardOpenOption#DSYNC DSYNC} options are used when opening a file
+ * to require that updates to the file are written synchronously to the underlying
+ * storage device. In the case of the default provider, and the file resides on
+ * a local storage device, and the {@link java.nio.channels.SeekableByteChannel
+ * seekable} channel is connected to a file that was opened with one of these
+ * options, then an invocation of the {@link
+ * java.nio.channels.WritableByteChannel#write(java.nio.ByteBuffer) write}
+ * method is only guaranteed to return when all changes made to the file
+ * by that invocation have been written to the device. These options are useful
+ * for ensuring that critical information is not lost in the event of a system
+ * 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.
+ *
+ * <h3>General Exceptions</h3>
+ * 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.
+ *
+ * <p> Unless otherwise noted, methods that attempt to access the file system
+ * will throw {@link java.nio.file.ClosedFileSystemException} when invoked on
+ * objects associated with a {@link java.nio.file.FileSystem} that has been
+ * {@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.
+ *
+ * <p> 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}.
+ *
+ * <h3>Optional Specific Exceptions</h3>
+ * Most of the methods defined by classes in this package that access the
+ * file system specify that {@link java.io.IOException} be thrown when an I/O
+ * error occurs. In some cases, these methods define specific I/O exceptions
+ * for common cases. These exceptions, noted as <i>optional specific exceptions</i>,
+ * are thrown by the implementation where it can detect the specific error.
+ * Where the specific error cannot be detected then the more general {@code
+ * IOException} is thrown.
+ *
+ * @since 1.7
+ */
+package java.nio.file;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/spi/AbstractPath.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,568 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.spi;
+
+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.*;
+
+/**
+ * Base implementation class for a {@code Path}.
+ *
+ * <p> This class is intended to be extended by provider implementors. It
+ * implements, or provides default implementations for several of the methods
+ * defined by the {@code Path} class. It implements the {@link #copyTo copyTo}
+ * and {@link #moveTo moveTo} methods for the case that the source and target
+ * are not associated with the same provider.
+ *
+ * @since 1.7
+ */
+
+public abstract class AbstractPath extends Path {
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected AbstractPath() { }
+
+    /**
+     * Deletes the file referenced by this object.
+     *
+     * <p> This method invokes the {@link #delete(boolean) delete(boolean)}
+     * method with a parameter of {@code true}. It may be overridden where
+     * required.
+     *
+     * @throws  NoSuchFileException             {@inheritDoc}
+     * @throws  DirectoryNotEmptyException      {@inheritDoc}
+     * @throws  IOException                     {@inheritDoc}
+     * @throws  SecurityException               {@inheritDoc}
+     */
+    @Override
+    public void delete() throws IOException {
+        delete(true);
+    }
+
+    /**
+     * Creates a new and empty file, failing if the file already exists.
+     *
+     * <p> This method invokes the {@link #newByteChannel(Set,FileAttribute[])
+     * newByteChannel(Set,FileAttribute...)} method to create the file. It may be
+     * overridden where required.
+     *
+     * @throws  IllegalArgumentException        {@inheritDoc}
+     * @throws  FileAlreadyExistsException      {@inheritDoc}
+     * @throws  IOException                     {@inheritDoc}
+     * @throws  SecurityException               {@inheritDoc}
+     */
+    @Override
+    public Path createFile(FileAttribute<?>... attrs)
+        throws IOException
+    {
+        EnumSet<StandardOpenOption> options = EnumSet.of(CREATE_NEW, WRITE);
+        SeekableByteChannel sbc = newByteChannel(options, attrs);
+        try {
+            sbc.close();
+        } catch (IOException x) {
+            // ignore
+        }
+        return this;
+    }
+
+    /**
+     * Opens or creates a file, returning a seekable byte channel to access the
+     * file.
+     *
+     * <p> This method invokes the {@link #newByteChannel(Set,FileAttribute[])
+     * newByteChannel(Set,FileAttribute...)} method to open or create the file.
+     * It may be overridden where required.
+     *
+     * @throws  IllegalArgumentException        {@inheritDoc}
+     * @throws  FileAlreadyExistsException      {@inheritDoc}
+     * @throws  IOException                     {@inheritDoc}
+     * @throws  SecurityException               {@inheritDoc}
+     */
+    @Override
+    public SeekableByteChannel newByteChannel(OpenOption... options)
+        throws IOException
+    {
+        Set<OpenOption> set = new HashSet<OpenOption>(options.length);
+        Collections.addAll(set, options);
+        return newByteChannel(set);
+    }
+
+    /**
+     * Opens the file located by this path for reading, returning an input
+     * stream to read bytes from the file.
+     *
+     * <p> This method returns an {@code InputStream} that is constructed by
+     * invoking the {@link java.nio.channels.Channels#newInputStream
+     * Channels.newInputStream} method. It may be overridden where a more
+     * efficient implementation is available.
+     *
+     * @throws  IOException                     {@inheritDoc}
+     * @throws  SecurityException               {@inheritDoc}
+     */
+    @Override
+    public InputStream newInputStream() throws IOException {
+        return Channels.newInputStream(newByteChannel());
+    }
+
+    // opts must be modifiable
+    private OutputStream implNewOutputStream(Set<OpenOption> opts,
+                                             FileAttribute<?>... attrs)
+        throws IOException
+    {
+        if (opts.isEmpty()) {
+            opts.add(CREATE);
+            opts.add(TRUNCATE_EXISTING);
+        } else {
+            if (opts.contains(READ))
+                throw new IllegalArgumentException("READ not allowed");
+        }
+        opts.add(WRITE);
+        return Channels.newOutputStream(newByteChannel(opts, attrs));
+    }
+
+    /**
+     * Opens or creates the file located by this path for writing, returning an
+     * output stream to write bytes to the file.
+     *
+     * <p> This method returns an {@code OutputStream} that is constructed by
+     * invoking the {@link java.nio.channels.Channels#newOutputStream
+     * Channels.newOutputStream} method. It may be overridden where a more
+     * efficient implementation is available.
+     *
+     * @throws  IllegalArgumentException        {@inheritDoc}
+     * @throws  IOException                     {@inheritDoc}
+     * @throws  SecurityException               {@inheritDoc}
+     */
+    @Override
+    public OutputStream newOutputStream(OpenOption... options) throws IOException {
+        int len = options.length;
+        Set<OpenOption> opts = new HashSet<OpenOption>(len + 3);
+        if (len > 0) {
+            for (OpenOption opt: options) {
+                opts.add(opt);
+            }
+        }
+        return implNewOutputStream(opts);
+    }
+
+    /**
+     * Opens or creates the file located by this path for writing, returning an
+     * output stream to write bytes to the file.
+     *
+     * <p> This method returns an {@code OutputStream} that is constructed by
+     * invoking the {@link java.nio.channels.Channels#newOutputStream
+     * Channels.newOutputStream} method. It may be overridden where a more
+     * efficient implementation is available.
+     *
+     * @throws  IllegalArgumentException        {@inheritDoc}
+     * @throws  IOException                     {@inheritDoc}
+     * @throws  SecurityException               {@inheritDoc}
+     */
+    @Override
+    public OutputStream newOutputStream(Set<? extends OpenOption> options,
+                                        FileAttribute<?>... attrs)
+        throws IOException
+    {
+        Set<OpenOption> opts = new HashSet<OpenOption>(options);
+        return implNewOutputStream(opts, attrs);
+    }
+
+    /**
+     * Opens the directory referenced by this object, returning a {@code
+     * DirectoryStream} to iterate over all entries in the directory.
+     *
+     * <p> This method invokes the {@link
+     * #newDirectoryStream(java.nio.file.DirectoryStream.Filter)
+     * newDirectoryStream(Filter)} method with a filter that accept all entries.
+     * It may be overridden where required.
+     *
+     * @throws  NotDirectoryException           {@inheritDoc}
+     * @throws  IOException                     {@inheritDoc}
+     * @throws  SecurityException               {@inheritDoc}
+     */
+    @Override
+    public DirectoryStream<Path> newDirectoryStream() throws IOException {
+        return newDirectoryStream(acceptAllFilter);
+    }
+    private static final DirectoryStream.Filter<Path> acceptAllFilter =
+        new DirectoryStream.Filter<Path>() {
+            @Override public boolean accept(Path entry) { return true; }
+        };
+
+    /**
+     * Opens the directory referenced by this object, returning a {@code
+     * DirectoryStream} to iterate over the entries in the directory. The
+     * entries are filtered by matching the {@code String} representation of
+     * their file names against a given pattern.
+     *
+     * <p> This method constructs a {@link PathMatcher} by invoking the
+     * file system's {@link java.nio.file.FileSystem#getPathMatcher
+     * getPathMatcher} method. This method may be overridden where a more
+     * efficient implementation is available.
+     *
+     * @throws  java.util.regex.PatternSyntaxException  {@inheritDoc}
+     * @throws  UnsupportedOperationException   {@inheritDoc}
+     * @throws  NotDirectoryException           {@inheritDoc}
+     * @throws  IOException                     {@inheritDoc}
+     * @throws  SecurityException               {@inheritDoc}
+     */
+    @Override
+    public DirectoryStream<Path> 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<Path> filter = new DirectoryStream.Filter<Path>() {
+            @Override
+            public boolean accept(Path entry)  {
+                return matcher.matches(entry.getName());
+            }
+        };
+        return newDirectoryStream(filter);
+    }
+
+    /**
+     * Tests whether the file located by this path exists.
+     *
+     * <p> This method invokes the {@link #checkAccess checkAccess} method to
+     * check if the file exists. It may be  overridden where a more efficient
+     * implementation is available.
+     */
+    @Override
+    public boolean exists() {
+        try {
+            checkAccess();
+            return true;
+        } catch (IOException x) {
+            // unable to determine if file exists
+        }
+        return false;
+    }
+
+    /**
+     * Tests whether the file located by this path does not exist.
+     *
+     * <p> This method invokes the {@link #checkAccess checkAccess} method to
+     * check if the file exists. It may be  overridden where a more efficient
+     * implementation is available.
+     */
+    @Override
+    public boolean notExists() {
+        try {
+            checkAccess();
+            return false;
+        } catch (NoSuchFileException x) {
+            // file confirmed not to exist
+            return true;
+        } catch (IOException x) {
+            return false;
+        }
+    }
+
+    /**
+     * Registers the file located by this path with a watch service.
+     *
+     * <p> This method invokes the {@link #register(WatchService,WatchEvent.Kind[],WatchEvent.Modifier[])
+     * register(WatchService,WatchEvent.Kind[],WatchEvent.Modifier...)}
+     * method to register the file. It may be  overridden where required.
+     */
+    @Override
+    public WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events)
+        throws IOException
+    {
+        return register(watcher, events, NO_MODIFIERS);
+    }
+    private static final WatchEvent.Modifier[] NO_MODIFIERS = new WatchEvent.Modifier[0];
+
+    /**
+     * Copy the file located by this path to a target location.
+     *
+     * <p> This method is invoked by the {@link #copyTo copyTo} method for
+     * the case that this {@code Path} and the target {@code Path} are
+     * associated with the same provider.
+     *
+     * @param   target
+     *          The target location
+     * @param   options
+     *          Options specifying how the copy should be done
+     *
+     * @throws  IllegalArgumentException
+     *          If an invalid option is specified
+     * @throws  FileAlreadyExistsException
+     *          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 <i>(optional specific exception)</i>
+     * @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")}.
+     */
+    protected abstract void implCopyTo(Path target, CopyOption... options)
+        throws IOException;
+
+    /**
+     * Move the file located by this path to a target location.
+     *
+     * <p> This method is invoked by the {@link #moveTo moveTo} method for
+     * the case that this {@code Path} and the target {@code Path} are
+     * associated with the same provider.
+     *
+     * @param   target
+     *          The target location
+     * @param   options
+     *          Options specifying how the move should be done
+     *
+     * @throws  IllegalArgumentException
+     *          If an invalid option is specified
+     * @throws  FileAlreadyExistsException
+     *          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
+     *          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.
+     */
+    protected abstract void implMoveTo(Path target, CopyOption... options)
+        throws IOException;
+
+    /**
+     * Copy the file located by this path to a target location.
+     *
+     * <p> If this path is associated with the same {@link FileSystemProvider
+     * provider} as the {@code target} then the {@link #implCopyTo implCopyTo}
+     * method is invoked to copy the file. Otherwise, this method attempts to
+     * copy the file to the target location in a manner that may be less
+     * efficient than would be the case that target is associated with the same
+     * provider as this path.
+     *
+     * @throws  IllegalArgumentException            {@inheritDoc}
+     * @throws  FileAlreadyExistsException          {@inheritDoc}
+     * @throws  IOException                         {@inheritDoc}
+     * @throws  SecurityException                   {@inheritDoc}
+     */
+    @Override
+    public final Path copyTo(Path target, CopyOption... options)
+        throws IOException
+    {
+        if ((getFileSystem().provider() == target.getFileSystem().provider())) {
+            implCopyTo(target, options);
+        } else {
+            xProviderCopyTo(target, options);
+        }
+        return target;
+    }
+
+    /**
+     * Move or rename the file located by this path to a target location.
+     *
+     * <p> If this path is associated with the same {@link FileSystemProvider
+     * provider} as the {@code target} then the {@link #implCopyTo implMoveTo}
+     * method is invoked to move the file. Otherwise, this method attempts to
+     * copy the file to the target location and delete the source file. This
+     * implementation may be less efficient than would be the case that
+     * target is associated with the same provider as this path.
+     *
+     * @throws  IllegalArgumentException            {@inheritDoc}
+     * @throws  FileAlreadyExistsException          {@inheritDoc}
+     * @throws  IOException                         {@inheritDoc}
+     * @throws  SecurityException                   {@inheritDoc}
+     */
+    @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
+            xProviderCopyTo(target, convertMoveToCopyOptions(options));
+            delete(false);
+        }
+        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<len; i++) {
+            CopyOption option = options[i];
+            if (option == StandardCopyOption.ATOMIC_MOVE) {
+                throw new AtomicMoveNotSupportedException(null, null,
+                    "Atomic move between providers is not supported");
+            }
+            newOptions[i] = option;
+        }
+        newOptions[len] = LinkOption.NOFOLLOW_LINKS;
+        newOptions[len+1] = StandardCopyOption.COPY_ATTRIBUTES;
+        return newOptions;
+    }
+
+    /**
+     * 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 IllegalArgumentException("'" + option +
+                    "' is not a valid copy option");
+            }
+            return result;
+        }
+    }
+
+    /**
+     * Simple cross-provider copy where the target is a Path.
+     */
+    private void xProviderCopyTo(Path target, CopyOption... options)
+        throws IOException
+    {
+        CopyOptions opts = CopyOptions.parse(options);
+        LinkOption[] linkOptions = (opts.followLinks) ? new LinkOption[0] :
+            new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+
+        // attributes of source file
+        BasicFileAttributes attrs = Attributes
+            .readBasicFileAttributes(this, linkOptions);
+        if (attrs.isSymbolicLink())
+            throw new IOException("Copying of symbolic links not supported");
+
+        // delete target file
+        if (opts.replaceExisting)
+            target.delete(false);
+
+        // create directory or file
+        if (attrs.isDirectory()) {
+            target.createDirectory();
+        } else {
+            xProviderCopyRegularFileTo(target);
+        }
+
+        // copy basic attributes to target
+        if (opts.copyAttributes) {
+            BasicFileAttributeView view = target
+                .getFileAttributeView(BasicFileAttributeView.class, linkOptions);
+            try {
+                view.setTimes(attrs.lastModifiedTime(),
+                              attrs.lastAccessTime(),
+                              attrs.creationTime(),
+                              attrs.resolution());
+            } catch (IOException x) {
+                // rollback
+                try {
+                    target.delete(false);
+                } catch (IOException ignore) { }
+                throw x;
+            }
+        }
+    }
+
+
+   /**
+     * Simple copy of regular file to a target file that exists.
+     */
+    private void xProviderCopyRegularFileTo(FileRef target)
+        throws IOException
+    {
+        ReadableByteChannel rbc = newByteChannel();
+        try {
+            // open target file for writing
+            SeekableByteChannel sbc = target.newByteChannel(CREATE, WRITE);
+
+            // simple copy loop
+            try {
+                ByteBuffer buf = ByteBuffer.wrap(new byte[8192]);
+                int n = 0;
+                for (;;) {
+                    n = rbc.read(buf);
+                    if (n < 0)
+                        break;
+                    assert n > 0;
+                    buf.flip();
+                    while (buf.hasRemaining()) {
+                        sbc.write(buf);
+                    }
+                    buf.rewind();
+                }
+
+            } finally {
+                sbc.close();
+            }
+        } finally {
+            rbc.close();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/spi/FileSystemProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,434 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.spi;
+
+import java.nio.file.*;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.channels.*;
+import java.net.URI;
+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.
+ *
+ * <p> A file system provider is a concrete implementation of this class that
+ * implements the abstract methods defined by this class. A provider is
+ * identified by a {@code URI} {@link #getScheme() scheme}. The default provider
+ * is identified by the URI scheme "file". It creates the {@link FileSystem} that
+ * provides access to the file systems accessible to the Java virtual machine.
+ * The {@link FileSystems} class defines how file system providers are located
+ * and loaded. The default provider is typically a system-default provider but
+ * may be overridden if the system property {@code
+ * java.nio.file.spi.DefaultFileSystemProvider} is set. In that case, the
+ * provider has a one argument constructor whose formal parameter type is {@code
+ * FileSystemProvider}. All other providers have a zero argument constructor
+ * that initializes the provider.
+ *
+ * <p> A provider is a factory for one or more {@link FileSystem} instances. Each
+ * file system is identified by a {@code URI} where the URI's scheme matches
+ * the provider's {@link #getScheme scheme}. The default file system, for example,
+ * is identified by the URI {@code "file:///"}. A memory-based file system,
+ * for example, may be identified by a URI such as {@code "memory:///?name=logfs"}.
+ * The {@link #newFileSystem newFileSystem} method may be used to create a file
+ * system, and the {@link #getFileSystem getFileSystem} method may be used to
+ * obtain a reference to an existing file system created by the provider. Where
+ * a provider is the factory for a single file system then it is provider dependent
+ * if the file system is created when the provider is initialized, or later when
+ * the {@code newFileSystem} method is invoked. In the case of the default
+ * provider, the {@code FileSystem} is created when the provider is initialized.
+ *
+ * <p> 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.
+ *
+ * <p> All of the methods in this class are safe for use by multiple concurrent
+ * threads.
+ *
+ * @since 1.7
+ */
+
+public abstract class FileSystemProvider {
+    // lock using when loading providers
+    private static final Object lock = new Object();
+
+    // installed providers
+    private static volatile List<FileSystemProvider> installedProviders;
+
+    // used to avoid recursive loading of instaled providers
+    private static boolean loadingProviders  = false;
+
+    private static Void checkPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(new RuntimePermission("fileSystemProvider"));
+        return null;
+    }
+    private FileSystemProvider(Void ignore) { }
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * <p> During construction a provider may safely access files associated
+     * with the default provider but care needs to be taken to avoid circular
+     * loading of other installed providers. If circular loading of installed
+     * providers is detected then an unspecified error is thrown.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     *          {@link RuntimePermission}<tt>("fileSystemProvider")</tt>
+     */
+    protected FileSystemProvider() {
+        this(checkPermission());
+    }
+
+    // loads all installed providers
+    private static List<FileSystemProvider> loadInstalledProviders() {
+        List<FileSystemProvider> list = new ArrayList<FileSystemProvider>();
+
+        ServiceLoader<FileSystemProvider> sl = ServiceLoader
+            .load(FileSystemProvider.class, ClassLoader.getSystemClassLoader());
+
+        // ServiceConfigurationError may be throw here
+        for (FileSystemProvider provider: sl) {
+            String scheme = provider.getScheme();
+
+            // add to list if the provider is not "file" and isn't a duplicate
+            if (!scheme.equalsIgnoreCase("file")) {
+                boolean found = false;
+                for (FileSystemProvider p: list) {
+                    if (p.getScheme().equalsIgnoreCase(scheme)) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (!found) {
+                    list.add(provider);
+                }
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns a list of the installed file system providers.
+     *
+     * <p> The first invocation of this method causes the default provider to be
+     * initialized (if not already initialized) and loads any other installed
+     * providers as described by the {@link FileSystems} class.
+     *
+     * @return  An unmodifiable list of the installed file system providers. The
+     *          list contains at least one element, that is the default file
+     *          system provider
+     *
+     * @throws  ServiceConfigurationError
+     *          When an error occurs while loading a service provider
+     */
+    public static List<FileSystemProvider> installedProviders() {
+        if (installedProviders == null) {
+            // ensure default provider is initialized
+            FileSystemProvider defaultProvider = FileSystems.getDefault().provider();
+
+            synchronized (lock) {
+                if (installedProviders == null) {
+                    if (loadingProviders) {
+                        throw new Error("Circular loading of installed providers detected");
+                    }
+                    loadingProviders = true;
+
+                    List<FileSystemProvider> list = AccessController
+                        .doPrivileged(new PrivilegedAction<List<FileSystemProvider>>() {
+                            @Override
+                            public List<FileSystemProvider> run() {
+                                return loadInstalledProviders();
+                        }});
+
+                    // insert the default provider at the start of the list
+                    list.add(0, defaultProvider);
+
+                    installedProviders = Collections.unmodifiableList(list);
+                }
+            }
+        }
+        return installedProviders;
+    }
+
+    /**
+     * Returns the URI scheme that identifies this provider.
+     *
+     * @return  The URI scheme
+     */
+    public abstract String getScheme();
+
+    /**
+     * Constructs a new {@code FileSystem} object identified by a URI. This
+     * method is invoked by the {@link FileSystems#newFileSystem(URI,Map)}
+     * method to open a new file system identified by a URI.
+     *
+     * <p> The {@code uri} parameter is an absolute, hierarchical URI, with a
+     * scheme equal (without regard to case) to the scheme supported by this
+     * provider. The exact form of the URI is highly provider dependent. The
+     * {@code env} parameter is a map of provider specific properties to configure
+     * the file system.
+     *
+     * <p> 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.
+     *
+     * @param   uri
+     *          URI reference
+     * @param   env
+     *          A map of provider specific properties to configure the file system;
+     *          may be empty
+     *
+     * @return  A new file system
+     *
+     * @throws  IllegalArgumentException
+     *          If the pre-conditions for the {@code uri} parameter aren't met,
+     *          or the {@code env} parameter does not contain properties required
+     *          by the provider, or a property value is invalid
+     * @throws  IOException
+     *          An I/O error occurs creating the file system
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission required by the file system provider implementation
+     * @throws  FileSystemAlreadyExistsException
+     *          If the file system has already been created
+     */
+    public abstract FileSystem newFileSystem(URI uri, Map<String,?> env)
+        throws IOException;
+
+    /**
+     * Returns an existing {@code FileSystem} created by this provider.
+     *
+     * <p> 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.
+     * 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}).
+     *
+     * <p> 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).
+     *
+     * <p> If a security manager is installed then a provider implementation
+     * may require to check a permission before returning a reference to an
+     * existing file system. In the case of the {@link FileSystems#getDefault
+     * default} file system, no permission check is required.
+     *
+     * @param   uri
+     *          URI reference
+     *
+     * @return  The file system
+     *
+     * @throws  IllegalArgumentException
+     *          If the pre-conditions for the {@code uri} parameter aren't met
+     * @throws  FileSystemNotFoundException
+     *          If the file system does not exist
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission.
+     */
+    public abstract FileSystem getFileSystem(URI uri);
+
+    /**
+     * Return a {@code Path} object by converting the given {@link URI}.
+     *
+     * <p> The exact form of the URI is file system provider dependent. In the
+     * case of the default provider, the URI scheme is {@code "file"} and the
+     * given URI has a non-empty path component, and undefined query, and
+     * fragment components. The resulting {@code Path} is associated with the
+     * default {@link FileSystems#getDefault default} {@code FileSystem}.
+     *
+     * <p> If a security manager is installed then a provider implementation
+     * may require to check a permission. In the case of the {@link
+     * FileSystems#getDefault default} file system, no permission check is
+     * required.
+     *
+     * @param   uri
+     *          The URI to convert
+     *
+     * @throws  IllegalArgumentException
+     *          If the URI scheme does not identify this provider or other
+     *          preconditions on the uri parameter do not hold
+     * @throws  FileSystemNotFoundException
+     *          The file system, identified by the URI, does not exist
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission.
+     */
+    public abstract Path getPath(URI uri);
+
+    /**
+     * Constructs a new {@code FileSystem} to access the contents of a file as a
+     * file system.
+     *
+     * <p> 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.
+     *
+     * <p> 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   env
+     *          A map of provider specific properties to configure the file system;
+     *          may be empty
+     *
+     * @return  A new file system
+     *
+     * @throws  UnsupportedOperationException
+     *          If this provider does not support access to the contents as a
+     *          file system or it does not recognize the file type of the
+     *          given file
+     * @throws  IllegalArgumentException
+     *          If the {@code env} parameter does not contain properties required
+     *          by the provider, or a property value is invalid
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission.
+     */
+    public FileSystem newFileSystem(FileRef file, Map<String,?> env)
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Opens or creates a file for reading and/or writing, returning a file
+     * channel to access the file.
+     *
+     * <p> 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}.
+     *
+     * @param   path
+     *          The path of 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 file channel
+     *
+     * @throws  IllegalArgumentException
+     *          If the set contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          If this provider that does not support creating file channels,
+     *          or an unsupported open option or file attribute is specified
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default file system, the {@link
+     *          SecurityManager#checkRead(String)} method is invoked to check
+     *          read access if the file is opened for reading. The {@link
+     *          SecurityManager#checkWrite(String)} method is invoked to check
+     *          write access if the file is opened for writing
+     */
+    public FileChannel newFileChannel(Path path,
+                                      Set<? extends OpenOption> options,
+                                      FileAttribute<?>... attrs)
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Opens or creates a file for reading and/or writing, returning an
+     * asynchronous file channel to access the file.
+     *
+     * <p> This method is invoked by the {@link
+     * AsynchronousFileChannel#open(Path,Set,ExecutorService,FileAttribute[])
+     * AsynchronousFileChannel.open} method to open an asynchronous file channel.
+     * 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
+     * file channels. When not overridden, the default implementation of this
+     * method throws {@code UnsupportedOperationException}.
+     *
+     * @param   path
+     *          The path of the file to open or create
+     * @param   options
+     *          Options specifying how the file is opened
+     * @param   executor
+     *          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
+     *          creating the file
+     *
+     * @return  A new asynchronous file channel
+     *
+     * @throws  IllegalArgumentException
+     *          If the set contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          If this provider that does not support creating asynchronous file
+     *          channels, or an unsupported open option or file attribute is
+     *          specified
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default file system, the {@link
+     *          SecurityManager#checkRead(String)} method is invoked to check
+     *          read access if the file is opened for reading. The {@link
+     *          SecurityManager#checkWrite(String)} method is invoked to check
+     *          write access if the file is opened for writing
+     */
+    public AsynchronousFileChannel newAsynchronousFileChannel(Path path,
+                                                              Set<? extends OpenOption> options,
+                                                              ExecutorService executor,
+                                                              FileAttribute<?>... attrs)
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/spi/FileTypeDetector.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.spi;
+
+import java.nio.file.FileRef;
+import java.io.IOException;
+
+/**
+ * A file type detector for probing a file to guess its file type.
+ *
+ * <p> A file type detector is a concrete implementation of this class, has a
+ * zero-argument constructor, and implements the abstract methods specified
+ * below.
+ *
+ * <p> The means by which a file type detector determines the file type is
+ * highly implementation specific. A simple implementation might examine the
+ * <em>file extension</em> (a convention used in some platforms) and map it to
+ * a file type. In other cases, the file type may be stored as a file <a
+ * href="../attribute/package-summary.html"> attribute</a> or the bytes in a
+ * file may be examined to guess its file type.
+ *
+ * @see java.nio.file.Files#probeContentType(FileRef)
+ *
+ * @since 1.7
+ */
+
+public abstract class FileTypeDetector {
+
+    private static Void checkPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(new RuntimePermission("fileTypeDetector"));
+        return null;
+    }
+    private FileTypeDetector(Void ignore) { }
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     *          {@link RuntimePermission}<tt>("fileTypeDetector")</tt>
+     */
+    protected FileTypeDetector() {
+        this(checkPermission());
+    }
+
+    /**
+     * Probes the given file to guess its content type.
+     *
+     * <p> The means by which this method determines the file type is highly
+     * implementation specific. It may simply examine the file name, it may use
+     * a file <a href="../attribute/package-summary.html">attribute</a>,
+     * or it may examines bytes in the file.
+     *
+     * <p> The probe result is the string form of the value of a
+     * Multipurpose Internet Mail Extension (MIME) content type as
+     * defined by <a href="http://www.ietf.org/rfc/rfc2045.txt"><i>RFC&nbsp;2045:
+     * Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet
+     * Message Bodies</i></a>. The string must be parsable according to the
+     * grammar in the RFC 2045.
+     *
+     * @param   file
+     *          The file to probe
+     *
+     * @return  The content type or {@code null} if the file type is not
+     *          recognized
+     *
+     * @throws  IOException
+     *          An I/O error occurs
+     * @throws  SecurityException
+     *          If the implementation requires to access the file, and a
+     *          security manager is installed, and it denies an unspecified
+     *          permission required by a file system provider implementation.
+     *          If the file reference is associated with the default file system
+     *          provider then the {@link SecurityManager#checkRead(String)} method
+     *          is invoked to check read access to the file.
+     *
+     * @see java.nio.file.Files#probeContentType
+     */
+    public abstract String probeContentType(FileRef file)
+        throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/nio/file/spi/package-info.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * Service-provider classes for the <tt>{@link java.nio.file}</tt> package.
+ *
+ * <p> Only developers who are defining new file system providers or file type
+ * detectors should need to make direct use of this package.  </p>
+ *
+ * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
+ * or method in any class or interface in this package will cause a {@link
+ * java.lang.NullPointerException NullPointerException} to be thrown.
+ *
+ * @since 1.7
+ */
+
+package java.nio.file.spi;
--- a/jdk/src/share/classes/java/util/Scanner.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/java/util/Scanner.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc.  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
@@ -25,6 +25,7 @@
 
 package java.util;
 
+import java.nio.file.FileRef;
 import java.util.regex.*;
 import java.io.*;
 import java.math.*;
@@ -673,6 +674,49 @@
     }
 
     /**
+     * {@note new}
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the underlying platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
+     *
+     * @param   source
+     *          A file to be scanned
+     * @throws  IOException
+     *          if an I/O error occurs opening source
+     *
+     * @since   1.7
+     */
+    public Scanner(FileRef source)
+        throws IOException
+    {
+        this(source.newByteChannel());
+    }
+
+    /**
+     * {@note new}
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the specified charset.
+     *
+     * @param   source
+     *          A file to be scanned
+     * @param   charsetName
+     *          The encoding type used to convert bytes from the file
+     *          into characters to be scanned
+     * @throws  IOException
+     *          if an I/O error occurs opening source
+     * @throws  IllegalArgumentException
+     *          if the specified encoding is not found
+     * @since   1.7
+     */
+    public Scanner(FileRef source, String charsetName)
+        throws IOException
+    {
+        this(source.newByteChannel(), charsetName);
+    }
+
+    /**
      * Constructs a new <code>Scanner</code> that produces values scanned
      * from the specified string.
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/AbstractFuture.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.AsynchronousChannel;
+import java.util.concurrent.Future;
+
+/**
+ * Base implementation of Future used for asynchronous I/O
+ */
+
+abstract class AbstractFuture<V,A>
+    implements Future<V>
+{
+    private final AsynchronousChannel channel;
+    private final A attachment;
+
+    protected AbstractFuture(AsynchronousChannel channel, A attachment) {
+        this.channel = channel;
+        this.attachment = attachment;
+    }
+
+    final AsynchronousChannel channel() {
+        return channel;
+    }
+
+    final A attachment() {
+        return attachment;
+    }
+
+    /**
+     * Returns the result of the operation if it has completed successfully.
+     */
+    abstract V value();
+
+    /**
+     * Returns the exception if the operation has failed.
+     */
+    abstract Throwable exception();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.Channel;
+import java.nio.channels.AsynchronousChannelGroup;
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.util.Queue;
+import java.util.concurrent.*;
+import java.util.concurrent.locks.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.security.PrivilegedAction;
+import java.security.AccessController;
+import java.security.AccessControlContext;
+import sun.security.action.GetIntegerAction;
+
+/**
+ * Base implementation of AsynchronousChannelGroup
+ */
+
+abstract class AsynchronousChannelGroupImpl
+    extends AsynchronousChannelGroup implements Executor
+{
+    // number of internal threads handling I/O events when using an unbounded
+    // thread pool. Internal threads do not dispatch to completion handlers.
+    private static final int internalThreadCount = AccessController.doPrivileged(
+        new GetIntegerAction("sun.nio.ch.internalThreadPoolSize", 1));
+
+    // associated thread pool
+    private final ThreadPool pool;
+
+    // number of tasks running (including internal)
+    private final AtomicInteger threadCount = new AtomicInteger();
+
+    // associated Executor for timeouts
+    private ScheduledThreadPoolExecutor timeoutExecutor;
+
+    // task queue for when using a fixed thread pool. In that case, thread
+    // waiting on I/O events must be awokon to poll tasks from this queue.
+    private final Queue<Runnable> taskQueue;
+
+    // group shutdown
+    // shutdownLock is RW lock so as to allow for concurrent queuing of tasks
+    // when using a fixed thread pool.
+    private final ReadWriteLock shutdownLock = new ReentrantReadWriteLock();
+    private final Object shutdownNowLock = new Object();
+    private volatile boolean shutdown;
+    private volatile boolean terminateInitiated;
+
+    AsynchronousChannelGroupImpl(AsynchronousChannelProvider provider,
+                                 ThreadPool pool)
+    {
+        super(provider);
+        this.pool = pool;
+
+        if (pool.isFixedThreadPool()) {
+            taskQueue = new ConcurrentLinkedQueue<Runnable>();
+        } else {
+            taskQueue = null;   // not used
+        }
+
+        // use default thread factory as thread should not be visible to
+        // application (it doesn't execute completion handlers).
+        this.timeoutExecutor = (ScheduledThreadPoolExecutor)
+            Executors.newScheduledThreadPool(1, ThreadPool.defaultThreadFactory());
+        this.timeoutExecutor.setRemoveOnCancelPolicy(true);
+    }
+
+    final ExecutorService executor() {
+        return pool.executor();
+    }
+
+    final boolean isFixedThreadPool() {
+        return pool.isFixedThreadPool();
+    }
+
+    final int fixedThreadCount() {
+        if (isFixedThreadPool()) {
+            return pool.poolSize();
+        } else {
+            return pool.poolSize() + internalThreadCount;
+        }
+    }
+
+    private Runnable bindToGroup(final Runnable task) {
+        final AsynchronousChannelGroupImpl thisGroup = this;
+        return new Runnable() {
+            public void run() {
+                Invoker.bindToGroup(thisGroup);
+                task.run();
+            }
+        };
+    }
+
+    private void startInternalThread(final Runnable task) {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run() {
+                // internal threads should not be visible to application so
+                // cannot use user-supplied thread factory
+                ThreadPool.defaultThreadFactory().newThread(task).start();
+                return null;
+            }
+         });
+    }
+
+    protected final void startThreads(Runnable task) {
+        if (!isFixedThreadPool()) {
+            for (int i=0; i<internalThreadCount; i++) {
+                startInternalThread(task);
+                threadCount.incrementAndGet();
+            }
+        }
+        if (pool.poolSize() > 0) {
+            task = bindToGroup(task);
+            try {
+                for (int i=0; i<pool.poolSize(); i++) {
+                    pool.executor().execute(task);
+                    threadCount.incrementAndGet();
+                }
+            } catch (RejectedExecutionException  x) {
+                // nothing we can do
+            }
+        }
+    }
+
+    final int threadCount() {
+        return threadCount.get();
+    }
+
+    /**
+     * Invoked by tasks as they terminate
+     */
+    final int threadExit(Runnable task, boolean replaceMe) {
+        if (replaceMe) {
+            try {
+                if (Invoker.isBoundToAnyGroup()) {
+                    // submit new task to replace this thread
+                    pool.executor().execute(bindToGroup(task));
+                } else {
+                    // replace internal thread
+                    startInternalThread(task);
+                }
+                return threadCount.get();
+            } catch (RejectedExecutionException x) {
+                // unable to replace
+            }
+        }
+        return threadCount.decrementAndGet();
+    }
+
+    /**
+     * Wakes up a thread waiting for I/O events to execute the given task.
+     */
+    abstract void executeOnHandlerTask(Runnable task);
+
+    /**
+     * For a fixed thread pool the task is queued to a thread waiting on I/O
+     * events. For other thread pools we simply submit the task to the thread
+     * pool.
+     */
+    final void executeOnPooledThread(Runnable task) {
+        if (isFixedThreadPool()) {
+            executeOnHandlerTask(task);
+        } else {
+            pool.executor().execute(bindToGroup(task));
+        }
+    }
+
+    final void offerTask(Runnable task) {
+        taskQueue.offer(task);
+    }
+
+    final Runnable pollTask() {
+        return (taskQueue == null) ? null : taskQueue.poll();
+    }
+
+    final Future<?> schedule(Runnable task, long timeout, TimeUnit unit) {
+        try {
+            return timeoutExecutor.schedule(task, timeout, unit);
+        } catch (RejectedExecutionException rej) {
+            if (terminateInitiated) {
+                // no timeout scheduled as group is terminating
+                return null;
+            }
+            throw new AssertionError(rej);
+        }
+    }
+
+    @Override
+    public final boolean isShutdown() {
+        return shutdown;
+    }
+
+    @Override
+    public final boolean isTerminated()  {
+        return pool.executor().isTerminated();
+    }
+
+    /**
+     * Returns true if there are no channels in the group
+     */
+    abstract boolean isEmpty();
+
+    /**
+     * Attaches a foreign channel to this group.
+     */
+    abstract Object attachForeignChannel(Channel channel, FileDescriptor fdo)
+        throws IOException;
+
+    /**
+     * Detaches a foreign channel from this group.
+     */
+    abstract void detachForeignChannel(Object key);
+
+    /**
+     * Closes all channels in the group
+     */
+    abstract void closeAllChannels() throws IOException;
+
+    /**
+     * Shutdown all tasks waiting for I/O events.
+     */
+    abstract void shutdownHandlerTasks();
+
+    private void shutdownExecutors() {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                pool.executor().shutdown();
+                timeoutExecutor.shutdown();
+                return null;
+            }
+        });
+    }
+
+    @Override
+    public final void shutdown() {
+        shutdownLock.writeLock().lock();
+        try {
+            if (shutdown) {
+                // already shutdown
+                return;
+            }
+            shutdown = true;
+        } finally {
+            shutdownLock.writeLock().unlock();
+        }
+
+        // if there are channels in the group then shutdown will continue
+        // when the last channel is closed
+        if (!isEmpty()) {
+            return;
+        }
+        // initiate termination (acquire shutdownNowLock to ensure that other
+        // threads invoking shutdownNow will block).
+        synchronized (shutdownNowLock) {
+            if (!terminateInitiated) {
+                terminateInitiated = true;
+                shutdownHandlerTasks();
+                shutdownExecutors();
+            }
+        }
+    }
+
+    @Override
+    public final void shutdownNow() throws IOException {
+        shutdownLock.writeLock().lock();
+        try {
+            shutdown = true;
+        } finally {
+            shutdownLock.writeLock().unlock();
+        }
+        synchronized (shutdownNowLock) {
+            if (!terminateInitiated) {
+                terminateInitiated = true;
+                closeAllChannels();
+                shutdownHandlerTasks();
+                shutdownExecutors();
+            }
+        }
+    }
+
+    @Override
+    public final boolean awaitTermination(long timeout, TimeUnit unit)
+        throws InterruptedException
+    {
+        return pool.executor().awaitTermination(timeout, unit);
+    }
+
+    /**
+     * Executes the given command on one of the channel group's pooled threads.
+     */
+    @Override
+    public final void execute(Runnable task) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            // when a security manager is installed then the user's task
+            // must be run with the current calling context
+            final AccessControlContext acc = AccessController.getContext();
+            final Runnable delegate = task;
+            task = new Runnable() {
+                @Override
+                public void run() {
+                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                        @Override
+                        public Void run() {
+                            delegate.run();
+                            return null;
+                        }
+                    }, acc);
+                }
+            };
+        }
+        executeOnPooledThread(task);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.locks.*;
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+/**
+ * Base implementation of AsynchronousFileChannel.
+ */
+
+abstract class AsynchronousFileChannelImpl
+    extends AsynchronousFileChannel
+{
+    // close support
+    protected final ReadWriteLock closeLock = new ReentrantReadWriteLock();
+    protected volatile boolean closed;
+
+    // file descriptor
+    protected final FileDescriptor fdObj;
+
+    // indicates if open for reading/writing
+    protected final boolean reading;
+    protected final boolean writing;
+
+    // associated Executor
+    protected final ExecutorService executor;
+
+    protected AsynchronousFileChannelImpl(FileDescriptor fdObj,
+                                          boolean reading,
+                                          boolean writing,
+                                          ExecutorService executor)
+    {
+        this.fdObj = fdObj;
+        this.reading = reading;
+        this.writing = writing;
+        this.executor = executor;
+    }
+
+    final ExecutorService executor() {
+        return executor;
+    }
+
+    @Override
+    public final boolean isOpen() {
+        return !closed;
+    }
+
+    /**
+     * Marks the beginning of an I/O operation.
+     *
+     * @throws  ClosedChannelException  If channel is closed
+     */
+    protected final void begin() throws IOException {
+        closeLock.readLock().lock();
+        if (closed)
+            throw new ClosedChannelException();
+    }
+
+    /**
+     * Marks the end of an I/O operation.
+     */
+    protected final void end() {
+        closeLock.readLock().unlock();
+    }
+
+    /**
+     * Marks end of I/O operation
+     */
+    protected final void end(boolean completed) throws IOException {
+        end();
+        if (!completed && !isOpen())
+            throw new AsynchronousCloseException();
+    }
+
+    // -- file locking --
+
+    private volatile FileLockTable fileLockTable;
+
+    final void ensureFileLockTableInitialized() throws IOException {
+        if (fileLockTable == null) {
+            synchronized (this) {
+                if (fileLockTable == null) {
+                    fileLockTable = FileLockTable.newSharedFileLockTable(this, fdObj);
+                }
+            }
+        }
+    }
+
+    final void invalidateAllLocks() {
+        if (fileLockTable != null) {
+            try {
+                fileLockTable.removeAll( new FileLockTable.Releaser() {
+                    public void release(FileLock fl) {
+                        ((FileLockImpl)fl).invalidate();
+                    }
+                });
+            } catch (IOException e) {
+                throw new AssertionError(e);
+            }
+        }
+    }
+
+    /**
+     * Adds region to lock table
+     */
+    protected final FileLockImpl addToFileLockTable(long position, long size, boolean shared) {
+        final FileLockImpl fli;
+        try {
+            // like begin() but returns null instead of exception
+            closeLock.readLock().lock();
+            if (closed)
+                return null;
+
+            try {
+                ensureFileLockTableInitialized();
+            } catch (IOException x) {
+                // should not happen
+                throw new AssertionError(x);
+            }
+            fli = new FileLockImpl(this, position, size, shared);
+            // may throw OverlappedFileLockException
+            fileLockTable.add(fli);
+        } finally {
+            end();
+        }
+        return fli;
+    }
+
+    protected final void removeFromFileLockTable(FileLockImpl fli) {
+        fileLockTable.remove(fli);
+    }
+
+    /**
+     * Invoked by FileLockImpl to release lock acquired by this channel.
+     */
+    abstract void release(FileLockImpl fli) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.net.SocketAddress;
+import java.net.SocketOption;
+import java.net.StandardSocketOption;
+import java.net.InetSocketAddress;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Base implementation of AsynchronousServerSocketChannel.
+ */
+
+abstract class AsynchronousServerSocketChannelImpl
+    extends AsynchronousServerSocketChannel
+    implements Cancellable, Groupable
+{
+    protected final FileDescriptor fd;
+
+    // the local address to which the channel's socket is bound
+    protected volatile SocketAddress localAddress = null;
+
+    // need this lock to set local address
+    private final Object stateLock = new Object();
+
+    // close support
+    private ReadWriteLock closeLock = new ReentrantReadWriteLock();
+    private volatile boolean open = true;
+
+    // set true when accept operation is cancelled
+    private volatile boolean acceptKilled;
+
+
+    AsynchronousServerSocketChannelImpl(AsynchronousChannelGroupImpl group) {
+        super(group.provider());
+        this.fd = Net.serverSocket(true);
+    }
+
+    @Override
+    public final boolean isOpen() {
+        return open;
+    }
+
+    /**
+     * Marks beginning of access to file descriptor/handle
+     */
+    final void begin() throws IOException {
+        closeLock.readLock().lock();
+        if (!isOpen())
+            throw new ClosedChannelException();
+    }
+
+    /**
+     * Marks end of access to file descriptor/handle
+     */
+    final void end() {
+        closeLock.readLock().unlock();
+    }
+
+    /**
+     * Invoked to close file descriptor/handle.
+     */
+    abstract void implClose() throws IOException;
+
+    @Override
+    public final void close() throws IOException {
+        // synchronize with any threads using file descriptor/handle
+        closeLock.writeLock().lock();
+        try {
+            if (!open)
+                return;     // already closed
+            open = false;
+        } finally {
+            closeLock.writeLock().unlock();
+        }
+        implClose();
+    }
+
+    final boolean isAcceptKilled() {
+        return acceptKilled;
+    }
+
+    @Override
+    public final void onCancel(PendingFuture<?,?> task) {
+        acceptKilled = true;
+    }
+
+    @Override
+    public final AsynchronousServerSocketChannel bind(SocketAddress local, int backlog)
+        throws IOException
+    {
+        InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) :
+            Net.checkAddress(local);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkListen(isa.getPort());
+
+        try {
+            begin();
+            synchronized (stateLock) {
+                if (localAddress != null)
+                    throw new AlreadyBoundException();
+                Net.bind(fd, isa.getAddress(), isa.getPort());
+                Net.listen(fd, backlog < 1 ? 50 : backlog);
+                localAddress = Net.localAddress(fd);
+            }
+        } finally {
+            end();
+        }
+        return this;
+    }
+
+    @Override
+    public final SocketAddress getLocalAddress() throws IOException {
+        if (!isOpen())
+            throw new ClosedChannelException();
+        return localAddress;
+    }
+
+    @Override
+    public final <T> AsynchronousServerSocketChannel setOption(SocketOption<T> name,
+                                                               T value)
+        throws IOException
+    {
+        if (name == null)
+            throw new NullPointerException();
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+
+        try {
+            begin();
+            Net.setSocketOption(fd, Net.UNSPEC, name, value);
+            return this;
+        } finally {
+            end();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <T> T getOption(SocketOption<T> name) throws IOException {
+        if (name == null)
+            throw new NullPointerException();
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+
+        try {
+            begin();
+            return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
+        } finally {
+            end();
+        }
+    }
+
+    private static class DefaultOptionsHolder {
+        static final Set<SocketOption<?>> defaultOptions = defaultOptions();
+
+        private static Set<SocketOption<?>> defaultOptions() {
+            HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(2);
+            set.add(StandardSocketOption.SO_RCVBUF);
+            set.add(StandardSocketOption.SO_REUSEADDR);
+            return Collections.unmodifiableSet(set);
+        }
+    }
+
+    @Override
+    public final Set<SocketOption<?>> supportedOptions() {
+        return DefaultOptionsHolder.defaultOptions;
+    }
+
+    @Override
+    public final String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(this.getClass().getName());
+        sb.append('[');
+        if (!isOpen())
+            sb.append("closed");
+        else {
+            if (localAddress == null) {
+                sb.append("unbound");
+            } else {
+                sb.append(localAddress.toString());
+            }
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,542 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.net.SocketOption;
+import java.net.StandardSocketOption;
+import java.net.SocketAddress;
+import java.net.InetSocketAddress;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+import java.util.concurrent.*;
+import java.util.concurrent.locks.*;
+
+/**
+ * Base implementation of AsynchronousSocketChannel
+ */
+
+abstract class AsynchronousSocketChannelImpl
+    extends AsynchronousSocketChannel
+    implements Cancellable, Groupable
+{
+    protected final FileDescriptor fd;
+
+    // protects state, localAddress, and remoteAddress
+    protected final Object stateLock = new Object();
+
+    protected volatile SocketAddress localAddress = null;
+    protected volatile SocketAddress remoteAddress = null;
+
+    // State, increases monotonically
+    static final int ST_UNINITIALIZED = -1;
+    static final int ST_UNCONNECTED = 0;
+    static final int ST_PENDING = 1;
+    static final int ST_CONNECTED = 2;
+    protected volatile int state = ST_UNINITIALIZED;
+
+    // reading state
+    private final Object readLock = new Object();
+    private boolean reading;
+    private boolean readShutdown;
+    private boolean readKilled;     // further reading disallowed due to timeout
+
+    // writing state
+    private final Object writeLock = new Object();
+    private boolean writing;
+    private boolean writeShutdown;
+    private boolean writeKilled;    // further writing disallowed due to timeout
+
+    // close support
+    private final ReadWriteLock closeLock = new ReentrantReadWriteLock();
+    private volatile boolean open = true;
+
+    AsynchronousSocketChannelImpl(AsynchronousChannelGroupImpl group)
+        throws IOException
+    {
+        super(group.provider());
+        this.fd = Net.socket(true);
+        this.state = ST_UNCONNECTED;
+    }
+
+    // Constructor for sockets obtained from AsynchronousServerSocketChannelImpl
+    AsynchronousSocketChannelImpl(AsynchronousChannelGroupImpl group,
+                                  FileDescriptor fd,
+                                  InetSocketAddress remote)
+        throws IOException
+    {
+        super(group.provider());
+        this.fd = fd;
+        this.state = ST_CONNECTED;
+        this.localAddress = Net.localAddress(fd);
+        this.remoteAddress = remote;
+    }
+
+    @Override
+    public final boolean isOpen() {
+        return open;
+    }
+
+    /**
+     * Marks beginning of access to file descriptor/handle
+     */
+    final void begin() throws IOException {
+        closeLock.readLock().lock();
+        if (!isOpen())
+            throw new ClosedChannelException();
+    }
+
+    /**
+     * Marks end of access to file descriptor/handle
+     */
+    final void end() {
+        closeLock.readLock().unlock();
+    }
+
+    /**
+     * Invoked to close socket and release other resources.
+     */
+    abstract void implClose() throws IOException;
+
+    @Override
+    public final void close() throws IOException {
+        // synchronize with any threads initiating asynchronous operations
+        closeLock.writeLock().lock();
+        try {
+            if (!open)
+                return;     // already closed
+            open = false;
+        } finally {
+            closeLock.writeLock().unlock();
+        }
+        implClose();
+    }
+
+    final void enableReading(boolean killed) {
+        synchronized (readLock) {
+            reading = false;
+            if (killed)
+                readKilled = true;
+        }
+    }
+
+    final void enableReading() {
+        enableReading(false);
+    }
+
+    final void enableWriting(boolean killed) {
+        synchronized (writeLock) {
+            writing = false;
+            if (killed)
+                writeKilled = true;
+        }
+    }
+
+    final void enableWriting() {
+        enableWriting(false);
+    }
+
+    final void killReading() {
+        synchronized (readLock) {
+            readKilled = true;
+        }
+    }
+
+    final void killWriting() {
+        synchronized (writeLock) {
+            writeKilled = true;
+        }
+    }
+
+    final void killConnect() {
+        // when a connect is cancelled then the connection may have been
+        // established so prevent reading or writing.
+        killReading();
+        killWriting();
+    }
+
+    /**
+     * Invoked by read to initiate the I/O operation.
+     */
+    abstract <V extends Number,A> Future<V> readImpl(ByteBuffer[] dsts,
+                                                     boolean isScatteringRead,
+                                                     long timeout,
+                                                     TimeUnit unit,
+                                                     A attachment,
+                                                     CompletionHandler<V,? super A> handler);
+
+    @SuppressWarnings("unchecked")
+    private <V extends Number,A> Future<V> read(ByteBuffer[] dsts,
+                                                boolean isScatteringRead,
+                                                long timeout,
+                                                TimeUnit unit,
+                                                A attachment,
+                                                CompletionHandler<V,? super A> handler)
+    {
+        if (!isOpen()) {
+            CompletedFuture<V,A> result = CompletedFuture
+                .withFailure(this, new ClosedChannelException(), attachment);
+            Invoker.invoke(handler, result);
+            return result;
+        }
+
+        if (remoteAddress == null)
+            throw new NotYetConnectedException();
+        if (timeout < 0L)
+            throw new IllegalArgumentException("Negative timeout");
+
+        boolean hasSpaceToRead = isScatteringRead || dsts[0].hasRemaining();
+        boolean shutdown = false;
+
+        // check and update state
+        synchronized (readLock) {
+            if (readKilled)
+                throw new RuntimeException("Reading not allowed due to timeout or cancellation");
+            if (reading)
+                throw new ReadPendingException();
+            if (readShutdown) {
+                shutdown = true;
+            } else {
+                if (hasSpaceToRead) {
+                    reading = true;
+                }
+            }
+        }
+
+        // immediately complete with -1 if shutdown for read
+        // immediately complete with 0 if no space remaining
+        if (shutdown || !hasSpaceToRead) {
+            CompletedFuture<V,A> result;
+            if (isScatteringRead) {
+                Long value = (shutdown) ? Long.valueOf(-1L) : Long.valueOf(0L);
+                result = (CompletedFuture<V,A>)CompletedFuture.withResult(this, value, attachment);
+            } else {
+                int value = (shutdown) ? -1 : 0;
+                result = (CompletedFuture<V,A>)CompletedFuture.withResult(this, value, attachment);
+            }
+            Invoker.invoke(handler, result);
+            return result;
+        }
+
+        return readImpl(dsts, isScatteringRead, timeout, unit, attachment, handler);
+    }
+
+    @Override
+    public final <A> Future<Integer> read(ByteBuffer dst,
+                                          long timeout,
+                                          TimeUnit unit,
+                                          A attachment,
+                                          CompletionHandler<Integer,? super A> handler)
+    {
+        if (dst.isReadOnly())
+            throw new IllegalArgumentException("Read-only buffer");
+        ByteBuffer[] bufs = new ByteBuffer[1];
+        bufs[0] = dst;
+        return read(bufs, false, timeout, unit, attachment, handler);
+    }
+
+    @Override
+    public final <A> Future<Long> read(ByteBuffer[] dsts,
+                                       int offset,
+                                       int length,
+                                       long timeout,
+                                       TimeUnit unit,
+                                       A attachment,
+                                       CompletionHandler<Long,? super A> handler)
+    {
+        if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
+            throw new IndexOutOfBoundsException();
+        ByteBuffer[] bufs = Util.subsequence(dsts, offset, length);
+        for (int i=0; i<bufs.length; i++) {
+            if (bufs[i].isReadOnly())
+                throw new IllegalArgumentException("Read-only buffer");
+        }
+        return read(bufs, true, timeout, unit, attachment, handler);
+    }
+
+    /**
+     * Invoked by write to initiate the I/O operation.
+     */
+    abstract <V extends Number,A> Future<V> writeImpl(ByteBuffer[] srcs,
+                                                      boolean isGatheringWrite,
+                                                      long timeout,
+                                                      TimeUnit unit,
+                                                      A attachment,
+                                                      CompletionHandler<V,? super A> handler);
+
+    @SuppressWarnings("unchecked")
+    private <V extends Number,A> Future<V> write(ByteBuffer[] srcs,
+                                                 boolean isGatheringWrite,
+                                                 long timeout,
+                                                 TimeUnit unit,
+                                                 A attachment,
+                                                 CompletionHandler<V,? super A> handler)
+    {
+        boolean hasDataToWrite = isGatheringWrite || srcs[0].hasRemaining();
+
+        boolean closed = false;
+        if (isOpen()) {
+            if (remoteAddress == null)
+                throw new NotYetConnectedException();
+            if (timeout < 0L)
+                throw new IllegalArgumentException("Negative timeout");
+            // check and update state
+            synchronized (writeLock) {
+                if (writeKilled)
+                    throw new RuntimeException("Writing not allowed due to timeout or cancellation");
+                if (writing)
+                    throw new WritePendingException();
+                if (writeShutdown) {
+                    closed = true;
+                } else {
+                    if (hasDataToWrite)
+                        writing = true;
+                }
+            }
+        } else {
+            closed = true;
+        }
+
+        // channel is closed or shutdown for write
+        if (closed) {
+            CompletedFuture<V,A> result = CompletedFuture
+                .withFailure(this, new ClosedChannelException(), attachment);
+            Invoker.invoke(handler, result);
+            return result;
+        }
+
+        // nothing to write so complete immediately
+        if (!hasDataToWrite) {
+            CompletedFuture<V,A> result;
+            if (isGatheringWrite) {
+                result = (CompletedFuture<V,A>)CompletedFuture.withResult(this, 0L, attachment);
+            } else {
+                result = (CompletedFuture<V,A>)CompletedFuture.withResult(this, 0, attachment);
+            }
+            Invoker.invoke(handler, result);
+            return result;
+        }
+
+        return writeImpl(srcs, isGatheringWrite, timeout, unit, attachment, handler);
+    }
+
+    @Override
+    public final <A> Future<Integer> write(ByteBuffer src,
+                                           long timeout,
+                                           TimeUnit unit,
+                                           A attachment,
+                                           CompletionHandler<Integer,? super A> handler)
+    {
+        ByteBuffer[] bufs = new ByteBuffer[1];
+        bufs[0] = src;
+        return write(bufs, false, timeout, unit, attachment, handler);
+    }
+
+    @Override
+    public final <A> Future<Long> write(ByteBuffer[] srcs,
+                                        int offset,
+                                        int length,
+                                        long timeout,
+                                        TimeUnit unit,
+                                        A attachment,
+                                        CompletionHandler<Long,? super A> handler)
+    {
+        if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
+            throw new IndexOutOfBoundsException();
+        srcs = Util.subsequence(srcs, offset, length);
+        return write(srcs, true, timeout, unit, attachment, handler);
+    }
+
+    @Override
+    public final AsynchronousSocketChannel bind(SocketAddress local)
+        throws IOException
+    {
+        try {
+            begin();
+            synchronized (stateLock) {
+                if (state == ST_PENDING)
+                    throw new ConnectionPendingException();
+                if (localAddress != null)
+                    throw new AlreadyBoundException();
+                InetSocketAddress isa = (local == null) ?
+                    new InetSocketAddress(0) : Net.checkAddress(local);
+                Net.bind(fd, isa.getAddress(), isa.getPort());
+                localAddress = Net.localAddress(fd);
+            }
+        } finally {
+            end();
+        }
+        return this;
+    }
+
+    @Override
+    public final SocketAddress getLocalAddress() throws IOException {
+        if (!isOpen())
+            throw new ClosedChannelException();
+        return localAddress;
+    }
+
+    @Override
+    public final <T> AsynchronousSocketChannel setOption(SocketOption<T> name, T value)
+        throws IOException
+    {
+        if (name == null)
+            throw new NullPointerException();
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+
+        try {
+            begin();
+            if (writeShutdown)
+                throw new IOException("Connection has been shutdown for writing");
+            Net.setSocketOption(fd, Net.UNSPEC, name, value);
+            return this;
+        } finally {
+            end();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <T> T getOption(SocketOption<T> name) throws IOException {
+        if (name == null)
+            throw new NullPointerException();
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+
+        try {
+            begin();
+            return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
+        } finally {
+            end();
+        }
+    }
+
+    private static class DefaultOptionsHolder {
+        static final Set<SocketOption<?>> defaultOptions = defaultOptions();
+
+        private static Set<SocketOption<?>> defaultOptions() {
+            HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(5);
+            set.add(StandardSocketOption.SO_SNDBUF);
+            set.add(StandardSocketOption.SO_RCVBUF);
+            set.add(StandardSocketOption.SO_KEEPALIVE);
+            set.add(StandardSocketOption.SO_REUSEADDR);
+            set.add(StandardSocketOption.TCP_NODELAY);
+            return Collections.unmodifiableSet(set);
+        }
+    }
+
+    @Override
+    public final Set<SocketOption<?>> supportedOptions() {
+        return DefaultOptionsHolder.defaultOptions;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final SocketAddress getRemoteAddress() throws IOException {
+        if (!isOpen())
+            throw new ClosedChannelException();
+        return remoteAddress;
+    }
+
+    @Override
+    public final AsynchronousSocketChannel shutdownInput() throws IOException {
+        try {
+            begin();
+            if (remoteAddress == null)
+                throw new NotYetConnectedException();
+            synchronized (readLock) {
+                if (!readShutdown) {
+                    Net.shutdown(fd, Net.SHUT_RD);
+                    readShutdown = true;
+                }
+            }
+        } finally {
+            end();
+        }
+        return this;
+    }
+
+    @Override
+    public final AsynchronousSocketChannel shutdownOutput() throws IOException {
+        try {
+            begin();
+            if (remoteAddress == null)
+                throw new NotYetConnectedException();
+            synchronized (writeLock) {
+                if (!writeShutdown) {
+                    Net.shutdown(fd, Net.SHUT_WR);
+                    writeShutdown = true;
+                }
+            }
+        } finally {
+            end();
+        }
+        return this;
+    }
+
+    @Override
+    public final String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(this.getClass().getName());
+        sb.append('[');
+        synchronized (stateLock) {
+            if (!isOpen()) {
+                sb.append("closed");
+            } else {
+                switch (state) {
+                case ST_UNCONNECTED:
+                    sb.append("unconnected");
+                    break;
+                case ST_PENDING:
+                    sb.append("connection-pending");
+                    break;
+                case ST_CONNECTED:
+                    sb.append("connected");
+                    if (readShutdown)
+                        sb.append(" ishut");
+                    if (writeShutdown)
+                        sb.append(" oshut");
+                    break;
+                }
+                if (localAddress != null) {
+                    sb.append(" local=");
+                    sb.append(localAddress.toString());
+                }
+                if (remoteAddress != null) {
+                    sb.append(" remote=");
+                    sb.append(remoteAddress.toString());
+                }
+            }
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/Cancellable.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+/**
+ * Implemented by asynchronous channels that require notification when an I/O
+ * operation is cancelled.
+ */
+
+interface Cancellable {
+    /**
+     * Invoked to notify channel that cancel has been invoked while holding
+     * the Future's lock.
+     */
+    void onCancel(PendingFuture<?,?> task);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/CompletedFuture.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.AsynchronousChannel;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ExecutionException;
+import java.io.IOException;
+
+/**
+ * A Future representing the result of an I/O operation that has already
+ * completed.
+ */
+
+final class CompletedFuture<V,A>
+    extends AbstractFuture<V,A>
+{
+    private final V result;
+    private final Throwable exc;
+
+    private CompletedFuture(AsynchronousChannel channel,
+                            V result,
+                            Throwable exc,
+                            A attachment)
+    {
+        super(channel, attachment);
+        this.result = result;
+        this.exc = exc;
+    }
+
+    @SuppressWarnings("unchecked")
+    static <V,A> CompletedFuture<V,A> withResult(AsynchronousChannel channel,
+                                                 V result,
+                                                 A attachment)
+    {
+        return new CompletedFuture<V,A>(channel, result, null, attachment);
+    }
+
+    @SuppressWarnings("unchecked")
+    static <V,A> CompletedFuture<V,A> withFailure(AsynchronousChannel channel,
+                                                  Throwable exc,
+                                                  A attachment)
+    {
+        // exception must be IOException or SecurityException
+        if (!(exc instanceof IOException) && !(exc instanceof SecurityException))
+            exc = new IOException(exc);
+        return new CompletedFuture(channel, null, exc, attachment);
+    }
+
+    @Override
+    public V get() throws ExecutionException {
+        if (exc != null)
+            throw new ExecutionException(exc);
+        return result;
+    }
+
+    @Override
+    public V get(long timeout, TimeUnit unit) throws ExecutionException {
+        if (unit == null)
+            throw new NullPointerException();
+        if (exc != null)
+            throw new ExecutionException(exc);
+        return result;
+    }
+
+    @Override
+    public boolean isCancelled() {
+        return false;
+    }
+
+    @Override
+    public boolean isDone() {
+        return true;
+    }
+
+    @Override
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        return false;
+    }
+
+    @Override
+    Throwable exception() {
+        return exc;
+    }
+
+    @Override
+    V value() {
+        return result;
+    }
+}
--- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2001-2009 Sun Microsystems, Inc.  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
@@ -111,8 +111,12 @@
     public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family) {
         super(sp);
         if ((family != StandardProtocolFamily.INET) &&
-            (family != StandardProtocolFamily.INET6)) {
-            throw new UnsupportedOperationException("Protocol family not supported");
+            (family != StandardProtocolFamily.INET6))
+        {
+            if (family == null)
+                throw new NullPointerException("'family' is null");
+            else
+                throw new UnsupportedOperationException("Protocol family not supported");
         }
         if (family == StandardProtocolFamily.INET6) {
             if (!Net.isIPv6Available()) {
@@ -149,28 +153,28 @@
     public SocketAddress getLocalAddress() throws IOException {
         synchronized (stateLock) {
             if (!isOpen())
-                return null;
+                throw new ClosedChannelException();
             return localAddress;
         }
     }
 
     @Override
-    public SocketAddress getConnectedAddress() throws IOException {
+    public SocketAddress getRemoteAddress() throws IOException {
         synchronized (stateLock) {
             if (!isOpen())
-                return null;
+                throw new ClosedChannelException();
             return remoteAddress;
         }
     }
 
     @Override
-    public DatagramChannel setOption(SocketOption name, Object value)
+    public <T> DatagramChannel setOption(SocketOption<T> name, T value)
         throws IOException
     {
         if (name == null)
             throw new NullPointerException();
-        if (!options().contains(name))
-            throw new IllegalArgumentException("Invalid option name");
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
 
         synchronized (stateLock) {
             ensureOpen();
@@ -224,8 +228,8 @@
     {
         if (name == null)
             throw new NullPointerException();
-        if (!options().contains(name))
-            throw new IllegalArgumentException("Invalid option name");
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
 
         synchronized (stateLock) {
             ensureOpen();
@@ -273,7 +277,7 @@
         }
     }
 
-    private static class LazyInitialization {
+    private static class DefaultOptionsHolder {
         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
 
         private static Set<SocketOption<?>> defaultOptions() {
@@ -291,8 +295,8 @@
     }
 
     @Override
-    public final Set<SocketOption<?>> options() {
-        return LazyInitialization.defaultOptions;
+    public final Set<SocketOption<?>> supportedOptions() {
+        return DefaultOptionsHolder.defaultOptions;
     }
 
     private void ensureOpen() throws ClosedChannelException {
@@ -864,23 +868,26 @@
     }
 
     // package-private
-    void drop(MembershipKeyImpl key)
-        throws IOException
-    {
-        assert key.getChannel() == this;
+    void drop(MembershipKeyImpl key) {
+        assert key.channel() == this;
 
         synchronized (stateLock) {
             if (!key.isValid())
                 return;
 
-            if (family == StandardProtocolFamily.INET6) {
-                MembershipKeyImpl.Type6 key6 =
-                    (MembershipKeyImpl.Type6)key;
-                Net.drop6(fd, key6.group(), key6.index(), key6.source());
-            } else {
-                MembershipKeyImpl.Type4 key4 =
-                    (MembershipKeyImpl.Type4)key;
-                Net.drop4(fd, key4.group(), key4.interfaceAddress(), key4.source());
+            try {
+                if (family == StandardProtocolFamily.INET6) {
+                    MembershipKeyImpl.Type6 key6 =
+                        (MembershipKeyImpl.Type6)key;
+                    Net.drop6(fd, key6.groupAddress(), key6.index(), key6.source());
+                } else {
+                    MembershipKeyImpl.Type4 key4 = (MembershipKeyImpl.Type4)key;
+                    Net.drop4(fd, key4.groupAddress(), key4.interfaceAddress(),
+                        key4.source());
+                }
+            } catch (IOException ioe) {
+                // should not happen
+                throw new AssertionError(ioe);
             }
 
             key.invalidate();
@@ -895,8 +902,8 @@
     void block(MembershipKeyImpl key, InetAddress source)
         throws IOException
     {
-        assert key.getChannel() == this;
-        assert key.getSourceAddress() == null;
+        assert key.channel() == this;
+        assert key.sourceAddress() == null;
 
         synchronized (stateLock) {
             if (!key.isValid())
@@ -905,19 +912,19 @@
                 throw new IllegalArgumentException("Source address is a wildcard address");
             if (source.isMulticastAddress())
                 throw new IllegalArgumentException("Source address is multicast address");
-            if (source.getClass() != key.getGroup().getClass())
+            if (source.getClass() != key.group().getClass())
                 throw new IllegalArgumentException("Source address is different type to group");
 
             int n;
             if (family == StandardProtocolFamily.INET6) {
                  MembershipKeyImpl.Type6 key6 =
                     (MembershipKeyImpl.Type6)key;
-                n = Net.block6(fd, key6.group(), key6.index(),
+                n = Net.block6(fd, key6.groupAddress(), key6.index(),
                                Net.inet6AsByteArray(source));
             } else {
                 MembershipKeyImpl.Type4 key4 =
                     (MembershipKeyImpl.Type4)key;
-                n = Net.block4(fd, key4.group(), key4.interfaceAddress(),
+                n = Net.block4(fd, key4.groupAddress(), key4.interfaceAddress(),
                                Net.inet4AsInt(source));
             }
             if (n == IOStatus.UNAVAILABLE) {
@@ -930,26 +937,29 @@
     /**
      * Unblock given source.
      */
-    void unblock(MembershipKeyImpl key, InetAddress source)
-        throws IOException
-    {
-        assert key.getChannel() == this;
-        assert key.getSourceAddress() == null;
+    void unblock(MembershipKeyImpl key, InetAddress source) {
+        assert key.channel() == this;
+        assert key.sourceAddress() == null;
 
         synchronized (stateLock) {
             if (!key.isValid())
                 throw new IllegalStateException("key is no longer valid");
 
-            if (family == StandardProtocolFamily.INET6) {
-                MembershipKeyImpl.Type6 key6 =
-                    (MembershipKeyImpl.Type6)key;
-                Net.unblock6(fd, key6.group(), key6.index(),
-                             Net.inet6AsByteArray(source));
-            } else {
-                MembershipKeyImpl.Type4 key4 =
-                    (MembershipKeyImpl.Type4)key;
-                Net.unblock4(fd, key4.group(), key4.interfaceAddress(),
-                             Net.inet4AsInt(source));
+            try {
+                if (family == StandardProtocolFamily.INET6) {
+                    MembershipKeyImpl.Type6 key6 =
+                        (MembershipKeyImpl.Type6)key;
+                    Net.unblock6(fd, key6.groupAddress(), key6.index(),
+                                 Net.inet6AsByteArray(source));
+                } else {
+                    MembershipKeyImpl.Type4 key4 =
+                        (MembershipKeyImpl.Type4)key;
+                    Net.unblock4(fd, key4.groupAddress(), key4.interfaceAddress(),
+                                 Net.inet4AsInt(source));
+                }
+            } catch (IOException ioe) {
+                // should not happen
+                throw new AssertionError(ioe);
             }
         }
     }
--- a/jdk/src/share/classes/sun/nio/ch/ExtendedSocketOption.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/ExtendedSocketOption.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  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
--- a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -26,27 +26,18 @@
 package sun.nio.ch;
 
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.RandomAccessFile;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.MappedByteBuffer;
 import java.nio.BufferPoolMXBean;
 import java.nio.channels.*;
-import java.nio.channels.spi.*;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Iterator;
-import java.util.concurrent.ConcurrentHashMap;
-import java.lang.ref.WeakReference;
-import java.lang.ref.ReferenceQueue;
 import java.lang.reflect.Field;
 import java.security.AccessController;
-import java.security.PrivilegedAction;
 import javax.management.ObjectName;
 import javax.management.MalformedObjectNameException;
-
 import sun.misc.Cleaner;
 import sun.security.action.GetPropertyAction;
 
@@ -55,7 +46,7 @@
 {
 
     // Used to make native read and write calls
-    private static final NativeDispatcher nd;
+    private static final FileDispatcher nd;
 
     // Memory allocation size for mapping buffers
     private static final long allocationGranularity;
@@ -104,20 +95,19 @@
     // -- Standard channel operations --
 
     protected void implCloseChannel() throws IOException {
-
-        nd.preClose(fd);
-        threads.signal();
-
         // Invalidate and release any locks that we still hold
         if (fileLockTable != null) {
             fileLockTable.removeAll( new FileLockTable.Releaser() {
                 public void release(FileLock fl) throws IOException {
                     ((FileLockImpl)fl).invalidate();
-                    release0(fd, fl.position(), fl.size());
+                    nd.release(fd, fl.position(), fl.size());
                 }
             });
         }
 
+        nd.preClose(fd);
+        threads.signalAndWait();
+
         if (parent != null) {
 
             // Close the fd via the parent stream's close method.  The parent
@@ -138,12 +128,11 @@
             throw new NonReadableChannelException();
         synchronized (positionLock) {
             int n = 0;
-            int ti = -1;
+            int ti = threads.add();
             try {
                 begin();
                 if (!isOpen())
                     return 0;
-                ti = threads.add();
                 do {
                     n = IOUtil.read(fd, dst, -1, nd, positionLock);
                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
@@ -162,12 +151,11 @@
             throw new NonReadableChannelException();
         synchronized (positionLock) {
             long n = 0;
-            int ti = -1;
+            int ti = threads.add();
             try {
                 begin();
                 if (!isOpen())
                     return 0;
-                ti = threads.add();
                 do {
                     n = IOUtil.read(fd, dsts, nd);
                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
@@ -195,12 +183,11 @@
             throw new NonWritableChannelException();
         synchronized (positionLock) {
             int n = 0;
-            int ti = -1;
+            int ti = threads.add();
             try {
                 begin();
                 if (!isOpen())
                     return 0;
-                ti = threads.add();
                 do {
                     n = IOUtil.write(fd, src, -1, nd, positionLock);
                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
@@ -219,12 +206,11 @@
             throw new NonWritableChannelException();
         synchronized (positionLock) {
             long n = 0;
-            int ti = -1;
+            int ti = threads.add();
             try {
                 begin();
                 if (!isOpen())
                     return 0;
-                ti = threads.add();
                 do {
                     n = IOUtil.write(fd, srcs, nd);
                 } while ((n == IOStatus.INTERRUPTED) && isOpen());
@@ -253,12 +239,11 @@
         ensureOpen();
         synchronized (positionLock) {
             long p = -1;
-            int ti = -1;
+            int ti = threads.add();
             try {
                 begin();
                 if (!isOpen())
                     return 0;
-                ti = threads.add();
                 do {
                     p = position0(fd, -1);
                 } while ((p == IOStatus.INTERRUPTED) && isOpen());
@@ -277,12 +262,11 @@
             throw new IllegalArgumentException();
         synchronized (positionLock) {
             long p = -1;
-            int ti = -1;
+            int ti = threads.add();
             try {
                 begin();
                 if (!isOpen())
                     return null;
-                ti = threads.add();
                 do {
                     p  = position0(fd, newPosition);
                 } while ((p == IOStatus.INTERRUPTED) && isOpen());
@@ -299,14 +283,13 @@
         ensureOpen();
         synchronized (positionLock) {
             long s = -1;
-            int ti = -1;
+            int ti = threads.add();
             try {
                 begin();
                 if (!isOpen())
                     return -1;
-                ti = threads.add();
                 do {
-                    s = size0(fd);
+                    s = nd.size(fd);
                 } while ((s == IOStatus.INTERRUPTED) && isOpen());
                 return IOStatus.normalize(s);
             } finally {
@@ -328,12 +311,11 @@
         synchronized (positionLock) {
             int rv = -1;
             long p = -1;
-            int ti = -1;
+            int ti = threads.add();
             try {
                 begin();
                 if (!isOpen())
                     return null;
-                ti = threads.add();
 
                 // get current position
                 do {
@@ -345,7 +327,7 @@
 
                 // truncate file
                 do {
-                    rv = truncate0(fd, size);
+                    rv = nd.truncate(fd, size);
                 } while ((rv == IOStatus.INTERRUPTED) && isOpen());
                 if (!isOpen())
                     return null;
@@ -368,14 +350,13 @@
     public void force(boolean metaData) throws IOException {
         ensureOpen();
         int rv = -1;
-        int ti = -1;
+        int ti = threads.add();
         try {
             begin();
             if (!isOpen())
                 return;
-            ti = threads.add();
             do {
-                rv = force0(fd, metaData);
+                rv = nd.force(fd, metaData);
             } while ((rv == IOStatus.INTERRUPTED) && isOpen());
         } finally {
             threads.remove(ti);
@@ -425,12 +406,11 @@
             return IOStatus.UNSUPPORTED;
 
         long n = -1;
-        int ti = -1;
+        int ti = threads.add();
         try {
             begin();
             if (!isOpen())
                 return -1;
-            ti = threads.add();
             do {
                 n = transferTo0(thisFDVal, position, icount, targetFDVal);
             } while ((n == IOStatus.INTERRUPTED) && isOpen());
@@ -632,12 +612,11 @@
             throw new NonReadableChannelException();
         ensureOpen();
         int n = 0;
-        int ti = -1;
+        int ti = threads.add();
         try {
             begin();
             if (!isOpen())
                 return -1;
-            ti = threads.add();
             do {
                 n = IOUtil.read(fd, dst, position, nd, positionLock);
             } while ((n == IOStatus.INTERRUPTED) && isOpen());
@@ -658,12 +637,11 @@
             throw new NonWritableChannelException();
         ensureOpen();
         int n = 0;
-        int ti = -1;
+        int ti = threads.add();
         try {
             begin();
             if (!isOpen())
                 return -1;
-            ti = threads.add();
             do {
                 n = IOUtil.write(fd, src, position, nd, positionLock);
             } while ((n == IOStatus.INTERRUPTED) && isOpen());
@@ -753,12 +731,11 @@
             throw new NonReadableChannelException();
 
         long addr = -1;
-        int ti = -1;
+        int ti = threads.add();
         try {
             begin();
             if (!isOpen())
                 return null;
-            ti = threads.add();
             if (size() < position + size) { // Extend file size
                 if (!writable) {
                     throw new IOException("Channel not open for writing " +
@@ -766,7 +743,7 @@
                 }
                 int rv;
                 do {
-                    rv = truncate0(fd, position + size);
+                    rv = nd.truncate(fd, position + size);
                 } while ((rv == IOStatus.INTERRUPTED) && isOpen());
             }
             if (size == 0) {
@@ -860,10 +837,7 @@
 
     // -- Locks --
 
-    public static final int NO_LOCK = -1;       // Failed to lock
-    public static final int LOCKED = 0;         // Obtained requested lock
-    public static final int RET_EX_LOCK = 1;    // Obtained exclusive lock
-    public static final int INTERRUPTED = 2;    // Request interrupted
+
 
     // keeps track of locks on this file
     private volatile FileLockTable fileLockTable;
@@ -893,12 +867,21 @@
         return isSharedFileLockTable;
     }
 
-    private FileLockTable fileLockTable() {
+    private FileLockTable fileLockTable() throws IOException {
         if (fileLockTable == null) {
             synchronized (this) {
                 if (fileLockTable == null) {
-                    fileLockTable = isSharedFileLockTable() ?
-                        new SharedFileLockTable(this) : new SimpleFileLockTable();
+                    if (isSharedFileLockTable()) {
+                        int ti = threads.add();
+                        try {
+                            ensureOpen();
+                            fileLockTable = FileLockTable.newSharedFileLockTable(this, fd);
+                        } finally {
+                            threads.remove(ti);
+                        }
+                    } else {
+                        fileLockTable = new SimpleFileLockTable();
+                    }
                 }
             }
         }
@@ -917,21 +900,20 @@
         FileLockTable flt = fileLockTable();
         flt.add(fli);
         boolean i = true;
-        int ti = -1;
+        int ti = threads.add();
         try {
             begin();
             if (!isOpen())
                 return null;
-            ti = threads.add();
-            int result = lock0(fd, true, position, size, shared);
-            if (result == RET_EX_LOCK) {
+            int result = nd.lock(fd, true, position, size, shared);
+            if (result == FileDispatcher.RET_EX_LOCK) {
                 assert shared;
                 FileLockImpl fli2 = new FileLockImpl(this, position, size,
                                                      false);
                 flt.replace(fli, fli2);
                 return fli2;
             }
-            if (result == INTERRUPTED || result == NO_LOCK) {
+            if (result == FileDispatcher.INTERRUPTED || result == FileDispatcher.NO_LOCK) {
                 flt.remove(fli);
                 i = false;
             }
@@ -960,77 +942,54 @@
         FileLockImpl fli = new FileLockImpl(this, position, size, shared);
         FileLockTable flt = fileLockTable();
         flt.add(fli);
-        int result = lock0(fd, false, position, size, shared);
-        if (result == NO_LOCK) {
-            flt.remove(fli);
-            return null;
+        int result;
+
+        int ti = threads.add();
+        try {
+            try {
+                ensureOpen();
+                result = nd.lock(fd, false, position, size, shared);
+            } catch (IOException e) {
+                flt.remove(fli);
+                throw e;
+            }
+            if (result == FileDispatcher.NO_LOCK) {
+                flt.remove(fli);
+                return null;
+            }
+            if (result == FileDispatcher.RET_EX_LOCK) {
+                assert shared;
+                FileLockImpl fli2 = new FileLockImpl(this, position, size,
+                                                     false);
+                flt.replace(fli, fli2);
+                return fli2;
+            }
+            return fli;
+        } finally {
+            threads.remove(ti);
         }
-        if (result == RET_EX_LOCK) {
-            assert shared;
-            FileLockImpl fli2 = new FileLockImpl(this, position, size,
-                                                 false);
-            flt.replace(fli, fli2);
-            return fli2;
-        }
-        return fli;
     }
 
     void release(FileLockImpl fli) throws IOException {
         ensureOpen();
-        release0(fd, fli.position(), fli.size());
+        int ti = threads.add();
+        try {
+            ensureOpen();
+            nd.release(fd, fli.position(), fli.size());
+        } finally {
+            threads.remove(ti);
+        }
         assert fileLockTable != null;
         fileLockTable.remove(fli);
     }
 
-
-    // -- File lock support  --
-
-    /**
-     * A table of FileLocks.
-     */
-    private interface FileLockTable {
-        /**
-         * Adds a file lock to the table.
-         *
-         * @throws OverlappingFileLockException if the file lock overlaps
-         *         with an existing file lock in the table
-         */
-        void add(FileLock fl) throws OverlappingFileLockException;
-
-        /**
-         * Remove an existing file lock from the table.
-         */
-        void remove(FileLock fl);
-
-        /**
-         * An implementation of this interface releases a given file lock.
-         * Used with removeAll.
-         */
-        interface Releaser {
-            void release(FileLock fl) throws IOException;
-        }
-
-        /**
-         * Removes all file locks from the table.
-         * <p>
-         * The Releaser#release method is invoked for each file lock before
-         * it is removed.
-         *
-         * @throws IOException if the release method throws IOException
-         */
-        void removeAll(Releaser r) throws IOException;
-
-        /**
-         * Replaces an existing file lock in the table.
-         */
-        void replace(FileLock fl1, FileLock fl2);
-    }
+    // -- File lock support --
 
     /**
      * A simple file lock table that maintains a list of FileLocks obtained by a
      * FileChannel. Use to get 1.4/5.0 behaviour.
      */
-    private static class SimpleFileLockTable implements FileLockTable {
+    private static class SimpleFileLockTable extends FileLockTable {
         // synchronize on list for access
         private List<FileLock> lockList = new ArrayList<FileLock>(2);
 
@@ -1080,207 +1039,8 @@
         }
     }
 
-    /**
-     * A weak reference to a FileLock.
-     * <p>
-     * SharedFileLockTable uses a list of file lock references to avoid keeping the
-     * FileLock (and FileChannel) alive.
-     */
-    private static class FileLockReference extends WeakReference<FileLock> {
-        private FileKey fileKey;
-
-        FileLockReference(FileLock referent,
-                          ReferenceQueue<FileLock> queue,
-                          FileKey key) {
-            super(referent, queue);
-            this.fileKey = key;
-        }
-
-        private FileKey fileKey() {
-            return fileKey;
-        }
-    }
-
-    /**
-     * A file lock table that is over a system-wide map of all file locks.
-     */
-    private static class SharedFileLockTable implements FileLockTable {
-        // The system-wide map is a ConcurrentHashMap that is keyed on the FileKey.
-        // The map value is a list of file locks represented by FileLockReferences.
-        // All access to the list must be synchronized on the list.
-        private static ConcurrentHashMap<FileKey, ArrayList<FileLockReference>> lockMap =
-            new ConcurrentHashMap<FileKey, ArrayList<FileLockReference>>();
-
-        // reference queue for cleared refs
-        private static ReferenceQueue<FileLock> queue = new ReferenceQueue<FileLock>();
-
-        // the enclosing file channel
-        private FileChannelImpl fci;
-
-        // File key for the file that this channel is connected to
-        private FileKey fileKey;
-
-        public SharedFileLockTable(FileChannelImpl fci) {
-            this.fci = fci;
-            this.fileKey = FileKey.create(fci.fd);
-        }
-
-        public void add(FileLock fl) throws OverlappingFileLockException {
-            ArrayList<FileLockReference> list = lockMap.get(fileKey);
-
-            for (;;) {
-
-                // The key isn't in the map so we try to create it atomically
-                if (list == null) {
-                    list = new ArrayList<FileLockReference>(2);
-                    ArrayList<FileLockReference> prev;
-                    synchronized (list) {
-                        prev = lockMap.putIfAbsent(fileKey, list);
-                        if (prev == null) {
-                            // we successfully created the key so we add the file lock
-                            list.add(new FileLockReference(fl, queue, fileKey));
-                            break;
-                        }
-                    }
-                    // someone else got there first
-                    list = prev;
-                }
-
-                // There is already a key. It is possible that some other thread
-                // is removing it so we re-fetch the value from the map. If it
-                // hasn't changed then we check the list for overlapping locks
-                // and add the new lock to the list.
-                synchronized (list) {
-                    ArrayList<FileLockReference> current = lockMap.get(fileKey);
-                    if (list == current) {
-                        checkList(list, fl.position(), fl.size());
-                        list.add(new FileLockReference(fl, queue, fileKey));
-                        break;
-                    }
-                    list = current;
-                }
-
-            }
-
-            // process any stale entries pending in the reference queue
-            removeStaleEntries();
-        }
-
-        private void removeKeyIfEmpty(FileKey fk, ArrayList<FileLockReference> list) {
-            assert Thread.holdsLock(list);
-            assert lockMap.get(fk) == list;
-            if (list.isEmpty()) {
-                lockMap.remove(fk);
-            }
-        }
-
-        public void remove(FileLock fl) {
-            assert fl != null;
-
-            // the lock must exist so the list of locks must be present
-            ArrayList<FileLockReference> list = lockMap.get(fileKey);
-            assert list != null;
-
-            synchronized (list) {
-                int index = 0;
-                while (index < list.size()) {
-                    FileLockReference ref = list.get(index);
-                    FileLock lock = ref.get();
-                    if (lock == fl) {
-                        assert (lock != null) && (lock.channel() == fci);
-                        ref.clear();
-                        list.remove(index);
-                        break;
-                    }
-                    index++;
-                }
-            }
-        }
-
-        public void removeAll(Releaser releaser) throws IOException {
-            ArrayList<FileLockReference> list = lockMap.get(fileKey);
-            if (list != null) {
-                synchronized (list) {
-                    int index = 0;
-                    while (index < list.size()) {
-                        FileLockReference ref = list.get(index);
-                        FileLock lock = ref.get();
-
-                        // remove locks obtained by this channel
-                        if (lock != null && lock.channel() == fci) {
-                            // invoke the releaser to invalidate/release the lock
-                            releaser.release(lock);
-
-                            // remove the lock from the list
-                            ref.clear();
-                            list.remove(index);
-                        } else {
-                            index++;
-                        }
-                    }
-
-                    // once the lock list is empty we remove it from the map
-                    removeKeyIfEmpty(fileKey, list);
-                }
-            }
-        }
-
-        public void replace(FileLock fromLock, FileLock toLock) {
-            // the lock must exist so there must be a list
-            ArrayList<FileLockReference> list = lockMap.get(fileKey);
-            assert list != null;
-
-            synchronized (list) {
-                for (int index=0; index<list.size(); index++) {
-                    FileLockReference ref = list.get(index);
-                    FileLock lock = ref.get();
-                    if (lock == fromLock) {
-                        ref.clear();
-                        list.set(index, new FileLockReference(toLock, queue, fileKey));
-                        break;
-                    }
-                }
-            }
-        }
-
-        // Check for overlapping file locks
-        private void checkList(List<FileLockReference> list, long position, long size)
-            throws OverlappingFileLockException
-        {
-            assert Thread.holdsLock(list);
-            for (FileLockReference ref: list) {
-                FileLock fl = ref.get();
-                if (fl != null && fl.overlaps(position, size))
-                    throw new OverlappingFileLockException();
-            }
-        }
-
-        // Process the reference queue
-        private void removeStaleEntries() {
-            FileLockReference ref;
-            while ((ref = (FileLockReference)queue.poll()) != null) {
-                FileKey fk = ref.fileKey();
-                ArrayList<FileLockReference> list = lockMap.get(fk);
-                if (list != null) {
-                    synchronized (list) {
-                        list.remove(ref);
-                        removeKeyIfEmpty(fk, list);
-                    }
-                }
-            }
-        }
-    }
-
     // -- Native methods --
 
-    // Grabs a file lock
-    native int lock0(FileDescriptor fd, boolean blocking, long pos, long size,
-                     boolean shared) throws IOException;
-
-    // Releases a file lock
-    native void release0(FileDescriptor fd, long pos, long size)
-        throws IOException;
-
     // Creates a new mapping
     private native long map0(int prot, long position, long length)
         throws IOException;
@@ -1288,12 +1048,6 @@
     // Removes an existing mapping
     private static native int unmap0(long address, long length);
 
-    // Forces output to device
-    private native int force0(FileDescriptor fd, boolean metaData);
-
-    // Truncates a file
-    private native int truncate0(FileDescriptor fd, long size);
-
     // Transfers from src to dst, or returns -2 if kernel can't do that
     private native long transferTo0(int src, long position, long count, int dst);
 
@@ -1302,16 +1056,13 @@
     // otherwise the position is set to offset
     private native long position0(FileDescriptor fd, long offset);
 
-    // Reports this file's size
-    private native long size0(FileDescriptor fd);
-
     // Caches fieldIDs
     private static native long initIDs();
 
     static {
         Util.load();
         allocationGranularity = initIDs();
-        nd = new FileDispatcher();
+        nd = new FileDispatcherImpl();
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/FileDispatcher.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.io.*;
+
+abstract class FileDispatcher extends NativeDispatcher {
+
+    public static final int NO_LOCK = -1;       // Failed to lock
+    public static final int LOCKED = 0;         // Obtained requested lock
+    public static final int RET_EX_LOCK = 1;    // Obtained exclusive lock
+    public static final int INTERRUPTED = 2;    // Request interrupted
+
+    abstract int force(FileDescriptor fd, boolean metaData) throws IOException;
+
+    abstract int truncate(FileDescriptor fd, long size) throws IOException;
+
+    abstract long size(FileDescriptor fd) throws IOException;
+
+    abstract int lock(FileDescriptor fd, boolean blocking, long pos, long size,
+                       boolean shared) throws IOException;
+
+    abstract void release(FileDescriptor fd, long pos, long size)
+        throws IOException;
+}
--- a/jdk/src/share/classes/sun/nio/ch/FileLockImpl.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/FileLockImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2003 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2001-2009 Sun Microsystems, Inc.  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
@@ -26,9 +26,7 @@
 package sun.nio.ch;
 
 import java.io.IOException;
-import java.nio.channels.ClosedChannelException;
-import java.nio.channels.FileLock;
-import java.nio.channels.FileChannel;
+import java.nio.channels.*;
 
 public class FileLockImpl
     extends FileLock
@@ -41,6 +39,12 @@
         this.valid = true;
     }
 
+    FileLockImpl(AsynchronousFileChannel channel, long position, long size, boolean shared)
+    {
+        super(channel, position, size, shared);
+        this.valid = true;
+    }
+
     public synchronized boolean isValid() {
         return valid;
     }
@@ -50,10 +54,15 @@
     }
 
     public synchronized void release() throws IOException {
-        if (!channel().isOpen())
+        Channel ch = acquiredBy();
+        if (!ch.isOpen())
             throw new ClosedChannelException();
         if (valid) {
-            ((FileChannelImpl)channel()).release(this);
+            if (ch instanceof FileChannelImpl)
+                ((FileChannelImpl)ch).release(this);
+            else if (ch instanceof AsynchronousFileChannelImpl)
+                ((AsynchronousFileChannelImpl)ch).release(this);
+            else throw new AssertionError();
             valid = false;
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/FileLockTable.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2005-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.lang.ref.*;
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+abstract class FileLockTable {
+    protected FileLockTable() {
+    }
+
+    /**
+     * Creates and returns a file lock table for a channel that is connected to
+     * the a system-wide map of all file locks for the Java virtual machine.
+     */
+    public static FileLockTable newSharedFileLockTable(Channel channel,
+                                                       FileDescriptor fd)
+        throws IOException
+    {
+        return new SharedFileLockTable(channel, fd);
+    }
+
+    /**
+     * Adds a file lock to the table.
+     *
+     * @throws OverlappingFileLockException if the file lock overlaps
+     *         with an existing file lock in the table
+     */
+    public abstract void add(FileLock fl) throws OverlappingFileLockException;
+
+    /**
+     * Remove an existing file lock from the table.
+     */
+    public abstract void remove(FileLock fl);
+
+    /**
+     * An implementation of this interface releases a given file lock.
+     * Used with removeAll.
+     */
+    public abstract interface Releaser {
+        void release(FileLock fl) throws IOException;
+    }
+
+    /**
+     * Removes all file locks from the table.
+     * <p>
+     * The Releaser#release method is invoked for each file lock before
+     * it is removed.
+     *
+     * @throws IOException if the release method throws IOException
+     */
+    public abstract void removeAll(Releaser r) throws IOException;
+
+    /**
+     * Replaces an existing file lock in the table.
+     */
+    public abstract void replace(FileLock fl1, FileLock fl2);
+}
+
+
+/**
+ * A file lock table that is over a system-wide map of all file locks.
+ */
+class SharedFileLockTable extends FileLockTable {
+
+    /**
+     * A weak reference to a FileLock.
+     * <p>
+     * SharedFileLockTable uses a list of file lock references to avoid keeping the
+     * FileLock (and FileChannel) alive.
+     */
+    private static class FileLockReference extends WeakReference<FileLock> {
+        private FileKey fileKey;
+
+        FileLockReference(FileLock referent,
+                          ReferenceQueue<FileLock> queue,
+                          FileKey key) {
+            super(referent, queue);
+            this.fileKey = key;
+        }
+
+        FileKey fileKey() {
+            return fileKey;
+        }
+    }
+
+    // The system-wide map is a ConcurrentHashMap that is keyed on the FileKey.
+    // The map value is a list of file locks represented by FileLockReferences.
+    // All access to the list must be synchronized on the list.
+    private static ConcurrentHashMap<FileKey, List<FileLockReference>> lockMap =
+        new ConcurrentHashMap<FileKey, List<FileLockReference>>();
+
+    // reference queue for cleared refs
+    private static ReferenceQueue<FileLock> queue = new ReferenceQueue<FileLock>();
+
+    // The connection to which this table is connected
+    private final Channel channel;
+
+    // File key for the file that this channel is connected to
+    private final FileKey fileKey;
+
+    SharedFileLockTable(Channel channel, FileDescriptor fd) throws IOException {
+        this.channel = channel;
+        this.fileKey = FileKey.create(fd);
+    }
+
+    @Override
+    public void add(FileLock fl) throws OverlappingFileLockException {
+        List<FileLockReference> list = lockMap.get(fileKey);
+
+        for (;;) {
+
+            // The key isn't in the map so we try to create it atomically
+            if (list == null) {
+                list = new ArrayList<FileLockReference>(2);
+                List<FileLockReference> prev;
+                synchronized (list) {
+                    prev = lockMap.putIfAbsent(fileKey, list);
+                    if (prev == null) {
+                        // we successfully created the key so we add the file lock
+                        list.add(new FileLockReference(fl, queue, fileKey));
+                        break;
+                    }
+                }
+                // someone else got there first
+                list = prev;
+            }
+
+            // There is already a key. It is possible that some other thread
+            // is removing it so we re-fetch the value from the map. If it
+            // hasn't changed then we check the list for overlapping locks
+            // and add the new lock to the list.
+            synchronized (list) {
+                List<FileLockReference> current = lockMap.get(fileKey);
+                if (list == current) {
+                    checkList(list, fl.position(), fl.size());
+                    list.add(new FileLockReference(fl, queue, fileKey));
+                    break;
+                }
+                list = current;
+            }
+
+        }
+
+        // process any stale entries pending in the reference queue
+        removeStaleEntries();
+    }
+
+    private void removeKeyIfEmpty(FileKey fk, List<FileLockReference> list) {
+        assert Thread.holdsLock(list);
+        assert lockMap.get(fk) == list;
+        if (list.isEmpty()) {
+            lockMap.remove(fk);
+        }
+    }
+
+    @Override
+    public void remove(FileLock fl) {
+        assert fl != null;
+
+        // the lock must exist so the list of locks must be present
+        List<FileLockReference> list = lockMap.get(fileKey);
+        if (list == null) return;
+
+        synchronized (list) {
+            int index = 0;
+            while (index < list.size()) {
+                FileLockReference ref = list.get(index);
+                FileLock lock = ref.get();
+                if (lock == fl) {
+                    assert (lock != null) && (lock.channel() == channel);
+                    ref.clear();
+                    list.remove(index);
+                    break;
+                }
+                index++;
+            }
+        }
+    }
+
+    @Override
+    public void removeAll(Releaser releaser) throws IOException {
+        List<FileLockReference> list = lockMap.get(fileKey);
+        if (list != null) {
+            synchronized (list) {
+                int index = 0;
+                while (index < list.size()) {
+                    FileLockReference ref = list.get(index);
+                    FileLock lock = ref.get();
+
+                    // remove locks obtained by this channel
+                    if (lock != null && lock.channel() == channel) {
+                        // invoke the releaser to invalidate/release the lock
+                        releaser.release(lock);
+
+                        // remove the lock from the list
+                        ref.clear();
+                        list.remove(index);
+                    } else {
+                        index++;
+                    }
+                }
+
+                // once the lock list is empty we remove it from the map
+                removeKeyIfEmpty(fileKey, list);
+            }
+        }
+    }
+
+    @Override
+    public void replace(FileLock fromLock, FileLock toLock) {
+        // the lock must exist so there must be a list
+        List<FileLockReference> list = lockMap.get(fileKey);
+        assert list != null;
+
+        synchronized (list) {
+            for (int index=0; index<list.size(); index++) {
+                FileLockReference ref = list.get(index);
+                FileLock lock = ref.get();
+                if (lock == fromLock) {
+                    ref.clear();
+                    list.set(index, new FileLockReference(toLock, queue, fileKey));
+                    break;
+                }
+            }
+        }
+    }
+
+    // Check for overlapping file locks
+    private void checkList(List<FileLockReference> list, long position, long size)
+        throws OverlappingFileLockException
+    {
+        assert Thread.holdsLock(list);
+        for (FileLockReference ref: list) {
+            FileLock fl = ref.get();
+            if (fl != null && fl.overlaps(position, size))
+                throw new OverlappingFileLockException();
+        }
+    }
+
+    // Process the reference queue
+    private void removeStaleEntries() {
+        FileLockReference ref;
+        while ((ref = (FileLockReference)queue.poll()) != null) {
+            FileKey fk = ref.fileKey();
+            List<FileLockReference> list = lockMap.get(fk);
+            if (list != null) {
+                synchronized (list) {
+                    list.remove(ref);
+                    removeKeyIfEmpty(fk, list);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/Groupable.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+/**
+ * Implemented by asynchronous channels that can be associated with an
+ * asynchronous channel group.
+ */
+
+interface Groupable {
+    AsynchronousChannelGroupImpl group();
+}
--- a/jdk/src/share/classes/sun/nio/ch/IOUtil.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/IOUtil.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2002 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -27,10 +27,7 @@
 
 import java.io.FileDescriptor;
 import java.io.IOException;
-import java.net.*;
 import java.nio.ByteBuffer;
-import java.nio.channels.*;
-import java.nio.channels.spi.*;
 
 
 /**
@@ -47,7 +44,6 @@
      */
     private static int remaining(ByteBuffer[] bufs) {
         int numBufs = bufs.length;
-        boolean remaining = false;
         for (int i=0; i<numBufs; i++) {
             if (bufs[i].hasRemaining()) {
                 return i;
@@ -138,74 +134,82 @@
             bufs = skipBufs(bufs, nextWithRemaining);
 
         int numBufs = bufs.length;
-        int bytesReadyToWrite = 0;
 
         // Create shadow to ensure DirectByteBuffers are used
         ByteBuffer[] shadow = new ByteBuffer[numBufs];
-        for (int i=0; i<numBufs; i++) {
-            if (!(bufs[i] instanceof DirectBuffer)) {
-                int pos = bufs[i].position();
-                int lim = bufs[i].limit();
-                assert (pos <= lim);
-                int rem = (pos <= lim ? lim - pos : 0);
+        try {
+            for (int i=0; i<numBufs; i++) {
+                if (!(bufs[i] instanceof DirectBuffer)) {
+                    int pos = bufs[i].position();
+                    int lim = bufs[i].limit();
+                    assert (pos <= lim);
+                    int rem = (pos <= lim ? lim - pos : 0);
+
+                    ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
+                    shadow[i] = bb;
+                    // Leave slow buffer position untouched; it will be updated
+                    // after we see how many bytes were really written out
+                    bb.put(bufs[i]);
+                    bufs[i].position(pos);
+                    bb.flip();
+                } else {
+                    shadow[i] = bufs[i];
+                }
+            }
+
+            IOVecWrapper vec = null;
+            long bytesWritten = 0;
+            try {
+                // Create a native iovec array
+                vec= new IOVecWrapper(numBufs);
+
+                // Fill in the iovec array with appropriate data
+                for (int i=0; i<numBufs; i++) {
+                    ByteBuffer nextBuffer = shadow[i];
+                    // put in the buffer addresses
+                    long pos = nextBuffer.position();
+                    long len = nextBuffer.limit() - pos;
+                    vec.putBase(i, ((DirectBuffer)nextBuffer).address() + pos);
+                    vec.putLen(i, len);
+                }
 
-                ByteBuffer bb = ByteBuffer.allocateDirect(rem);
-                shadow[i] = bb;
-                // Leave slow buffer position untouched; it will be updated
-                // after we see how many bytes were really written out
-                bb.put(bufs[i]);
-                bufs[i].position(pos);
-                bb.flip();
-            } else {
-                shadow[i] = bufs[i];
+                // Invoke native call to fill the buffers
+                bytesWritten = nd.writev(fd, vec.address, numBufs);
+            } finally {
+                vec.free();
+            }
+            long returnVal = bytesWritten;
+
+            // Notify the buffers how many bytes were taken
+            for (int i=0; i<numBufs; i++) {
+                ByteBuffer nextBuffer = bufs[i];
+                int pos = nextBuffer.position();
+                int lim = nextBuffer.limit();
+                assert (pos <= lim);
+                int len = (pos <= lim ? lim - pos : lim);
+                if (bytesWritten >= len) {
+                    bytesWritten -= len;
+                    int newPosition = pos + len;
+                    nextBuffer.position(newPosition);
+                } else { // Buffers not completely filled
+                    if (bytesWritten > 0) {
+                        assert(pos + bytesWritten < (long)Integer.MAX_VALUE);
+                        int newPosition = (int)(pos + bytesWritten);
+                        nextBuffer.position(newPosition);
+                    }
+                    break;
+                }
+            }
+            return returnVal;
+        } finally {
+            // return any substituted buffers to cache
+            for (int i=0; i<numBufs; i++) {
+                ByteBuffer bb = shadow[i];
+                if (bb != null && bb != bufs[i]) {
+                    Util.releaseTemporaryDirectBuffer(bb);
+                }
             }
         }
-
-        IOVecWrapper vec = null;
-        long bytesWritten = 0;
-        try {
-            // Create a native iovec array
-            vec= new IOVecWrapper(numBufs);
-
-            // Fill in the iovec array with appropriate data
-            for (int i=0; i<numBufs; i++) {
-                ByteBuffer nextBuffer = shadow[i];
-                // put in the buffer addresses
-                long pos = nextBuffer.position();
-                long len = nextBuffer.limit() - pos;
-                bytesReadyToWrite += len;
-                vec.putBase(i, ((DirectBuffer)nextBuffer).address() + pos);
-                vec.putLen(i, len);
-            }
-
-            // Invoke native call to fill the buffers
-            bytesWritten = nd.writev(fd, vec.address, numBufs);
-        } finally {
-            vec.free();
-        }
-        long returnVal = bytesWritten;
-
-        // Notify the buffers how many bytes were taken
-        for (int i=0; i<numBufs; i++) {
-            ByteBuffer nextBuffer = bufs[i];
-            int pos = nextBuffer.position();
-            int lim = nextBuffer.limit();
-            assert (pos <= lim);
-            int len = (pos <= lim ? lim - pos : lim);
-            if (bytesWritten >= len) {
-                bytesWritten -= len;
-                int newPosition = pos + len;
-                nextBuffer.position(newPosition);
-            } else { // Buffers not completely filled
-                if (bytesWritten > 0) {
-                    assert(pos + bytesWritten < (long)Integer.MAX_VALUE);
-                    int newPosition = (int)(pos + bytesWritten);
-                    nextBuffer.position(newPosition);
-                }
-                break;
-            }
-        }
-        return returnVal;
     }
 
     static int read(FileDescriptor fd, ByteBuffer dst, long position,
@@ -270,68 +274,83 @@
 
         // Read into the shadow to ensure DirectByteBuffers are used
         ByteBuffer[] shadow = new ByteBuffer[numBufs];
-        for (int i=0; i<numBufs; i++) {
-            if (bufs[i].isReadOnly())
-                throw new IllegalArgumentException("Read-only buffer");
-            if (!(bufs[i] instanceof DirectBuffer)) {
-                shadow[i] = ByteBuffer.allocateDirect(bufs[i].remaining());
-            } else {
-                shadow[i] = bufs[i];
-            }
-        }
-
-        IOVecWrapper vec = null;
-        long bytesRead = 0;
+        boolean usingSlowBuffers = false;
         try {
-            // Create a native iovec array
-            vec = new IOVecWrapper(numBufs);
-
-            // Fill in the iovec array with appropriate data
             for (int i=0; i<numBufs; i++) {
-                ByteBuffer nextBuffer = shadow[i];
-                // put in the buffer addresses
-                long pos = nextBuffer.position();
-                long len = nextBuffer.remaining();
-                vec.putBase(i, ((DirectBuffer)nextBuffer).address() + pos);
-                vec.putLen(i, len);
+                if (bufs[i].isReadOnly())
+                    throw new IllegalArgumentException("Read-only buffer");
+                if (!(bufs[i] instanceof DirectBuffer)) {
+                    shadow[i] = Util.getTemporaryDirectBuffer(bufs[i].remaining());
+                    usingSlowBuffers = true;
+                } else {
+                    shadow[i] = bufs[i];
+                }
             }
 
-            // Invoke native call to fill the buffers
-            bytesRead = nd.readv(fd, vec.address, numBufs);
-        } finally {
-            vec.free();
-        }
-        long returnVal = bytesRead;
+            IOVecWrapper vec = null;
+            long bytesRead = 0;
+            try {
+                // Create a native iovec array
+                vec = new IOVecWrapper(numBufs);
+
+                // Fill in the iovec array with appropriate data
+                for (int i=0; i<numBufs; i++) {
+                    ByteBuffer nextBuffer = shadow[i];
+                    // put in the buffer addresses
+                    long pos = nextBuffer.position();
+                    long len = nextBuffer.remaining();
+                    vec.putBase(i, ((DirectBuffer)nextBuffer).address() + pos);
+                    vec.putLen(i, len);
+                }
+
+                // Invoke native call to fill the buffers
+                bytesRead = nd.readv(fd, vec.address, numBufs);
+            } finally {
+                vec.free();
+            }
+            long returnVal = bytesRead;
 
-        // Notify the buffers how many bytes were read
-        for (int i=0; i<numBufs; i++) {
-            ByteBuffer nextBuffer = shadow[i];
-            // Note: should this have been cached from above?
-            int pos = nextBuffer.position();
-            int len = nextBuffer.remaining();
-            if (bytesRead >= len) {
-                bytesRead -= len;
-                int newPosition = pos + len;
-                nextBuffer.position(newPosition);
-            } else { // Buffers not completely filled
-                if (bytesRead > 0) {
-                    assert(pos + bytesRead < (long)Integer.MAX_VALUE);
-                    int newPosition = (int)(pos + bytesRead);
+            // Notify the buffers how many bytes were read
+            for (int i=0; i<numBufs; i++) {
+                ByteBuffer nextBuffer = shadow[i];
+                // Note: should this have been cached from above?
+                int pos = nextBuffer.position();
+                int len = nextBuffer.remaining();
+                if (bytesRead >= len) {
+                    bytesRead -= len;
+                    int newPosition = pos + len;
                     nextBuffer.position(newPosition);
+                } else { // Buffers not completely filled
+                    if (bytesRead > 0) {
+                        assert(pos + bytesRead < (long)Integer.MAX_VALUE);
+                        int newPosition = (int)(pos + bytesRead);
+                        nextBuffer.position(newPosition);
+                    }
+                    break;
                 }
-                break;
+            }
+
+            // Put results from shadow into the slow buffers
+            if (usingSlowBuffers) {
+                for (int i=0; i<numBufs; i++) {
+                    if (!(bufs[i] instanceof DirectBuffer)) {
+                        shadow[i].flip();
+                        bufs[i].put(shadow[i]);
+                    }
+                }
+            }
+            return returnVal;
+        } finally {
+            // return any substituted buffers to cache
+            if (usingSlowBuffers) {
+                for (int i=0; i<numBufs; i++) {
+                    ByteBuffer bb = shadow[i];
+                    if (bb != null && bb != bufs[i]) {
+                        Util.releaseTemporaryDirectBuffer(bb);
+                    }
+                }
             }
         }
-
-        // Put results from shadow into the slow buffers
-        for (int i=0; i<numBufs; i++) {
-            if (!(bufs[i] instanceof DirectBuffer)) {
-                shadow[i].flip();
-                bufs[i].put(shadow[i]);
-            }
-        }
-
-        return returnVal;
     }
 
     static FileDescriptor newFD(int i) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/Invoker.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.util.concurrent.*;
+import java.security.AccessController;
+import sun.security.action.GetIntegerAction;
+
+/**
+ * Defines static methods to invoke a completion handler or arbitrary task.
+ */
+
+class Invoker {
+    private Invoker() { }
+
+    // maximum number of completion handlers that may be invoked on the current
+    // thread before it re-directs invocations to the thread pool. This helps
+    // avoid stack overflow and lessens the risk of starvation.
+    private static final int maxHandlerInvokeCount = AccessController.doPrivileged(
+        new GetIntegerAction("sun.nio.ch.maxCompletionHandlersOnStack", 16));
+
+    // Per-thread object with reference to channel group and a counter for
+    // the number of completion handlers invoked. This should be reset to 0
+    // when all completion handlers have completed.
+    static class GroupAndInvokeCount {
+        private final AsynchronousChannelGroupImpl group;
+        private int handlerInvokeCount;
+        GroupAndInvokeCount(AsynchronousChannelGroupImpl group) {
+            this.group = group;
+        }
+        AsynchronousChannelGroupImpl group() {
+            return group;
+        }
+        int invokeCount() {
+            return handlerInvokeCount;
+        }
+        void setInvokeCount(int value) {
+            handlerInvokeCount = value;
+        }
+        void resetInvokeCount() {
+            handlerInvokeCount = 0;
+        }
+        void incrementInvokeCount() {
+            handlerInvokeCount++;
+        }
+    }
+    private static final ThreadLocal<GroupAndInvokeCount> myGroupAndInvokeCount =
+        new ThreadLocal<GroupAndInvokeCount>() {
+            @Override protected GroupAndInvokeCount initialValue() {
+                return null;
+            }
+        };
+
+    /**
+     * Binds this thread to the given group
+     */
+    static void bindToGroup(AsynchronousChannelGroupImpl group) {
+        myGroupAndInvokeCount.set(new GroupAndInvokeCount(group));
+    }
+
+    /**
+     * Returns the GroupAndInvokeCount object for this thread.
+     */
+    static GroupAndInvokeCount getGroupAndInvokeCount() {
+        return myGroupAndInvokeCount.get();
+    }
+
+    /**
+     * Returns true if the current thread is in a channel group's thread pool
+     */
+    static boolean isBoundToAnyGroup() {
+        return myGroupAndInvokeCount.get() != null;
+    }
+
+    /**
+     * Returns true if the current thread is in the given channel's thread
+     * pool and we haven't exceeded the maximum number of handler frames on
+     * the stack.
+     */
+    static boolean mayInvokeDirect(GroupAndInvokeCount myGroupAndInvokeCount,
+                                   AsynchronousChannelGroupImpl group)
+    {
+        if ((myGroupAndInvokeCount != null) &&
+            (myGroupAndInvokeCount.group() == group) &&
+            (myGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount))
+        {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Invoke handler without checking the thread identity or number of handlers
+     * on the thread stack.
+     */
+    @SuppressWarnings("unchecked")
+    static <V,A> void invokeUnchecked(CompletionHandler<V,? super A> handler,
+                                      AbstractFuture<V,A> result)
+    {
+        if (handler != null && !result.isCancelled()) {
+            Throwable exc = result.exception();
+            if (exc == null) {
+                handler.completed(result.value(), result.attachment());
+            } else {
+                handler.failed(exc, result.attachment());
+            }
+
+            // clear interrupt
+            Thread.interrupted();
+        }
+    }
+
+
+    /**
+     * Invoke handler after incrementing the invoke count.
+     */
+    static <V,A> void invokeDirect(GroupAndInvokeCount myGroupAndInvokeCount,
+                                   CompletionHandler<V,? super A> handler,
+                                   AbstractFuture<V,A> result)
+    {
+        myGroupAndInvokeCount.incrementInvokeCount();
+        invokeUnchecked(handler, result);
+    }
+
+    /**
+     * Invokes the handler. If the current thread is in the channel group's
+     * thread pool then the handler is invoked directly, otherwise it is
+     * invoked indirectly.
+     */
+    static <V,A> void invoke(CompletionHandler<V,? super A> handler,
+                             AbstractFuture<V,A> result)
+    {
+        if (handler != null) {
+            boolean invokeDirect = false;
+            boolean identityOkay = false;
+            GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();
+            if (thisGroupAndInvokeCount != null) {
+                AsynchronousChannel channel = result.channel();
+                if ((thisGroupAndInvokeCount.group() == ((Groupable)channel).group()))
+                    identityOkay = true;
+                if (identityOkay &&
+                    (thisGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount))
+                {
+                    // group match
+                    invokeDirect = true;
+                }
+            }
+            if (invokeDirect) {
+                thisGroupAndInvokeCount.incrementInvokeCount();
+                invokeUnchecked(handler, result);
+            } else {
+                try {
+                    invokeIndirectly(handler, result);
+                } catch (RejectedExecutionException ree) {
+                    // channel group shutdown; fallback to invoking directly
+                    // if the current thread has the right identity.
+                    if (identityOkay) {
+                        invokeUnchecked(handler, result);
+                    } else {
+                        throw new ShutdownChannelGroupException();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Invokes the handler "indirectly" in the channel group's thread pool.
+     */
+    static <V,A> void invokeIndirectly(final CompletionHandler<V,? super A> handler,
+                                       final AbstractFuture<V,A> result)
+    {
+        if (handler != null) {
+            AsynchronousChannel channel = result.channel();
+            try {
+                ((Groupable)channel).group().executeOnPooledThread(new Runnable() {
+                    public void run() {
+                        GroupAndInvokeCount thisGroupAndInvokeCount =
+                            myGroupAndInvokeCount.get();
+                        if (thisGroupAndInvokeCount != null)
+                            thisGroupAndInvokeCount.setInvokeCount(1);
+                        invokeUnchecked(handler, result);
+                    }
+                });
+            } catch (RejectedExecutionException ree) {
+                throw new ShutdownChannelGroupException();
+            }
+        }
+    }
+
+    /**
+     * Invokes the handler "indirectly" in the given Executor
+     */
+    static <V,A> void invokeIndirectly(final CompletionHandler<V,? super A> handler,
+                                       final AbstractFuture<V,A> result,
+                                       Executor executor)
+    {
+        if (handler != null) {
+            try {
+                executor.execute(new Runnable() {
+                    public void run() {
+                        invokeUnchecked(handler, result);
+                    }
+                });
+            } catch (RejectedExecutionException ree) {
+                throw new ShutdownChannelGroupException();
+            }
+        }
+    }
+
+    /**
+     * Invokes the given task on the thread pool associated with the given
+     * channel. If the current thread is in the thread pool then the task is
+     * invoked directly.
+     */
+    static void invokeOnThreadInThreadPool(Groupable channel,
+                                           Runnable task)
+    {
+        boolean invokeDirect;
+        GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();
+        AsynchronousChannelGroupImpl targetGroup = channel.group();
+        if (thisGroupAndInvokeCount == null) {
+            invokeDirect = false;
+        } else {
+            invokeDirect = (thisGroupAndInvokeCount.group == targetGroup);
+        }
+        try {
+            if (invokeDirect) {
+                task.run();
+            } else {
+                targetGroup.executeOnPooledThread(task);
+            }
+        } catch (RejectedExecutionException ree) {
+            throw new ShutdownChannelGroupException();
+        }
+    }
+}
--- a/jdk/src/share/classes/sun/nio/ch/MembershipKeyImpl.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/MembershipKeyImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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
@@ -85,7 +85,7 @@
             this.sourceAddress = sourceAddress;
         }
 
-        int group() {
+        int groupAddress() {
             return groupAddress;
         }
 
@@ -120,7 +120,7 @@
             this.sourceAddress = sourceAddress;
         }
 
-        byte[] group() {
+        byte[] groupAddress() {
             return groupAddress;
         }
 
@@ -142,28 +142,28 @@
         valid = false;
     }
 
-    public void drop() throws IOException {
+    public void drop() {
         // delegate to channel
         ((DatagramChannelImpl)ch).drop(this);
     }
 
     @Override
-    public MulticastChannel getChannel() {
+    public MulticastChannel channel() {
         return ch;
     }
 
     @Override
-    public InetAddress getGroup() {
+    public InetAddress group() {
         return group;
     }
 
     @Override
-    public NetworkInterface getNetworkInterface() {
+    public NetworkInterface networkInterface() {
         return interf;
     }
 
     @Override
-    public InetAddress getSourceAddress() {
+    public InetAddress sourceAddress() {
         return source;
     }
 
@@ -191,9 +191,7 @@
     }
 
     @Override
-    public MembershipKey unblock(InetAddress toUnblock)
-        throws IOException
-    {
+    public MembershipKey unblock(InetAddress toUnblock) {
         synchronized (stateLock) {
             if ((blockedSet == null) || !blockedSet.contains(toUnblock))
                 throw new IllegalStateException("not blocked");
--- a/jdk/src/share/classes/sun/nio/ch/MembershipRegistry.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/MembershipRegistry.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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
@@ -55,20 +55,20 @@
             List<MembershipKeyImpl> keys = groups.get(group);
             if (keys != null) {
                 for (MembershipKeyImpl key: keys) {
-                    if (key.getNetworkInterface().equals(interf)) {
+                    if (key.networkInterface().equals(interf)) {
                         // already a member to receive all packets so return
                         // existing key or detect conflict
                         if (source == null) {
-                            if (key.getSourceAddress() == null)
+                            if (key.sourceAddress() == null)
                                 return key;
                             throw new IllegalStateException("Already a member to receive all packets");
                         }
 
                         // already have source-specific membership so return key
                         // or detect conflict
-                        if (key.getSourceAddress() == null)
+                        if (key.sourceAddress() == null)
                             throw new IllegalStateException("Already have source-specific membership");
-                        if (source.equals(key.getSourceAddress()))
+                        if (source.equals(key.sourceAddress()))
                             return key;
                     }
                 }
@@ -81,7 +81,7 @@
      * Add membership to the registry, returning a new membership key.
      */
     void add(MembershipKeyImpl key) {
-        InetAddress group = key.getGroup();
+        InetAddress group = key.group();
         List<MembershipKeyImpl> keys;
         if (groups == null) {
             groups = new HashMap<InetAddress,List<MembershipKeyImpl>>();
@@ -100,7 +100,7 @@
      * Remove a key from the registry
      */
     void remove(MembershipKeyImpl key) {
-        InetAddress group = key.getGroup();
+        InetAddress group = key.group();
         List<MembershipKeyImpl> keys = groups.get(group);
         if (keys != null) {
             Iterator<MembershipKeyImpl> i = keys.iterator();
@@ -120,9 +120,11 @@
      * Invalidate all keys in the registry
      */
     void invalidateAll() {
-        for (InetAddress group: groups.keySet()) {
-            for (MembershipKeyImpl key: groups.get(group)) {
-                key.invalidate();
+        if (groups != null) {
+            for (InetAddress group: groups.keySet()) {
+                for (MembershipKeyImpl key: groups.get(group)) {
+                    key.invalidate();
+                }
             }
         }
     }
--- a/jdk/src/share/classes/sun/nio/ch/NativeThreadSet.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/NativeThreadSet.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2002-2009 Sun Microsystems, Inc.  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
@@ -33,6 +33,7 @@
 
     private long[] elts;
     private int used = 0;
+    private boolean waitingToEmpty;
 
     NativeThreadSet(int n) {
         elts = new long[n];
@@ -75,12 +76,14 @@
         synchronized (this) {
             elts[i] = 0;
             used--;
+            if (used == 0 && waitingToEmpty)
+                notifyAll();
         }
     }
 
     // Signals all threads in this set.
     //
-    void signal() {
+    void signalAndWait() {
         synchronized (this) {
             int u = used;
             int n = elts.length;
@@ -92,7 +95,12 @@
                 if (--u == 0)
                     break;
             }
+            waitingToEmpty = true;
+            while (used > 0) {
+                try {
+                    wait();
+                } catch (InterruptedException ignore) { }
+            }
         }
     }
-
 }
--- a/jdk/src/share/classes/sun/nio/ch/Net.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/Net.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -207,7 +207,7 @@
     // -- Socket options
 
     static void setSocketOption(FileDescriptor fd, ProtocolFamily family,
-                                SocketOption name, Object value)
+                                SocketOption<?> name, Object value)
         throws IOException
     {
         if (value == null)
@@ -262,7 +262,7 @@
     }
 
     static Object getSocketOption(FileDescriptor fd, ProtocolFamily family,
-                                  SocketOption name)
+                                  SocketOption<?> name)
         throws IOException
     {
         Class<?> type = name.type();
--- a/jdk/src/share/classes/sun/nio/ch/OptionKey.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/OptionKey.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/PendingFuture.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.util.concurrent.*;
+import java.io.IOException;
+
+/**
+ * A Future for a pending I/O operation. A PendingFuture allows for the
+ * attachment of an additional arbitrary context object and a timer task.
+ */
+
+final class PendingFuture<V,A>
+    extends AbstractFuture<V,A>
+{
+    private static final CancellationException CANCELLED =
+        new CancellationException();
+
+    private final CompletionHandler<V,? super A> handler;
+
+    // true if result (or exception) is available
+    private volatile boolean haveResult;
+    private volatile V result;
+    private volatile Throwable exc;
+
+    // latch for waiting (created lazily if needed)
+    private CountDownLatch latch;
+
+    // optional timer task that is cancelled when result becomes available
+    private Future<?> timeoutTask;
+
+    // optional context object
+    private volatile Object context;
+
+
+    PendingFuture(AsynchronousChannel channel,
+                  CompletionHandler<V,? super A> handler,
+                  A attachment,
+                  Object context)
+    {
+        super(channel, attachment);
+        this.handler = handler;
+        this.context = context;
+    }
+
+    PendingFuture(AsynchronousChannel channel,
+                  CompletionHandler<V,? super A> handler,
+                  A attachment)
+    {
+        super(channel, attachment);
+        this.handler = handler;
+    }
+
+    CompletionHandler<V,? super A> handler() {
+        return handler;
+    }
+
+    void setContext(Object context) {
+        this.context = context;
+    }
+
+    Object getContext() {
+        return context;
+    }
+
+    void setTimeoutTask(Future<?> task) {
+        synchronized (this) {
+            if (haveResult) {
+                task.cancel(false);
+            } else {
+                this.timeoutTask = task;
+            }
+        }
+    }
+
+    // creates latch if required; return true if caller needs to wait
+    private boolean prepareForWait() {
+        synchronized (this) {
+            if (haveResult) {
+                return false;
+            } else {
+                if (latch == null)
+                    latch = new CountDownLatch(1);
+                return true;
+            }
+        }
+    }
+
+    /**
+     * Sets the result, or a no-op if the result or exception is already set.
+     */
+    boolean setResult(V res) {
+        synchronized (this) {
+            if (haveResult)
+                return false;
+            result = res;
+            haveResult = true;
+            if (timeoutTask != null)
+                timeoutTask.cancel(false);
+            if (latch != null)
+                latch.countDown();
+            return true;
+        }
+    }
+
+    /**
+     * Sets the result, or a no-op if the result or exception is already set.
+     */
+    boolean setFailure(Throwable x) {
+        if (!(x instanceof IOException) && !(x instanceof SecurityException))
+            x = new IOException(x);
+        synchronized (this) {
+            if (haveResult)
+                return false;
+            exc = x;
+            haveResult = true;
+            if (timeoutTask != null)
+                timeoutTask.cancel(false);
+            if (latch != null)
+                latch.countDown();
+            return true;
+        }
+    }
+
+    @Override
+    public V get() throws ExecutionException, InterruptedException {
+        if (!haveResult) {
+            boolean needToWait = prepareForWait();
+            if (needToWait)
+                latch.await();
+        }
+        if (exc != null) {
+            if (exc == CANCELLED)
+                throw new CancellationException();
+            throw new ExecutionException(exc);
+        }
+        return result;
+    }
+
+    @Override
+    public V get(long timeout, TimeUnit unit)
+        throws ExecutionException, InterruptedException, TimeoutException
+    {
+        if (!haveResult) {
+            boolean needToWait = prepareForWait();
+            if (needToWait)
+                if (!latch.await(timeout, unit)) throw new TimeoutException();
+        }
+        if (exc != null) {
+            if (exc == CANCELLED)
+                throw new CancellationException();
+            throw new ExecutionException(exc);
+        }
+        return result;
+    }
+
+    @Override
+    Throwable exception() {
+        return (exc != CANCELLED) ? exc : null;
+    }
+
+    @Override
+    V value() {
+        return result;
+    }
+
+    @Override
+    public boolean isCancelled() {
+        return (exc == CANCELLED);
+    }
+
+    @Override
+    public boolean isDone() {
+        return haveResult;
+    }
+
+    @Override
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        synchronized (this) {
+            if (haveResult)
+                return false;    // already completed
+
+            // A shutdown of the channel group will close all channels and
+            // shutdown the executor. To ensure that the completion handler
+            // is executed we queue the task while holding the lock.
+            if (handler != null) {
+                prepareForWait();
+                Runnable cancelTask = new Runnable() {
+                    public void run() {
+                        while (!haveResult) {
+                            try {
+                                latch.await();
+                            } catch (InterruptedException ignore) { }
+                        }
+                        handler.cancelled(attachment());
+                    }
+                };
+                AsynchronousChannel ch = channel();
+                if (ch instanceof Groupable) {
+                    ((Groupable)ch).group().executeOnPooledThread(cancelTask);
+                } else {
+                    if (ch instanceof AsynchronousFileChannelImpl) {
+                        ((AsynchronousFileChannelImpl)ch).executor().execute(cancelTask);
+                    } else {
+                        throw new AssertionError("Should not get here");
+                    }
+                }
+            }
+
+            // notify channel
+            if (channel() instanceof Cancellable)
+                ((Cancellable)channel()).onCancel(this);
+
+            // set result and cancel timer
+            exc = CANCELLED;
+            haveResult = true;
+            if (timeoutTask != null)
+                timeoutTask.cancel(false);
+        }
+
+        // close channel if forceful cancel
+        if (mayInterruptIfRunning) {
+            try {
+                channel().close();
+            } catch (IOException ignore) { }
+        }
+
+        // release waiters (this also releases the invoker)
+        if (latch != null)
+            latch.countDown();
+        return true;
+    }
+}
--- a/jdk/src/share/classes/sun/nio/ch/Reflect.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/Reflect.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -55,7 +55,7 @@
     {
         try {
             Class<?> cl = Class.forName(className);
-            Constructor c = cl.getDeclaredConstructor(paramTypes);
+            Constructor<?> c = cl.getDeclaredConstructor(paramTypes);
             setAccessible(c);
             return c;
         } catch (ClassNotFoundException x) {
@@ -79,7 +79,7 @@
 
     static Method lookupMethod(String className,
                                String methodName,
-                               Class[] paramTypes)
+                               Class... paramTypes)
     {
         try {
             Class<?> cl = Class.forName(className);
--- a/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -27,12 +27,9 @@
 
 import java.io.FileDescriptor;
 import java.io.IOException;
-import java.lang.reflect.*;
 import java.net.*;
 import java.nio.channels.*;
 import java.nio.channels.spi.*;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import java.util.*;
 
 
@@ -111,19 +108,19 @@
     public SocketAddress getLocalAddress() throws IOException {
         synchronized (stateLock) {
             if (!isOpen())
-                return null;
+                throw new ClosedChannelException();
             return localAddress;
         }
     }
 
     @Override
-    public ServerSocketChannel setOption(SocketOption name, Object value)
+    public <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
         throws IOException
     {
         if (name == null)
             throw new NullPointerException();
-        if (!options().contains(name))
-            throw new IllegalArgumentException("invalid option name");
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
 
         synchronized (stateLock) {
             if (!isOpen())
@@ -142,8 +139,8 @@
     {
         if (name == null)
             throw new NullPointerException();
-        if (!options().contains(name))
-            throw new IllegalArgumentException("invalid option name");
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
 
         synchronized (stateLock) {
             if (!isOpen())
@@ -154,7 +151,7 @@
         }
     }
 
-    private static class LazyInitialization {
+    private static class DefaultOptionsHolder {
         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
 
         private static Set<SocketOption<?>> defaultOptions() {
@@ -166,8 +163,8 @@
     }
 
     @Override
-    public final Set<SocketOption<?>> options() {
-        return LazyInitialization.defaultOptions;
+    public final Set<SocketOption<?>> supportedOptions() {
+        return DefaultOptionsHolder.defaultOptions;
     }
 
     public boolean isBound() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,612 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.net.*;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.*;
+import java.security.AccessController;
+import java.security.AccessControlContext;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
+
+/**
+ * A prototype implementation of AsynchronousDatagramChannel, used to aid
+ * test and spec development.
+ */
+
+class SimpleAsynchronousDatagramChannelImpl
+    extends AsynchronousDatagramChannel implements Groupable, Cancellable
+{
+    private final DatagramChannel dc;
+    private final AsynchronousChannelGroupImpl group;
+    private final Object attachKey;
+    private boolean closed;
+
+    // used to coordinate timed and blocking reads
+    private final Object readLock = new Object();
+
+    // channel blocking mode (requires readLock)
+    private boolean isBlocking = true;
+
+    // number of blocking readers (requires readLock)
+    private int blockingReaderCount;
+
+    // true if timed read attempted while blocking read in progress (requires readLock)
+    private boolean transitionToNonBlocking;
+
+    // true if a blocking read is cancelled (requires readLock)
+    private boolean blockingReadKilledByCancel;
+
+    // temporary Selectors used by timed reads (requires readLock)
+    private Selector firstReader;
+    private Set<Selector> otherReaders;
+
+    SimpleAsynchronousDatagramChannelImpl(ProtocolFamily family,
+                                          AsynchronousChannelGroupImpl group)
+        throws IOException
+    {
+        super(group.provider());
+        this.dc = (family == null) ?
+            DatagramChannel.open() : DatagramChannel.open(family);
+        this.group = group;
+
+        // attach this channel to the group as foreign channel
+        boolean registered = false;
+        try {
+            if (!(dc instanceof DatagramChannelImpl))
+                throw new UnsupportedOperationException();
+            attachKey = group
+                .attachForeignChannel(this, ((DatagramChannelImpl)dc).getFD());
+            registered = true;
+        } finally {
+            if (!registered)
+                dc.close();
+        }
+    }
+
+    // throws RuntimeException if blocking read has been cancelled
+    private void ensureBlockingReadNotKilled() {
+        assert Thread.holdsLock(readLock);
+        if (blockingReadKilledByCancel)
+            throw new RuntimeException("Reading not allowed due to cancellation");
+    }
+
+    // invoke prior to non-timed read/receive
+    private void beginNoTimeoutRead() {
+        synchronized (readLock) {
+            ensureBlockingReadNotKilled();
+            if (isBlocking)
+                blockingReaderCount++;
+        }
+    }
+
+    // invoke after non-timed read/receive has completed
+    private void endNoTimeoutRead() {
+        synchronized (readLock) {
+            if (isBlocking) {
+                if (--blockingReaderCount == 0 && transitionToNonBlocking) {
+                    // notify any threads waiting to make channel non-blocking
+                    readLock.notifyAll();
+                }
+            }
+        }
+    }
+
+    // invoke prior to timed read
+    // returns the timeout remaining
+    private long prepareForTimedRead(PendingFuture<?,?> result, long timeout)
+        throws IOException
+    {
+        synchronized (readLock) {
+            ensureBlockingReadNotKilled();
+            if (isBlocking) {
+                transitionToNonBlocking = true;
+                while (blockingReaderCount > 0 &&
+                       timeout > 0L &&
+                       !result.isCancelled())
+                {
+                    long st = System.currentTimeMillis();
+                    try {
+                        readLock.wait(timeout);
+                    } catch (InterruptedException e) { }
+                    timeout -= System.currentTimeMillis() - st;
+                }
+                if (blockingReaderCount == 0) {
+                    // re-check that blocked read wasn't cancelled
+                    ensureBlockingReadNotKilled();
+                    // no blocking reads so change channel to non-blocking
+                    dc.configureBlocking(false);
+                    isBlocking = false;
+                }
+            }
+            return timeout;
+        }
+    }
+
+    // returns a temporary Selector
+    private Selector getSelector() throws IOException {
+        Selector sel = Util.getTemporarySelector(dc);
+        synchronized (readLock) {
+            if (firstReader == null) {
+                firstReader = sel;
+            } else {
+                if (otherReaders == null)
+                    otherReaders = new HashSet<Selector>();
+                otherReaders.add(sel);
+            }
+        }
+        return sel;
+    }
+
+    // releases a temporary Selector
+    private void releaseSelector(Selector sel) throws IOException {
+        synchronized (readLock) {
+            if (firstReader == sel) {
+                firstReader = null;
+            } else {
+                otherReaders.remove(sel);
+            }
+        }
+        Util.releaseTemporarySelector(sel);
+    }
+
+    // wakeup all Selectors currently in use
+    private void wakeupSelectors() {
+        synchronized (readLock) {
+            if (firstReader != null)
+                firstReader.wakeup();
+            if (otherReaders != null) {
+                for (Selector sel: otherReaders) {
+                    sel.wakeup();
+                }
+            }
+        }
+    }
+
+    @Override
+    public AsynchronousChannelGroupImpl group() {
+        return group;
+    }
+
+    @Override
+    public boolean isOpen() {
+        return dc.isOpen();
+    }
+
+    @Override
+    public void onCancel(PendingFuture<?,?> task) {
+        synchronized (readLock) {
+            if (blockingReaderCount > 0) {
+                blockingReadKilledByCancel = true;
+                readLock.notifyAll();
+                return;
+            }
+        }
+        wakeupSelectors();
+    }
+
+    @Override
+    public void close() throws IOException {
+        synchronized (dc) {
+            if (closed)
+                return;
+            closed = true;
+        }
+        // detach from group and close underlying channel
+        group.detachForeignChannel(attachKey);
+        dc.close();
+
+        // wakeup any threads blocked in timed read/receives
+        wakeupSelectors();
+    }
+
+    @Override
+    public AsynchronousDatagramChannel connect(SocketAddress remote)
+        throws IOException
+    {
+        dc.connect(remote);
+        return this;
+    }
+
+    @Override
+    public AsynchronousDatagramChannel disconnect() throws IOException {
+        dc.disconnect();
+        return this;
+    }
+
+    private static class WrappedMembershipKey extends MembershipKey {
+        private final MulticastChannel channel;
+        private final MembershipKey key;
+
+        WrappedMembershipKey(MulticastChannel channel, MembershipKey key) {
+            this.channel = channel;
+            this.key = key;
+        }
+
+        @Override
+        public boolean isValid() {
+            return key.isValid();
+        }
+
+        @Override
+        public void drop() {
+            key.drop();
+        }
+
+        @Override
+        public MulticastChannel channel() {
+            return channel;
+        }
+
+        @Override
+        public InetAddress group() {
+            return key.group();
+        }
+
+        @Override
+        public NetworkInterface networkInterface() {
+            return key.networkInterface();
+        }
+
+        @Override
+        public InetAddress sourceAddress() {
+            return key.sourceAddress();
+        }
+
+        @Override
+        public MembershipKey block(InetAddress toBlock) throws IOException {
+            key.block(toBlock);
+            return this;
+        }
+
+        @Override
+        public MembershipKey unblock(InetAddress toUnblock) {
+            key.unblock(toUnblock);
+            return this;
+        }
+
+        @Override
+        public String toString() {
+            return key.toString();
+        }
+    }
+
+    @Override
+    public MembershipKey join(InetAddress group,
+                              NetworkInterface interf)
+        throws IOException
+    {
+        MembershipKey key = ((MulticastChannel)dc).join(group, interf);
+        return new WrappedMembershipKey(this, key);
+    }
+
+    @Override
+    public MembershipKey join(InetAddress group,
+                              NetworkInterface interf,
+                              InetAddress source)
+        throws IOException
+    {
+        MembershipKey key = ((MulticastChannel)dc).join(group, interf, source);
+        return new WrappedMembershipKey(this, key);
+    }
+
+    @Override
+    public <A> Future<Integer> send(ByteBuffer src,
+                                    SocketAddress target,
+                                    long timeout,
+                                    TimeUnit unit,
+                                    A attachment,
+                                    CompletionHandler<Integer,? super A> handler)
+    {
+        if (timeout < 0L)
+            throw new IllegalArgumentException("Negative timeout");
+        if (unit == null)
+            throw new NullPointerException();
+
+        CompletedFuture<Integer,A> result;
+        try {
+            int n = dc.send(src, target);
+            result = CompletedFuture.withResult(this, n, attachment);
+        } catch (IOException ioe) {
+            result = CompletedFuture.withFailure(this, ioe, attachment);
+        }
+        Invoker.invoke(handler, result);
+        return result;
+    }
+
+    @Override
+    public <A> Future<Integer> write(ByteBuffer src,
+                                     long timeout,
+                                     TimeUnit unit,
+                                     A attachment,
+                                     CompletionHandler<Integer,? super A> handler)
+    {
+        if (timeout < 0L)
+            throw new IllegalArgumentException("Negative timeout");
+        if (unit == null)
+            throw new NullPointerException();
+
+        CompletedFuture<Integer,A> result;
+        try {
+            int n = dc.write(src);
+            result = CompletedFuture.withResult(this, n, attachment);
+        } catch (IOException ioe) {
+            result = CompletedFuture.withFailure(this, ioe, attachment);
+        }
+        Invoker.invoke(handler, result);
+        return result;
+    }
+
+    /**
+     * Receive into the given buffer with privileges enabled and restricted by
+     * the given AccessControlContext (can be null).
+     */
+    private SocketAddress doRestrictedReceive(final ByteBuffer dst,
+                                              AccessControlContext acc)
+        throws IOException
+    {
+        if (acc == null) {
+            return dc.receive(dst);
+        } else {
+            try {
+                return AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<SocketAddress>() {
+                        public SocketAddress run() throws IOException {
+                            return dc.receive(dst);
+                        }}, acc);
+            } catch (PrivilegedActionException pae) {
+                Exception cause = pae.getException();
+                if (cause instanceof SecurityException)
+                    throw (SecurityException)cause;
+                throw (IOException)cause;
+            }
+        }
+    }
+
+    @Override
+    public <A> Future<SocketAddress> receive(final ByteBuffer dst,
+                                             final long timeout,
+                                             final TimeUnit unit,
+                                             A attachment,
+                                             final CompletionHandler<SocketAddress,? super A> handler)
+    {
+        if (dst.isReadOnly())
+            throw new IllegalArgumentException("Read-only buffer");
+        if (timeout < 0L)
+            throw new IllegalArgumentException("Negative timeout");
+        if (unit == null)
+            throw new NullPointerException();
+
+        // complete immediately if channel closed
+        if (!isOpen()) {
+            CompletedFuture<SocketAddress,A> result = CompletedFuture.withFailure(this,
+                new ClosedChannelException(), attachment);
+            Invoker.invoke(handler, result);
+            return result;
+        }
+
+        final AccessControlContext acc = (System.getSecurityManager() == null) ?
+            null : AccessController.getContext();
+        final PendingFuture<SocketAddress,A> result =
+            new PendingFuture<SocketAddress,A>(this, handler, attachment);
+        Runnable task = new Runnable() {
+            public void run() {
+                try {
+                    SocketAddress remote = null;
+                    long to;
+                    if (timeout == 0L) {
+                        beginNoTimeoutRead();
+                        try {
+                            remote = doRestrictedReceive(dst, acc);
+                        } finally {
+                            endNoTimeoutRead();
+                        }
+                        to = 0L;
+                    } else {
+                        to = prepareForTimedRead(result, unit.toMillis(timeout));
+                        if (to <= 0L)
+                            throw new InterruptedByTimeoutException();
+                        remote = doRestrictedReceive(dst, acc);
+                    }
+                    if (remote == null) {
+                        Selector sel = getSelector();
+                        SelectionKey sk = null;
+                        try {
+                            sk = dc.register(sel, SelectionKey.OP_READ);
+                            for (;;) {
+                                if (!dc.isOpen())
+                                    throw new AsynchronousCloseException();
+                                if (result.isCancelled())
+                                    break;
+                                long st = System.currentTimeMillis();
+                                int ns = sel.select(to);
+                                if (ns > 0) {
+                                    remote = doRestrictedReceive(dst, acc);
+                                    if (remote != null)
+                                        break;
+                                }
+                                sel.selectedKeys().remove(sk);
+                                if (timeout != 0L) {
+                                    to -= System.currentTimeMillis() - st;
+                                    if (to <= 0)
+                                        throw new InterruptedByTimeoutException();
+                                }
+                            }
+                        } finally {
+                            if (sk != null)
+                                sk.cancel();
+                            releaseSelector(sel);
+                        }
+                    }
+                    result.setResult(remote);
+                } catch (Throwable x) {
+                    if (x instanceof ClosedChannelException)
+                        x = new AsynchronousCloseException();
+                    result.setFailure(x);
+                }
+                Invoker.invokeUnchecked(handler, result);
+            }
+        };
+        try {
+            group.executeOnPooledThread(task);
+        } catch (RejectedExecutionException ree) {
+            throw new ShutdownChannelGroupException();
+        }
+        return result;
+    }
+
+    @Override
+    public <A> Future<Integer> read(final ByteBuffer dst,
+                                    final long timeout,
+                                    final TimeUnit unit,
+                                    A attachment,
+                                    final CompletionHandler<Integer,? super A> handler)
+    {
+        if (dst.isReadOnly())
+            throw new IllegalArgumentException("Read-only buffer");
+        if (timeout < 0L)
+            throw new IllegalArgumentException("Negative timeout");
+        if (unit == null)
+            throw new NullPointerException();
+        // another thread may disconnect before read is initiated
+        if (!dc.isConnected())
+            throw new NotYetConnectedException();
+
+        // complete immediately if channel closed
+        if (!isOpen()) {
+            CompletedFuture<Integer,A> result = CompletedFuture.withFailure(this,
+                new ClosedChannelException(), attachment);
+            Invoker.invoke(handler, result);
+            return result;
+        }
+
+        final PendingFuture<Integer,A> result =
+            new PendingFuture<Integer,A>(this, handler, attachment);
+        Runnable task = new Runnable() {
+            public void run() {
+                try {
+                    int n = 0;
+                    long to;
+                    if (timeout == 0L) {
+                        beginNoTimeoutRead();
+                        try {
+                            n = dc.read(dst);
+                        } finally {
+                            endNoTimeoutRead();
+                        }
+                        to = 0L;
+                    } else {
+                        to = prepareForTimedRead(result, unit.toMillis(timeout));
+                        if (to <= 0L)
+                            throw new InterruptedByTimeoutException();
+                        n = dc.read(dst);
+                    }
+                    if (n == 0) {
+                        Selector sel = getSelector();
+                        SelectionKey sk = null;
+                        try {
+                            sk = dc.register(sel, SelectionKey.OP_READ);
+                            for (;;) {
+                                if (!dc.isOpen())
+                                    throw new AsynchronousCloseException();
+                                if (result.isCancelled())
+                                    break;
+                                long st = System.currentTimeMillis();
+                                int ns = sel.select(to);
+                                if (ns > 0) {
+                                    if ((n = dc.read(dst)) != 0)
+                                        break;
+                                }
+                                sel.selectedKeys().remove(sk);
+                                if (timeout != 0L) {
+                                    to -= System.currentTimeMillis() - st;
+                                    if (to <= 0)
+                                        throw new InterruptedByTimeoutException();
+                                }
+                            }
+                        } finally {
+                            if (sk != null)
+                                sk.cancel();
+                            releaseSelector(sel);
+                        }
+                    }
+                    result.setResult(n);
+                } catch (Throwable x) {
+                    if (x instanceof ClosedChannelException)
+                        x = new AsynchronousCloseException();
+                    result.setFailure(x);
+                }
+                Invoker.invokeUnchecked(handler, result);
+            }
+        };
+        try {
+            group.executeOnPooledThread(task);
+        } catch (RejectedExecutionException ree) {
+            throw new ShutdownChannelGroupException();
+        }
+        return result;
+    }
+
+    @Override
+    public  AsynchronousDatagramChannel bind(SocketAddress local)
+        throws IOException
+    {
+        dc.bind(local);
+        return this;
+    }
+
+    @Override
+    public SocketAddress getLocalAddress() throws IOException {
+        return dc.getLocalAddress();
+    }
+
+    @Override
+    public <T> AsynchronousDatagramChannel setOption(SocketOption<T> name, T value)
+        throws IOException
+    {
+        dc.setOption(name, value);
+        return this;
+    }
+
+    @Override
+    public  <T> T getOption(SocketOption<T> name) throws IOException {
+        return dc.getOption(name);
+    }
+
+    @Override
+    public Set<SocketOption<?>> supportedOptions() {
+        return dc.supportedOptions();
+    }
+
+    @Override
+    public SocketAddress getRemoteAddress() throws IOException {
+        return dc.getRemoteAddress();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,426 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.util.concurrent.*;
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+/**
+ * "Portable" implementation of AsynchronousFileChannel for use on operating
+ * systems that don't support asynchronous file I/O.
+ */
+
+public class SimpleAsynchronousFileChannelImpl
+    extends AsynchronousFileChannelImpl
+{
+    // lazy initialization of default thread pool for file I/O
+    private static class DefaultExecutorHolder {
+        static final ExecutorService defaultExecutor =
+            ThreadPool.createDefault().executor();
+    }
+
+    // Used to make native read and write calls
+    private static final FileDispatcher nd = new FileDispatcherImpl();
+
+    // indicates if the associated thread pool is the default thread pool
+    private final boolean isDefaultExecutor;
+
+    // Thread-safe set of IDs of native threads, for signalling
+    private final NativeThreadSet threads = new NativeThreadSet(2);
+
+
+    SimpleAsynchronousFileChannelImpl(FileDescriptor fdObj,
+                                      boolean reading,
+                                      boolean writing,
+                                      ExecutorService executor,
+                                      boolean isDefaultexecutor)
+    {
+        super(fdObj, reading, writing, executor);
+        this.isDefaultExecutor = isDefaultexecutor;
+    }
+
+    public static AsynchronousFileChannel open(FileDescriptor fdo,
+                                               boolean reading,
+                                               boolean writing,
+                                               ThreadPool pool)
+    {
+        // Executor is either default or based on pool parameters
+        ExecutorService executor;
+        boolean isDefaultexecutor;
+        if (pool == null) {
+            executor = DefaultExecutorHolder.defaultExecutor;
+            isDefaultexecutor = true;
+        } else {
+            executor = pool.executor();
+            isDefaultexecutor = false;
+        }
+        return new SimpleAsynchronousFileChannelImpl(fdo,
+            reading, writing, executor, isDefaultexecutor);
+    }
+
+    @Override
+    public void close() throws IOException {
+        // mark channel as closed
+        synchronized (fdObj) {
+            if (closed)
+                return;     // already closed
+            closed = true;
+            // from this point on, if another thread invokes the begin() method
+            // then it will throw ClosedChannelException
+        }
+
+        // signal any threads blocked on this channel
+        nd.preClose(fdObj);
+        threads.signalAndWait();
+
+        // wait until all async I/O operations have completely gracefully
+        closeLock.writeLock().lock();
+        try {
+            // do nothing
+        } finally {
+            closeLock.writeLock().unlock();
+        }
+
+        // Invalidate and release any locks that we still hold
+        invalidateAllLocks();
+
+        // close file
+        nd.close(fdObj);
+
+        // shutdown executor if specific to this channel
+        if (!isDefaultExecutor) {
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    executor.shutdown();
+                    return null;
+                }
+            });
+        }
+    }
+
+    @Override
+    public long size() throws IOException {
+        int ti = threads.add();
+        try {
+            long n = 0L;
+            try {
+                begin();
+                do {
+                    n = nd.size(fdObj);
+                } while ((n == IOStatus.INTERRUPTED) && isOpen());
+                return n;
+            } finally {
+                end(n >= 0L);
+            }
+        } finally {
+            threads.remove(ti);
+        }
+    }
+
+    @Override
+    public AsynchronousFileChannel truncate(long size) throws IOException {
+        if (size < 0L)
+            throw new IllegalArgumentException("Negative size");
+        if (!writing)
+            throw new NonWritableChannelException();
+        int ti = threads.add();
+        try {
+            long n = 0L;
+            try {
+                begin();
+                do {
+                    n = nd.size(fdObj);
+                } while ((n == IOStatus.INTERRUPTED) && isOpen());
+
+                // truncate file if 'size' less than current size
+                if (size < n && isOpen()) {
+                    do {
+                        n = nd.truncate(fdObj, size);
+                    } while ((n == IOStatus.INTERRUPTED) && isOpen());
+                }
+                return this;
+            } finally {
+                end(n > 0);
+            }
+        } finally {
+            threads.remove(ti);
+        }
+    }
+
+    @Override
+    public void force(boolean metaData) throws IOException {
+        int ti = threads.add();
+        try {
+            int n = 0;
+            try {
+                begin();
+                do {
+                    n = nd.force(fdObj, metaData);
+                } while ((n == IOStatus.INTERRUPTED) && isOpen());
+            } finally {
+                end(n >= 0);
+            }
+        } finally {
+            threads.remove(ti);
+        }
+    }
+
+    @Override
+    public <A> Future<FileLock> lock(final long position,
+                                     final long size,
+                                     final boolean shared,
+                                     A attachment,
+                                     final CompletionHandler<FileLock,? super A> handler)
+    {
+        if (shared && !reading)
+            throw new NonReadableChannelException();
+        if (!shared && !writing)
+            throw new NonWritableChannelException();
+
+        // add to lock table
+        final FileLockImpl fli = addToFileLockTable(position, size, shared);
+        if (fli == null) {
+            CompletedFuture<FileLock,A> result = CompletedFuture
+                .withFailure(this, new ClosedChannelException(), attachment);
+            Invoker.invokeIndirectly(handler, result, executor);
+            return result;
+        }
+
+        final PendingFuture<FileLock,A> result =
+            new PendingFuture<FileLock,A>(this, handler, attachment);
+        Runnable task = new Runnable() {
+            public void run() {
+                int ti = threads.add();
+                try {
+                    int n;
+                    try {
+                        begin();
+                        do {
+                            n = nd.lock(fdObj, true, position, size, shared);
+                        } while ((n == FileDispatcher.INTERRUPTED) && isOpen());
+                        if (n == FileDispatcher.LOCKED) {
+                            result.setResult(fli);
+                        } else {
+                            if (n != FileDispatcher.INTERRUPTED)
+                                throw new AssertionError();
+                            throw new AsynchronousCloseException();
+                        }
+                    } catch (IOException x) {
+                        removeFromFileLockTable(fli);
+                        if (!isOpen())
+                            x = new AsynchronousCloseException();
+                        result.setFailure(x);
+                    } finally {
+                        end();
+                    }
+                } finally {
+                    threads.remove(ti);
+                }
+                Invoker.invokeUnchecked(handler, result);
+            }
+        };
+        try {
+            executor.execute(task);
+        } catch (RejectedExecutionException ree) {
+            // rollback
+            removeFromFileLockTable(fli);
+            throw new ShutdownChannelGroupException();
+        }
+        return result;
+    }
+
+    @Override
+    public FileLock tryLock(long position, long size, boolean shared)
+        throws IOException
+    {
+        if (shared && !reading)
+            throw new NonReadableChannelException();
+        if (!shared && !writing)
+            throw new NonWritableChannelException();
+
+        // add to lock table
+        FileLockImpl fli = addToFileLockTable(position, size, shared);
+        if (fli == null)
+            throw new ClosedChannelException();
+
+        int ti = threads.add();
+        boolean gotLock = false;
+        try {
+            begin();
+            int n;
+            do {
+                n = nd.lock(fdObj, false, position, size, shared);
+            } while ((n == FileDispatcher.INTERRUPTED) && isOpen());
+            if (n != FileDispatcher.LOCKED) {
+                if (n == FileDispatcher.NO_LOCK)
+                    return null;    // locked by someone else
+                if (n == FileDispatcher.INTERRUPTED)
+                    throw new AsynchronousCloseException();
+                // should not get here
+                throw new AssertionError();
+            }
+            gotLock = true;
+            return fli;
+        } finally {
+            if (!gotLock)
+                removeFromFileLockTable(fli);
+            end();
+            threads.remove(ti);
+        }
+    }
+
+    @Override
+    void release(FileLockImpl fli) throws IOException {
+        try {
+            begin();
+            nd.release(fdObj, fli.position(), fli.size());
+            removeFromFileLockTable(fli);
+        } finally {
+            end();
+        }
+    }
+
+    @Override
+    public <A> Future<Integer> read(final ByteBuffer dst,
+                                    final long position,
+                                    A attachment,
+                                    final CompletionHandler<Integer,? super A> handler)
+    {
+        if (position < 0)
+            throw new IllegalArgumentException("Negative position");
+        if (!reading)
+            throw new NonReadableChannelException();
+        if (dst.isReadOnly())
+            throw new IllegalArgumentException("Read-only buffer");
+
+        // complete immediately if channel closed or no space remaining
+        if (!isOpen() || (dst.remaining() == 0)) {
+            CompletedFuture<Integer,A> result;
+            if (isOpen()) {
+                result = CompletedFuture.withResult(this, 0, attachment);
+            } else {
+                result = CompletedFuture.withFailure(this,
+                    new ClosedChannelException(), attachment);
+            }
+            Invoker.invokeIndirectly(handler, result, executor);
+            return result;
+        }
+
+        final PendingFuture<Integer,A> result =
+            new PendingFuture<Integer,A>(this, handler, attachment);
+        Runnable task = new Runnable() {
+            public void run() {
+                int ti = threads.add();
+                try {
+                    begin();
+                    int n;
+                    do {
+                        n = IOUtil.read(fdObj, dst, position, nd, null);
+                    } while ((n == IOStatus.INTERRUPTED) && isOpen());
+                    if (n < 0 && !isOpen())
+                        throw new AsynchronousCloseException();
+                    result.setResult(n);
+                } catch (IOException x) {
+                    if (!isOpen())
+                        x = new AsynchronousCloseException();
+                    result.setFailure(x);
+                } finally {
+                    end();
+                    threads.remove(ti);
+                }
+                Invoker.invokeUnchecked(handler, result);
+            }
+        };
+        try {
+            executor.execute(task);
+        } catch (RejectedExecutionException ree) {
+            throw new ShutdownChannelGroupException();
+        }
+        return result;
+    }
+
+    @Override
+    public <A> Future<Integer> write(final ByteBuffer src,
+                                     final long position,
+                                     A attachment,
+                                     final CompletionHandler<Integer,? super A> handler)
+    {
+        if (position < 0)
+            throw new IllegalArgumentException("Negative position");
+        if (!writing)
+            throw new NonWritableChannelException();
+
+        // complete immediately if channel is closed or no bytes remaining
+        if (!isOpen() || (src.remaining() == 0)) {
+            CompletedFuture<Integer,A> result;
+            if (isOpen()) {
+                result = CompletedFuture.withResult(this, 0, attachment);
+            } else {
+                result = CompletedFuture.withFailure(this,
+                    new ClosedChannelException(), attachment);
+            }
+            Invoker.invokeIndirectly(handler, result, executor);
+            return result;
+        }
+
+        final PendingFuture<Integer,A> result =
+            new PendingFuture<Integer,A>(this, handler, attachment);
+        Runnable task = new Runnable() {
+            public void run() {
+                int ti = threads.add();
+                try {
+                    begin();
+                    int n;
+                    do {
+                        n = IOUtil.write(fdObj, src, position, nd, null);
+                    } while ((n == IOStatus.INTERRUPTED) && isOpen());
+                    if (n < 0 && !isOpen())
+                        throw new AsynchronousCloseException();
+                    result.setResult(n);
+                } catch (IOException x) {
+                    if (!isOpen())
+                        x = new AsynchronousCloseException();
+                    result.setFailure(x);
+                } finally {
+                    end();
+                    threads.remove(ti);
+                }
+                Invoker.invokeUnchecked(handler, result);
+            }
+        };
+        try {
+            executor.execute(task);
+        } catch (RejectedExecutionException ree) {
+            throw new ShutdownChannelGroupException();
+        }
+        return result;
+    }
+}
--- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -128,28 +128,28 @@
     public SocketAddress getLocalAddress() throws IOException {
         synchronized (stateLock) {
             if (!isOpen())
-                return null;
+                throw new ClosedChannelException();
             return localAddress;
         }
     }
 
     @Override
-    public SocketAddress getConnectedAddress() throws IOException {
+    public SocketAddress getRemoteAddress() throws IOException {
         synchronized (stateLock) {
             if (!isOpen())
-                return null;
+                throw new ClosedChannelException();
             return remoteAddress;
         }
     }
 
     @Override
-    public SocketChannel setOption(SocketOption name, Object value)
+    public <T> SocketChannel setOption(SocketOption<T> name, T value)
         throws IOException
     {
         if (name == null)
             throw new NullPointerException();
-        if (!options().contains(name))
-            throw new IllegalArgumentException("Invalid option name");
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
 
         synchronized (stateLock) {
             if (!isOpen())
@@ -175,8 +175,8 @@
     {
         if (name == null)
             throw new NullPointerException();
-        if (!options().contains(name))
-            throw new IllegalArgumentException("Invalid option name");
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
 
         synchronized (stateLock) {
             if (!isOpen())
@@ -193,7 +193,7 @@
         }
     }
 
-    private static class LazyInitialization {
+    private static class DefaultOptionsHolder {
         static final Set<SocketOption<?>> defaultOptions = defaultOptions();
 
         private static Set<SocketOption<?>> defaultOptions() {
@@ -212,8 +212,8 @@
     }
 
     @Override
-    public final Set<SocketOption<?>> options() {
-        return LazyInitialization.defaultOptions;
+    public final Set<SocketOption<?>> supportedOptions() {
+        return DefaultOptionsHolder.defaultOptions;
     }
 
     private boolean ensureReadOpen() throws ClosedChannelException {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/ThreadPool.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.util.concurrent.*;
+import java.security.AccessController;
+import sun.security.action.GetPropertyAction;
+import sun.security.action.GetIntegerAction;
+
+/**
+ * Encapsulates a thread pool associated with a channel group.
+ */
+
+public class ThreadPool {
+    private static final String DEFAULT_THREAD_POOL_THREAD_FACTORY =
+        "java.nio.channels.DefaultThreadPool.threadFactory";
+    private static final String DEFAULT_THREAD_POOL_INITIAL_SIZE =
+        "java.nio.channels.DefaultThreadPool.initialSize";
+    private static final ThreadFactory defaultThreadFactory = new ThreadFactory() {
+         @Override
+         public Thread newThread(Runnable r) {
+             Thread t = new Thread(r);
+             t.setDaemon(true);
+             return t;
+        }
+     };
+
+    private final ExecutorService executor;
+
+    // indicates if thread pool is fixed size
+    private final boolean isFixed;
+
+    // indicates the pool size (for a fixed thread pool configuratin this is
+    // the maximum pool size; for other thread pools it is the initial size)
+    private final int poolSize;
+
+    private ThreadPool(ExecutorService executor,
+                       boolean isFixed,
+                       int poolSize)
+    {
+        this.executor = executor;
+        this.isFixed = isFixed;
+        this.poolSize = poolSize;
+    }
+
+    ExecutorService executor() {
+        return executor;
+    }
+
+    boolean isFixedThreadPool() {
+        return isFixed;
+    }
+
+    int poolSize() {
+        return poolSize;
+    }
+
+    static ThreadFactory defaultThreadFactory() {
+        return defaultThreadFactory;
+    }
+
+    private static class DefaultThreadPoolHolder {
+        final static ThreadPool defaultThreadPool = createDefault();
+    }
+
+    // return the default (system-wide) thread pool
+    static ThreadPool getDefault() {
+        return DefaultThreadPoolHolder.defaultThreadPool;
+    }
+
+    // create thread using default settings (configured by system properties)
+    static ThreadPool createDefault() {
+        // default the number of fixed threads to the hardware core count
+        int initialSize = getDefaultThreadPoolInitialSize();
+        if (initialSize < 0)
+            initialSize = Runtime.getRuntime().availableProcessors();
+        // default to thread factory that creates daemon threads
+        ThreadFactory threadFactory = getDefaultThreadPoolThreadFactory();
+        if (threadFactory == null)
+            threadFactory = defaultThreadFactory;
+        // create thread pool
+        ExecutorService executor =
+            new ThreadPoolExecutor(0, Integer.MAX_VALUE,
+                                   Long.MAX_VALUE, TimeUnit.MILLISECONDS,
+                                   new SynchronousQueue<Runnable>(),
+                                   threadFactory);
+        return new ThreadPool(executor, false, initialSize);
+    }
+
+    // create using given parameters
+    static ThreadPool create(int nThreads, ThreadFactory factory) {
+        if (nThreads <= 0)
+            throw new IllegalArgumentException("'nThreads' must be > 0");
+        ExecutorService executor = Executors.newFixedThreadPool(nThreads, factory);
+        return new ThreadPool(executor, true, nThreads);
+    }
+
+    // wrap a user-supplied executor
+    public static ThreadPool wrap(ExecutorService executor, int initialSize) {
+        if (executor == null)
+            throw new NullPointerException("'executor' is null");
+        // attempt to check if cached thread pool
+        if (executor instanceof ThreadPoolExecutor) {
+            int max = ((ThreadPoolExecutor)executor).getMaximumPoolSize();
+            if (max == Integer.MAX_VALUE) {
+                if (initialSize < 0) {
+                    initialSize = Runtime.getRuntime().availableProcessors();
+                } else {
+                   // not a cached thread pool so ignore initial size
+                    initialSize = 0;
+                }
+            }
+        } else {
+            // some other type of thread pool
+            if (initialSize < 0)
+                initialSize = 0;
+        }
+        return new ThreadPool(executor, false, initialSize);
+    }
+
+    private static int getDefaultThreadPoolInitialSize() {
+        String propValue = AccessController.doPrivileged(new
+            GetPropertyAction(DEFAULT_THREAD_POOL_INITIAL_SIZE));
+        if (propValue != null) {
+            try {
+                return Integer.parseInt(propValue);
+            } catch (NumberFormatException x) {
+                throw new Error("Value of property '" + DEFAULT_THREAD_POOL_INITIAL_SIZE +
+                    "' is invalid: " + x);
+            }
+        }
+        return -1;
+    }
+
+    private static ThreadFactory getDefaultThreadPoolThreadFactory() {
+        String propValue = AccessController.doPrivileged(new
+            GetPropertyAction(DEFAULT_THREAD_POOL_THREAD_FACTORY));
+        if (propValue != null) {
+            try {
+                Class<?> c = Class
+                    .forName(propValue, true, ClassLoader.getSystemClassLoader());
+                return ((ThreadFactory)c.newInstance());
+            } catch (ClassNotFoundException x) {
+                throw new Error(x);
+            } catch (InstantiationException x) {
+                throw new Error(x);
+            } catch (IllegalAccessException x) {
+                throw new Error(x);
+            }
+        }
+        return null;
+    }
+}
--- a/jdk/src/share/classes/sun/nio/ch/Util.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/Util.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -31,7 +31,6 @@
 import java.nio.ByteBuffer;
 import java.nio.MappedByteBuffer;
 import java.nio.channels.*;
-import java.nio.channels.spi.*;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.*;
@@ -100,6 +99,9 @@
                 return;
             }
         }
+
+        // release memory
+       ((DirectBuffer)buf).cleaner().clean();
     }
 
     private static class SelectorWrapper {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Base implementation of AclFileAttributeView
+ */
+
+abstract class AbstractAclFileAttributeView
+    implements AclFileAttributeView
+{
+    private static final String OWNER_NAME = "owner";
+    private static final String ACL_NAME = "acl";
+
+    @Override
+    public final String name() {
+        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)
+        throws IOException
+    {
+        if (attribute.equals(OWNER_NAME)) {
+            setOwner((UserPrincipal)value);
+            return;
+        }
+        if (attribute.equals(ACL_NAME)) {
+            setAcl((List<AclEntry>)value);
+            return;
+        }
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public final Map<String,?> readAttributes(String first, String[] rest)
+        throws IOException
+    {
+        boolean acl = false;
+        boolean owner = false;
+
+        if (first.equals(ACL_NAME)) acl = true;
+        else if (first.equals(OWNER_NAME)) owner = true;
+        else if (first.equals("*")) {
+            owner = true;
+            acl = true;
+        }
+
+        if (!acl || !owner) {
+            for (String attribute: rest) {
+                if (attribute.equals("*")) {
+                    owner = true;
+                    acl = true;
+                    break;
+                }
+                if (attribute.equals(ACL_NAME)) {
+                    acl = true;
+                    continue;
+                }
+                if (attribute.equals(OWNER_NAME)) {
+                    owner = true;
+                    continue;
+                }
+            }
+        }
+        Map<String,Object> result = new HashMap<String,Object>(2);
+        if (acl)
+            result.put(ACL_NAME, getAcl());
+        if (owner)
+            result.put(OWNER_NAME, getOwner());
+        return Collections.unmodifiableMap(result);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Base implementation of BasicFileAttributeView
+ */
+
+abstract class AbstractBasicFileAttributeView
+    implements BasicFileAttributeView
+{
+    private static final String SIZE_NAME = "size";
+    private static final String CREATION_TIME_NAME = "creationTime";
+    private static final String LAST_ACCESS_TIME_NAME = "lastAccessTime";
+    private static final String LAST_MODIFIED_TIME_NAME = "lastModifiedTime";
+    private static final String RESOLUTION_NAME = "resolution";
+    private static final String FILE_KEY_NAME = "fileKey";
+    private static final String LINK_COUNT_NAME = "linkCount";
+    private static final String IS_DIRECTORY_NAME = "isDirectory";
+    private static final String IS_REGULAR_FILE_NAME = "isRegularFile";
+    private static final String IS_SYMBOLIC_LINK_NAME = "isSymbolicLink";
+    private static final String IS_OTHER_NAME = "isOther";
+
+    protected AbstractBasicFileAttributeView() { }
+
+    @Override
+    public String name() {
+        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(RESOLUTION_NAME))
+            return attrs.resolution();
+        if (attribute.equals(FILE_KEY_NAME))
+            return attrs.fileKey();
+        if (attribute.equals(LINK_COUNT_NAME))
+            return attrs.linkCount();
+        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;
+    }
+
+    private Long toTimeValue(Object value) {
+        if (value == null)
+            throw new NullPointerException();
+        Long time = (Long)value;
+        if (time < 0L && time != -1L)
+            throw new IllegalArgumentException("time value cannot be negative");
+        return time;
+    }
+
+    @Override
+    public void setAttribute(String attribute, Object value)
+        throws IOException
+    {
+        if (attribute.equals(LAST_MODIFIED_TIME_NAME)) {
+            setTimes(toTimeValue(value), null, null, TimeUnit.MILLISECONDS);
+            return;
+        }
+        if (attribute.equals(LAST_ACCESS_TIME_NAME)) {
+            setTimes(null, toTimeValue(value), null, TimeUnit.MILLISECONDS);
+            return;
+        }
+        if (attribute.equals(CREATION_TIME_NAME)) {
+            setTimes(null, null, toTimeValue(value), TimeUnit.MILLISECONDS);
+            return;
+        }
+        throw new UnsupportedOperationException("'" + attribute +
+            "' is unknown or read-only attribute");
+    }
+
+    /**
+     *
+     */
+    static class AttributesBuilder {
+        private Set<String> set = new HashSet<String>();
+        private Map<String,Object> map = new HashMap<String,Object>();
+        private boolean copyAll;
+
+        private AttributesBuilder(String first, String[] rest) {
+            if (first.equals("*")) {
+                copyAll = true;
+            } else {
+                set.add(first);
+                // copy names into the given Set bailing out if "*" is found
+                for (String attribute: rest) {
+                    if (attribute.equals("*")) {
+                        copyAll = true;
+                        break;
+                    }
+                    set.add(attribute);
+                }
+            }
+        }
+
+        /**
+         * Creates builder to build up a map of the matching attributes
+         */
+        static AttributesBuilder create(String first, String[] rest) {
+            return new AttributesBuilder(first, rest);
+        }
+
+        /**
+         * Returns true if the attribute should be returned in the map
+         */
+        boolean match(String attribute) {
+            if (copyAll)
+                return true;
+            return set.contains(attribute);
+        }
+
+        void add(String attribute, Object value) {
+            map.put(attribute, value);
+        }
+
+        /**
+         * Returns the map. Discard all references to the AttributesBuilder
+         * after invoking this method.
+         */
+        Map<String,Object> unmodifiableMap() {
+            return Collections.unmodifiableMap(map);
+        }
+    }
+
+    /**
+     * Invoked by readAttributes or sub-classes to add all matching basic
+     * attributes to the builder
+     */
+    final void addBasicAttributesToBuilder(BasicFileAttributes attrs,
+                                           AttributesBuilder builder)
+    {
+        if (builder.match(SIZE_NAME))
+            builder.add(SIZE_NAME, attrs.size());
+        if (builder.match(CREATION_TIME_NAME))
+            builder.add(CREATION_TIME_NAME, attrs.creationTime());
+        if (builder.match(LAST_ACCESS_TIME_NAME))
+            builder.add(LAST_ACCESS_TIME_NAME, attrs.lastAccessTime());
+        if (builder.match(LAST_MODIFIED_TIME_NAME))
+            builder.add(LAST_MODIFIED_TIME_NAME, attrs.lastModifiedTime());
+        if (builder.match(RESOLUTION_NAME))
+            builder.add(RESOLUTION_NAME, attrs.resolution());
+        if (builder.match(FILE_KEY_NAME))
+            builder.add(FILE_KEY_NAME, attrs.fileKey());
+        if (builder.match(LINK_COUNT_NAME))
+            builder.add(LINK_COUNT_NAME, attrs.linkCount());
+        if (builder.match(IS_DIRECTORY_NAME))
+            builder.add(IS_DIRECTORY_NAME, attrs.isDirectory());
+        if (builder.match(IS_REGULAR_FILE_NAME))
+            builder.add(IS_REGULAR_FILE_NAME, attrs.isRegularFile());
+        if (builder.match(IS_SYMBOLIC_LINK_NAME))
+            builder.add(IS_SYMBOLIC_LINK_NAME, attrs.isSymbolicLink());
+        if (builder.match(IS_OTHER_NAME))
+            builder.add(IS_OTHER_NAME, attrs.isOther());
+    }
+
+    @Override
+    public Map<String,?> readAttributes(String first, String[] rest)
+        throws IOException
+    {
+        AttributesBuilder builder = AttributesBuilder.create(first, rest);
+        addBasicAttributesToBuilder(readAttributes(), builder);
+        return builder.unmodifiableMap();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/AbstractFileStoreSpaceAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Base implementation of FileStoreSpaceAttributeView
+ */
+
+abstract class AbstractFileStoreSpaceAttributeView
+    implements FileStoreSpaceAttributeView
+{
+    private static final String TOTAL_SPACE_NAME = "totalSpace";
+    private static final String USABLE_SPACE_NAME = "usableSpace";
+    private static final String UNALLOCATED_SPACE_NAME = "unallocatedSpace";
+
+    @Override
+    public final String name() {
+        return "space";
+    }
+
+    @Override
+    public final Object getAttribute(String attribute) throws IOException {
+        FileStoreSpaceAttributes attrs = readAttributes();
+        if (attribute.equals(TOTAL_SPACE_NAME))
+            return attrs.totalSpace();
+        if (attribute.equals(USABLE_SPACE_NAME))
+            return attrs.usableSpace();
+        if (attribute.equals(UNALLOCATED_SPACE_NAME))
+            return attrs.unallocatedSpace();
+        return null;
+    }
+
+    @Override
+    public final void setAttribute(String attribute, Object value)
+        throws IOException
+    {
+        if (attribute == null || value == null)
+            throw new NullPointerException();
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public final Map<String,?> readAttributes(String first, String[] rest)
+        throws IOException
+    {
+        boolean total = false;
+        boolean usable = false;
+        boolean unallocated = false;
+
+        if (first.equals(TOTAL_SPACE_NAME)) total = true;
+        else if (first.equals(USABLE_SPACE_NAME)) usable = true;
+        else if (first.equals(UNALLOCATED_SPACE_NAME)) unallocated = true;
+        else if (first.equals("*")) {
+            total = true;
+            usable = true;
+            unallocated = true;
+        }
+
+        if (!total || !usable || !unallocated) {
+            for (String attribute: rest) {
+                if (attribute.equals("*")) {
+                    total = true;
+                    usable = true;
+                    unallocated = true;
+                    break;
+                }
+                if (attribute.equals(TOTAL_SPACE_NAME)) {
+                    total = true;
+                    continue;
+                }
+                if (attribute.equals(USABLE_SPACE_NAME)) {
+                    usable = true;
+                    continue;
+                }
+                if (attribute.equals(UNALLOCATED_SPACE_NAME)) {
+                    unallocated = true;
+                    continue;
+                }
+            }
+        }
+
+        FileStoreSpaceAttributes attrs = readAttributes();
+        Map<String,Object> result = new HashMap<String,Object>(2);
+        if (total)
+            result.put(TOTAL_SPACE_NAME, attrs.totalSpace());
+        if (usable)
+            result.put(USABLE_SPACE_NAME, attrs.usableSpace());
+        if (unallocated)
+            result.put(UNALLOCATED_SPACE_NAME, attrs.unallocatedSpace());
+        return Collections.unmodifiableMap(result);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/AbstractFileTypeDetector.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.FileRef;
+import java.nio.file.spi.FileTypeDetector;
+import java.io.IOException;
+import sun.nio.fs.MimeType;
+
+/**
+ * Base implementation of FileTypeDetector
+ */
+
+public abstract class AbstractFileTypeDetector
+    extends FileTypeDetector
+{
+    protected AbstractFileTypeDetector() {
+        super();
+    }
+
+    /**
+     * Invokes the implProbeContentType method to guess the file's content type,
+     * and this validates that the content type's syntax is valid.
+     */
+    @Override
+    public final String probeContentType(FileRef file) throws IOException {
+        if (file == null)
+            throw new NullPointerException("'file' is null");
+        String result = implProbeContentType(file);
+        if (result != null) {
+            // check the content type
+            try {
+                MimeType.parse(result);
+            } catch (IllegalArgumentException ignore) {
+                result = null;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Probes the given file to guess its content type.
+     */
+    protected abstract String implProbeContentType(FileRef file)
+        throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/AbstractPoller.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Base implementation of background poller thread used in watch service
+ * implementations. A poller thread waits on events from the file system and
+ * also services "requests" from clients to register for new events or cancel
+ * existing registrations.
+ */
+
+abstract class AbstractPoller implements Runnable {
+
+    // list of requests pending to the poller thread
+    private final LinkedList<Request> requestList;
+
+    // set to true when shutdown
+    private boolean shutdown;
+
+    protected AbstractPoller() {
+        this.requestList = new LinkedList<Request>();
+        this.shutdown = false;
+    }
+
+    /**
+     * Starts the poller thread
+     */
+    public void start() {
+        final Runnable thisRunnable = this;
+        AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                Thread thr = new Thread(thisRunnable);
+                thr.setDaemon(true);
+                thr.start();
+                return null;
+            }
+         });
+    }
+
+    /**
+     * Wakeup poller thread so that it can service pending requests
+     */
+    abstract void wakeup() throws IOException;
+
+    /**
+     * Executed by poller thread to register directory for changes
+     */
+    abstract Object implRegister(Path path,
+                                 Set<? extends WatchEvent.Kind<?>> events,
+                                 WatchEvent.Modifier... modifiers);
+
+    /**
+     * Executed by poller thread to cancel key
+     */
+    abstract void implCancelKey(WatchKey key);
+
+    /**
+     * Executed by poller thread to shutdown and cancel all keys
+     */
+    abstract void implCloseAll();
+
+    /**
+     * Requests, and waits on, poller thread to register given file.
+     */
+    final WatchKey register(FileRef dir,
+                            WatchEvent.Kind<?>[] events,
+                            WatchEvent.Modifier... modifiers)
+        throws IOException
+    {
+        // validate arguments before request to poller
+        if (dir == null)
+            throw new NullPointerException();
+        if (events.length == 0)
+            throw new IllegalArgumentException("No events to register");
+        Set<WatchEvent.Kind<?>> eventSet = new HashSet<WatchEvent.Kind<?>>(events.length);
+        for (WatchEvent.Kind<?> event: events) {
+            // standard events
+            if (event == StandardWatchEventKind.ENTRY_CREATE ||
+                event == StandardWatchEventKind.ENTRY_MODIFY ||
+                event == StandardWatchEventKind.ENTRY_DELETE)
+            {
+                eventSet.add(event);
+                continue;
+            }
+
+            // OVERFLOW is ignored
+            if (event == StandardWatchEventKind.OVERFLOW) {
+                if (events.length == 1)
+                    throw new IllegalArgumentException("No events to register");
+                continue;
+            }
+
+            // null/unsupported
+            if (event == null)
+                throw new NullPointerException("An element in event set is 'null'");
+            throw new UnsupportedOperationException(event.name());
+        }
+        return (WatchKey)invoke(RequestType.REGISTER, dir, eventSet, modifiers);
+    }
+
+    /**
+     * Cancels, and waits on, poller thread to cancel given key.
+     */
+    final void cancel(WatchKey key) {
+        try {
+            invoke(RequestType.CANCEL, key);
+        } catch (IOException x) {
+            // should not happen
+            throw new AssertionError(x.getMessage());
+        }
+    }
+
+    /**
+     * Shutdown poller thread
+     */
+    final void close() throws IOException {
+        invoke(RequestType.CLOSE);
+    }
+
+    /**
+     * Types of request that the poller thread must handle
+     */
+    private static enum RequestType {
+        REGISTER,
+        CANCEL,
+        CLOSE;
+    }
+
+    /**
+     * Encapsulates a request (command) to the poller thread.
+     */
+    private static class Request {
+        private final RequestType type;
+        private final Object[] params;
+
+        private boolean completed = false;
+        private Object result = null;
+
+        Request(RequestType type, Object... params) {
+            this.type = type;
+            this.params = params;
+        }
+
+        RequestType type() {
+            return type;
+        }
+
+        Object[] parameters() {
+            return params;
+        }
+
+        void release(Object result) {
+            synchronized (this) {
+                this.completed = true;
+                this.result = result;
+                notifyAll();
+            }
+        }
+
+        /**
+         * Await completion of the request. The return value is the result of
+         * the request.
+         */
+        Object awaitResult() {
+            synchronized (this) {
+                while (!completed) {
+                    try {
+                        wait();
+                    } catch (InterruptedException x) {
+                        // ignore
+                    }
+                }
+                return result;
+            }
+        }
+    }
+
+    /**
+     * Enqueues request to poller thread and waits for result
+     */
+    private Object invoke(RequestType type, Object... params) throws IOException {
+        // submit request
+        Request req = new Request(type, params);
+        synchronized (requestList) {
+            if (shutdown) {
+                throw new ClosedWatchServiceException();
+            }
+            requestList.add(req);
+        }
+
+        // wakeup thread
+        wakeup();
+
+        // wait for result
+        Object result = req.awaitResult();
+
+        if (result instanceof RuntimeException)
+            throw (RuntimeException)result;
+        if (result instanceof IOException )
+            throw (IOException)result;
+        return result;
+    }
+
+    /**
+     * Invoked by poller thread to process all pending requests
+     *
+     * @return  true if poller thread should shutdown
+     */
+    @SuppressWarnings("unchecked")
+    boolean processRequests() {
+        synchronized (requestList) {
+            Request req;
+            while ((req = requestList.poll()) != null) {
+                // if in process of shutdown then reject request
+                if (shutdown) {
+                    req.release(new ClosedWatchServiceException());
+                }
+
+                switch (req.type()) {
+                    /**
+                     * Register directory
+                     */
+                    case REGISTER: {
+                        Object[] params = req.parameters();
+                        Path path = (Path)params[0];
+                        Set<? extends WatchEvent.Kind<?>> events =
+                            (Set<? extends WatchEvent.Kind<?>>)params[1];
+                        WatchEvent.Modifier[] modifiers =
+                            (WatchEvent.Modifier[])params[2];
+                        req.release(implRegister(path, events, modifiers));
+                        break;
+                    }
+                    /**
+                     * Cancel existing key
+                     */
+                    case CANCEL : {
+                        Object[] params = req.parameters();
+                        WatchKey key = (WatchKey)params[0];
+                        implCancelKey(key);
+                        req.release(null);
+                        break;
+                    }
+                    /**
+                     * Close watch service
+                     */
+                    case CLOSE: {
+                        implCloseAll();
+                        req.release(null);
+                        shutdown = true;
+                        break;
+                    }
+
+                    default:
+                        req.release(new IOException("request not recognized"));
+                }
+            }
+        }
+        return shutdown;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.ByteBuffer;
+import java.nio.file.attribute.UserDefinedFileAttributeView;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Base implementation of NamedAttributeView
+ */
+
+abstract class AbstractUserDefinedFileAttributeView
+    implements UserDefinedFileAttributeView
+{
+    protected AbstractUserDefinedFileAttributeView() { }
+
+    protected void checkAccess(String file,
+                               boolean checkRead,
+                               boolean checkWrite)
+    {
+        assert checkRead || checkWrite;
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            if (checkRead)
+                sm.checkRead(file);
+            if (checkWrite)
+                sm.checkWrite(file);
+            sm.checkPermission(new RuntimePermission("accessUserDefinedAttributes"));
+        }
+    }
+
+    @Override
+    public final String name() {
+        return "xattr";
+    }
+
+    @Override
+    public final Object getAttribute(String attribute) throws IOException {
+        int size;
+        try {
+            size = size(attribute);
+        } catch (IOException e) {
+            // not found or some other I/O error
+            if (list().contains(attribute))
+                throw e;
+            return null;
+        }
+        byte[] buf = new byte[size];
+        int n = read(attribute, ByteBuffer.wrap(buf));
+        return (n == size) ? buf : Arrays.copyOf(buf, n);
+    }
+
+    @Override
+    public final void setAttribute(String attribute, Object value)
+        throws IOException
+    {
+        ByteBuffer bb;
+        if (value instanceof byte[]) {
+            bb = ByteBuffer.wrap((byte[])value);
+        } else {
+            bb = (ByteBuffer)value;
+        }
+        write(attribute, bb);
+    }
+
+    @Override
+    public final Map<String,?> readAttributes(String first, String... rest)
+        throws IOException
+    {
+        // names of attributes to return
+        List<String> names = new ArrayList<String>();
+
+        boolean readAll = false;
+        if (first.equals("*")) {
+            readAll = true;
+        } else {
+            names.add(first);
+        }
+        for (String name: rest) {
+            if (name.equals("*")) {
+                readAll = true;
+            } else {
+                names.add(name);
+            }
+        }
+        if (readAll)
+            names = list();
+
+        // read each value and return in map
+        Map<String,Object> result = new HashMap<String,Object>();
+        for (String name: names) {
+            Object value = getAttribute(name);
+            if (value != null)
+                result.put(name, value);
+        }
+
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.util.*;
+
+/**
+ * Base implementation class for watch keys.
+ */
+
+abstract class AbstractWatchKey extends WatchKey {
+
+    /**
+     * Maximum size of event list (in the future this may be tunable)
+     */
+    static final int MAX_EVENT_LIST_SIZE    = 512;
+
+    /**
+     * Special event to signal overflow
+     */
+    static final Event<Void> OVERFLOW_EVENT =
+        new Event<Void>(StandardWatchEventKind.OVERFLOW, null);
+
+    /**
+     * Possible key states
+     */
+    private static enum State { READY, SIGNALLED };
+
+    // reference to watcher
+    private final AbstractWatchService watcher;
+
+    // key state
+    private State state;
+
+    // pending events
+    private List<WatchEvent<?>> events;
+
+    protected AbstractWatchKey(AbstractWatchService watcher) {
+        this.watcher = watcher;
+        this.state = State.READY;
+        this.events = new ArrayList<WatchEvent<?>>();
+    }
+
+    final AbstractWatchService watcher() {
+        return watcher;
+    }
+
+    /**
+     * Enqueues this key to the watch service
+     */
+    final void signal() {
+        synchronized (this) {
+            if (state == State.READY) {
+                state = State.SIGNALLED;
+                watcher.enqueueKey(this);
+            }
+        }
+    }
+
+    /**
+     * Adds the event to this key and signals it.
+     */
+    @SuppressWarnings("unchecked")
+    final void signalEvent(WatchEvent.Kind<?> kind, Object context) {
+        synchronized (this) {
+            int size = events.size();
+            if (size > 1) {
+                // don't let list get too big
+                if (size >= MAX_EVENT_LIST_SIZE) {
+                    kind = StandardWatchEventKind.OVERFLOW;
+                    context = null;
+                }
+
+                // repeated event
+                WatchEvent<?> prev = events.get(size-1);
+                if (kind == prev.kind()) {
+                    boolean isRepeat;
+                    if (context == null) {
+                        isRepeat = (prev.context() == null);
+                    } else {
+                        isRepeat = context.equals(prev.context());
+                    }
+                    if (isRepeat) {
+                        ((Event<?>)prev).increment();
+                        return;
+                    }
+                }
+            }
+
+            // non-repeated event
+            events.add(new Event<Object>((WatchEvent.Kind<Object>)kind, context));
+            signal();
+        }
+    }
+
+    @Override
+    public final List<WatchEvent<?>> pollEvents() {
+        synchronized (this) {
+            List<WatchEvent<?>> result = events;
+            events = new ArrayList<WatchEvent<?>>();
+            return result;
+        }
+    }
+
+    @Override
+    public final boolean reset() {
+        synchronized (this) {
+            if (state == State.SIGNALLED && isValid()) {
+                if (events.isEmpty()) {
+                    state = State.READY;
+                } else {
+                    // pending events so re-queue key
+                    watcher.enqueueKey(this);
+                }
+            }
+            return isValid();
+        }
+    }
+
+    /**
+     * WatchEvent implementation
+     */
+    private static class Event<T> extends WatchEvent<T> {
+        private final WatchEvent.Kind<T> kind;
+        private final T context;
+
+        // synchronize on watch key to access/increment count
+        private int count;
+
+        Event(WatchEvent.Kind<T> type, T context) {
+            this.kind = type;
+            this.context = context;
+            this.count = 1;
+        }
+
+        @Override
+        public WatchEvent.Kind<T> kind() {
+            return kind;
+        }
+
+        @Override
+        public T context() {
+            return context;
+        }
+
+        @Override
+        public int count() {
+            return count;
+        }
+
+        // for repeated events
+        void increment() {
+            count++;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/AbstractWatchService.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.util.concurrent.*;
+import java.io.IOException;
+
+/**
+ * Base implementation class for watch services.
+ */
+
+abstract class AbstractWatchService extends WatchService {
+
+    // signaled keys waiting to be dequeued
+    private final LinkedBlockingDeque<WatchKey> pendingKeys =
+        new LinkedBlockingDeque<WatchKey>();
+
+    // special key to indicate that watch service is closed
+    private final WatchKey CLOSE_KEY =
+        new AbstractWatchKey(null) {
+            @Override
+            public boolean isValid() {
+                return true;
+            }
+
+            @Override
+            public void cancel() {
+            }
+        };
+
+    // used when closing watch service
+    private volatile boolean closed;
+    private Object closeLock = new Object();
+
+    protected AbstractWatchService() {
+    }
+
+    /**
+     * Register the given object with this watch service
+     */
+    abstract WatchKey register(Path path,
+                               WatchEvent.Kind<?>[] events,
+                               WatchEvent.Modifier... modifers)
+        throws IOException;
+
+    // used by AbstractWatchKey to enqueue key
+    final void enqueueKey(WatchKey key) {
+        pendingKeys.offer(key);
+    }
+
+    /**
+     * Throws ClosedWatchServiceException if watch service is closed
+     */
+    private void checkOpen() {
+        if (closed)
+            throw new ClosedWatchServiceException();
+    }
+
+    /**
+     * Checks the key isn't the special CLOSE_KEY used to unblock threads when
+     * the watch service is closed.
+     */
+    private void checkKey(WatchKey key) {
+        if (key == CLOSE_KEY) {
+            // re-queue in case there are other threads blocked in take/poll
+            enqueueKey(key);
+        }
+        checkOpen();
+    }
+
+    @Override
+    public final WatchKey  poll() {
+        checkOpen();
+        WatchKey key = pendingKeys.poll();
+        checkKey(key);
+        return key;
+    }
+
+    @Override
+    public final WatchKey poll(long timeout, TimeUnit unit)
+        throws InterruptedException
+    {
+        checkOpen();
+        WatchKey key = pendingKeys.poll(timeout, unit);
+        checkKey(key);
+        return key;
+    }
+
+    @Override
+    public final WatchKey take()
+        throws InterruptedException
+    {
+        checkOpen();
+        WatchKey key = pendingKeys.take();
+        checkKey(key);
+        return key;
+    }
+
+    /**
+     * Tells whether or not this watch service is open.
+     */
+    final boolean isOpen() {
+        return !closed;
+    }
+
+    /**
+     * Retrieves the object upon which the close method synchronizes.
+     */
+    final Object closeLock() {
+        return closeLock;
+    }
+
+    /**
+     * Closes this watch service. This method is invoked by the close
+     * method to perform the actual work of closing the watch service.
+     */
+    abstract void implClose() throws IOException;
+
+    @Override
+    public final void close()
+        throws IOException
+    {
+        synchronized (closeLock) {
+            // nothing to do if already closed
+            if (closed)
+                return;
+            closed = true;
+
+            implClose();
+
+            // clear pending keys and queue special key to ensure that any
+            // threads blocked in take/poll wakeup
+            pendingKeys.clear();
+            pendingKeys.offer(CLOSE_KEY);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/Cancellable.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import sun.misc.Unsafe;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Base implementation of a task (typically native) that polls a memory location
+ * during execution so that it may be aborted/cancelled before completion. The
+ * task is executed by invoking the {@link runInterruptibly} method defined
+ * here and cancelled by invoking Thread.interrupt.
+ */
+
+abstract class Cancellable implements Runnable {
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    private final long pollingAddress;
+    private final Object lock = new Object();
+
+    // the following require lock when examining or changing
+    private boolean completed;
+    private Throwable exception;
+
+    protected Cancellable() {
+        pollingAddress = unsafe.allocateMemory(4);
+        unsafe.putIntVolatile(null, pollingAddress, 0);
+    }
+
+    /**
+     * Returns the memory address of a 4-byte int that should be polled to
+     * detect cancellation.
+     */
+    protected long addressToPollForCancel() {
+        return pollingAddress;
+    }
+
+    /**
+     * The value to write to the polled memory location to indicate that the
+     * task has been cancelled. If this method is not overridden then it
+     * defaults to MAX_VALUE.
+     */
+    protected int cancelValue() {
+        return Integer.MAX_VALUE;
+    }
+
+    /**
+     * "cancels" the task by writing bits into memory location that it polled
+     * by the task.
+     */
+    final void cancel() {
+        synchronized (lock) {
+            if (!completed) {
+                unsafe.putIntVolatile(null, pollingAddress, cancelValue());
+            }
+        }
+    }
+
+    /**
+     * Returns the exception thrown by the task or null if the task completed
+     * successfully.
+     */
+    private Throwable exception() {
+        synchronized (lock) {
+            return exception;
+        }
+    }
+
+    @Override
+    public final void run() {
+        try {
+            implRun();
+        } catch (Throwable t) {
+            synchronized (lock) {
+                exception = t;
+            }
+        } finally {
+            synchronized (lock) {
+                completed = true;
+                unsafe.freeMemory(pollingAddress);
+            }
+        }
+    }
+
+    /**
+     * The task body. This should periodically poll the memory location
+     * to check for cancellation.
+     */
+    abstract void implRun() throws Throwable;
+
+    /**
+     * Invokes the given task in its own thread. If this (meaning the current)
+     * thread is interrupted then an attempt is make to cancel the background
+     * thread by writing into the memory location that it polls cooperatively.
+     */
+    static void runInterruptibly(Cancellable task) throws ExecutionException {
+        Thread t = new Thread(task);
+        t.start();
+        boolean cancelledByInterrupt = false;
+        while (t.isAlive()) {
+            try {
+                t.join();
+            } catch (InterruptedException e) {
+                cancelledByInterrupt = true;
+                task.cancel();
+            }
+        }
+        if (cancelledByInterrupt)
+            Thread.currentThread().interrupt();
+        Throwable exc = task.exception();
+        if (exc != null)
+            throw new ExecutionException(exc);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.io.IOException;
+
+/**
+ * An implementation of FileOwnerAttributeView that delegates to a given
+ * PosixFileAttributeView or AclFileAttributeView object.
+ */
+
+final class FileOwnerAttributeViewImpl implements FileOwnerAttributeView {
+    private static final String OWNER_NAME = "owner";
+
+    private final FileAttributeView view;
+    private final boolean isPosixView;
+
+    FileOwnerAttributeViewImpl(PosixFileAttributeView view) {
+        this.view = view;
+        this.isPosixView = true;
+    }
+
+    FileOwnerAttributeViewImpl(AclFileAttributeView view) {
+        this.view = view;
+        this.isPosixView = false;
+    }
+
+    @Override
+    public String name() {
+        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
+    {
+        if (attribute.equals(OWNER_NAME)) {
+            setOwner((UserPrincipal)value);
+            return;
+        }
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Map<String,?> readAttributes(String first, String[] rest) throws IOException {
+        Map<String,Object> result = new HashMap<String,Object>();
+        if (first.equals("*") || first.equals(OWNER_NAME)) {
+            result.put(OWNER_NAME, getOwner());
+        } else {
+            for (String attribute: rest) {
+                if (attribute.equals("*") || attribute.equals(OWNER_NAME)) {
+                    result.put(OWNER_NAME, getOwner());
+                    break;
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public UserPrincipal getOwner() throws IOException {
+        if (isPosixView) {
+            return ((PosixFileAttributeView)view).readAttributes().owner();
+        } else {
+            return ((AclFileAttributeView)view).getOwner();
+        }
+    }
+
+    @Override
+    public void setOwner(UserPrincipal owner)
+        throws IOException
+    {
+        if (isPosixView) {
+            ((PosixFileAttributeView)view).setOwner(owner);
+        } else {
+            ((AclFileAttributeView)view).setOwner(owner);
+        }
+    }
+ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/Globs.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.util.regex.PatternSyntaxException;
+
+public class Globs {
+    private Globs() { }
+
+    private static final String regexMetaChars = ".^$+{[]|()";
+    private static final String globMetaChars = "\\*?[{";
+
+    private static boolean isRegexMeta(char c) {
+        return regexMetaChars.indexOf(c) != -1;
+    }
+
+    private static boolean isGlobMeta(char c) {
+        return globMetaChars.indexOf(c) != -1;
+    }
+    private static char EOL = 0;  //TBD
+
+    private static char next(String glob, int i) {
+        if (i < glob.length()) {
+            return glob.charAt(i);
+        }
+        return EOL;
+    }
+
+    /**
+     * Creates a regex pattern from the given glob expression.
+     *
+     * @throws  PatternSyntaxException
+     */
+    private static String toRegexPattern(String globPattern, boolean isDos) {
+        boolean inGroup = false;
+        StringBuilder regex = new StringBuilder("^");
+
+        int i = 0;
+        while (i < globPattern.length()) {
+            char c = globPattern.charAt(i++);
+            switch (c) {
+                case '\\':
+                    // escape special characters
+                    if (i == globPattern.length()) {
+                        throw new PatternSyntaxException("No character to escape",
+                                globPattern, i - 1);
+                    }
+                    char next = globPattern.charAt(i++);
+                    if (isGlobMeta(next) || isRegexMeta(next)) {
+                        regex.append('\\');
+                    }
+                    regex.append(next);
+                    break;
+                case '/':
+                    if (isDos) {
+                        regex.append("\\\\");
+                    } else {
+                        regex.append(c);
+                    }
+                    break;
+                case '[':
+                    // don't match name separator in class
+                    if (isDos) {
+                        regex.append("[[^\\\\]&&[");
+                    } else {
+                        regex.append("[[^/]&&[");
+                    }
+                    if (next(globPattern, i) == '^') {
+                        // escape the regex negation char if it appears
+                        regex.append("\\^");
+                        i++;
+                    } else {
+                        // negation
+                        if (next(globPattern, i) == '!') {
+                            regex.append('^');
+                            i++;
+                        }
+                        // hyphen allowed at start
+                        if (next(globPattern, i) == '-') {
+                            regex.append('-');
+                            i++;
+                        }
+                    }
+                    boolean hasRangeStart = false;
+                    char last = 0;
+                    while (i < globPattern.length()) {
+                        c = globPattern.charAt(i++);
+                        if (c == ']') {
+                            break;
+                        }
+                        if (c == '/' || (isDos && c == '\\')) {
+                            throw new PatternSyntaxException("Explicit 'name separator' in class",
+                                    globPattern, i - 1);
+                        }
+                        // TBD: how to specify ']' in a class?
+                        if (c == '\\' || c == '[' ||
+                                c == '&' && next(globPattern, i) == '&') {
+                            // escape '\', '[' or "&&" for regex class
+                            regex.append('\\');
+                        }
+                        regex.append(c);
+
+                        if (c == '-') {
+                            if (!hasRangeStart) {
+                                throw new PatternSyntaxException("Invalid range",
+                                        globPattern, i - 1);
+                            }
+                            if ((c = next(globPattern, i++)) == EOL || c == ']') {
+                                break;
+                            }
+                            if (c < last) {
+                                throw new PatternSyntaxException("Invalid range",
+                                        globPattern, i - 3);
+                            }
+                            regex.append(c);
+                            hasRangeStart = false;
+                        } else {
+                            hasRangeStart = true;
+                            last = c;
+                        }
+                    }
+                    if (c != ']') {
+                        throw new PatternSyntaxException("Missing ']", globPattern, i - 1);
+                    }
+                    regex.append("]]");
+                    break;
+                case '{':
+                    if (inGroup) {
+                        throw new PatternSyntaxException("Cannot nest groups",
+                                globPattern, i - 1);
+                    }
+                    regex.append("(?:(?:");
+                    inGroup = true;
+                    break;
+                case '}':
+                    if (inGroup) {
+                        regex.append("))");
+                        inGroup = false;
+                    } else {
+                        regex.append('}');
+                    }
+                    break;
+                case ',':
+                    if (inGroup) {
+                        regex.append(")|(?:");
+                    } else {
+                        regex.append(',');
+                    }
+                    break;
+                case '*':
+                    if (next(globPattern, i) == '*') {
+                        // crosses directory boundaries
+                        regex.append(".*");
+                        i++;
+                    } else {
+                        // within directory boundary
+                        if (isDos) {
+                            regex.append("[^\\\\]*");
+                        } else {
+                            regex.append("[^/]*");
+                        }
+                    }
+                    break;
+                case '?':
+                   if (isDos) {
+                       regex.append("[^\\\\]");
+                   } else {
+                       regex.append("[^/]");
+                   }
+                   break;
+
+                default:
+                    if (isRegexMeta(c)) {
+                        regex.append('\\');
+                    }
+                    regex.append(c);
+            }
+        }
+
+        if (inGroup) {
+            throw new PatternSyntaxException("Missing '}", globPattern, i - 1);
+        }
+
+        return regex.append('$').toString();
+    }
+
+    static String toUnixRegexPattern(String globPattern) {
+        return toRegexPattern(globPattern, false);
+    }
+
+    static String toWindowsRegexPattern(String globPattern) {
+        return toRegexPattern(globPattern, true);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/MimeType.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+/**
+ * Represents a MIME type for the purposes of validation and matching. For
+ * now this class is implemented using the javax.activation.MimeType class but
+ * this dependency can easily be eliminated when required.
+ */
+
+public class MimeType {
+    private final javax.activation.MimeType type;
+
+    private MimeType(javax.activation.MimeType type) {
+        this.type = type;
+    }
+
+    /**
+     * Parses the given string as a MIME type.
+     *
+     * @throws  IllegalArgumentException
+     *          If the string is not a valid MIME type
+     */
+    public static MimeType parse(String type) {
+        try {
+            return new MimeType(new javax.activation.MimeType(type));
+        } catch (javax.activation.MimeTypeParseException x) {
+            throw new IllegalArgumentException(x);
+        }
+    }
+
+    /**
+     * Returns {@code true} if this MIME type has parameters.
+     */
+    public boolean hasParameters() {
+        return !type.getParameters().isEmpty();
+    }
+
+    /**
+     * Matches this MIME type against a given MIME type. This method returns
+     * true if the given string is a MIME type and it matches this type.
+     */
+    public boolean match(String other) {
+        try {
+            return type.match(other);
+        } catch (javax.activation.MimeTypeParseException x) {
+            return false;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/NativeBuffer.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import sun.misc.Unsafe;
+import sun.misc.Cleaner;
+
+/**
+ * A light-weight buffer in native memory.
+ */
+
+class NativeBuffer {
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    private final long address;
+    private final int size;
+    private final Cleaner cleaner;
+
+    // optional "owner" to avoid copying
+    // (only safe for use by thread-local caches)
+    private Object owner;
+
+    private static class Deallocator implements Runnable {
+        private final long address;
+        Deallocator(long address) {
+            this.address = address;
+        }
+        public void run() {
+            unsafe.freeMemory(address);
+        }
+    }
+
+    NativeBuffer(int size) {
+        this.address = unsafe.allocateMemory(size);
+        this.size = size;
+        this.cleaner = Cleaner.create(this, new Deallocator(address));
+    }
+
+    void release() {
+        NativeBuffers.releaseNativeBuffer(this);
+    }
+
+    long address() {
+        return address;
+    }
+
+    int size() {
+        return size;
+    }
+
+    Cleaner cleaner() {
+        return cleaner;
+    }
+
+    // not synchronized; only safe for use by thread-local caches
+    void setOwner(Object owner) {
+        this.owner = owner;
+    }
+
+    // not synchronized; only safe for use by thread-local caches
+    Object owner() {
+        return owner;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/NativeBuffers.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import sun.misc.Unsafe;
+
+/**
+ * Factory for native buffers.
+ */
+
+class NativeBuffers {
+    private NativeBuffers() { }
+
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    private static final int TEMP_BUF_POOL_SIZE = 3;
+    private static ThreadLocal<NativeBuffer[]> threadLocal =
+        new ThreadLocal<NativeBuffer[]>();
+
+    /**
+     * Allocates a native buffer, of at least the given size, from the heap.
+     */
+    static NativeBuffer allocNativeBuffer(int size) {
+        // Make a new one of at least 2k
+        if (size < 2048) size = 2048;
+        return new NativeBuffer(size);
+    }
+
+    /**
+     * Returns a native buffer, of at least the given size, from the thread
+     * local cache.
+     */
+    static NativeBuffer getNativeBufferFromCache(int size) {
+        // return from cache if possible
+        NativeBuffer[] buffers = threadLocal.get();
+        if (buffers != null) {
+            for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
+                NativeBuffer buffer = buffers[i];
+                if (buffer != null && buffer.size() >= size) {
+                    buffers[i] = null;
+                    return buffer;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a native buffer, of at least the given size. The native buffer
+     * is taken from the thread local cache if possible; otherwise it is
+     * allocated from the heap.
+     */
+    static NativeBuffer getNativeBuffer(int size) {
+        NativeBuffer buffer = getNativeBufferFromCache(size);
+        if (buffer != null) {
+            buffer.setOwner(null);
+            return buffer;
+        } else {
+            return allocNativeBuffer(size);
+        }
+    }
+
+    /**
+     * Releases the given buffer. If there is space in the thread local cache
+     * then the buffer goes into the cache; otherwise the memory is deallocated.
+     */
+    static void releaseNativeBuffer(NativeBuffer buffer) {
+        // create cache if it doesn't exist
+        NativeBuffer[] buffers = threadLocal.get();
+        if (buffers == null) {
+            buffers = new NativeBuffer[TEMP_BUF_POOL_SIZE];
+            buffers[0] = buffer;
+            threadLocal.set(buffers);
+            return;
+        }
+        // Put it in an empty slot if such exists
+        for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
+            if (buffers[i] == null) {
+                buffers[i] = buffer;
+                return;
+            }
+        }
+        // Otherwise replace a smaller one in the cache if such exists
+        for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
+            NativeBuffer existing = buffers[i];
+            if (existing.size() < buffer.size()) {
+                existing.cleaner().clean();
+                buffers[i] = buffer;
+                return;
+            }
+        }
+
+        // free it
+        buffer.cleaner().clean();
+    }
+
+    /**
+     * Copies a byte array and zero terminator into a given native buffer.
+     */
+    static void copyCStringToNativeBuffer(byte[] cstr, NativeBuffer buffer) {
+        long offset = Unsafe.ARRAY_BYTE_BASE_OFFSET;
+        long len = cstr.length;
+        assert buffer.size() >= (len + 1);
+        unsafe.copyMemory(cstr, offset, null, buffer.address(), len);
+        unsafe.putByte(buffer.address() + len, (byte)0);
+    }
+
+    /**
+     * Copies a byte array and zero terminator into a native buffer, returning
+     * the buffer.
+     */
+    static NativeBuffer asNativeBuffer(byte[] cstr) {
+        NativeBuffer buffer = getNativeBuffer(cstr.length+1);
+        copyCStringToNativeBuffer(cstr, buffer);
+        return buffer;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/PollingWatchService.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,429 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.*;
+import com.sun.nio.file.SensitivityWatchEventModifier;
+
+/**
+ * Simple WatchService implementation that uses periodic tasks to poll
+ * registered directories for changes.  This implementation is for use on
+ * operating systems that do not have native file change notification support.
+ */
+
+class PollingWatchService
+    extends AbstractWatchService
+{
+    // map of registrations
+    private final Map<Object,PollingWatchKey> map =
+        new HashMap<Object,PollingWatchKey>();
+
+    // used to execute the periodic tasks that poll for changes
+    private final ScheduledExecutorService scheduledExecutor;
+
+    PollingWatchService() {
+        // TBD: Make the number of threads configurable
+        scheduledExecutor = Executors
+            .newSingleThreadScheduledExecutor(new ThreadFactory() {
+                 @Override
+                 public Thread newThread(Runnable r) {
+                     Thread t = new Thread(r);
+                     t.setDaemon(true);
+                     return t;
+                 }});
+    }
+
+    /**
+     * Register the given file with this watch service
+     */
+    @Override
+    WatchKey register(final Path path,
+                      WatchEvent.Kind<?>[] events,
+                      WatchEvent.Modifier... modifiers)
+         throws IOException
+    {
+        // check events - CCE will be thrown if there are invalid elements
+        if (events.length == 0)
+            throw new IllegalArgumentException("No events to register");
+        final Set<WatchEvent.Kind<?>> eventSet =
+            new HashSet<WatchEvent.Kind<?>>(events.length);
+        for (WatchEvent.Kind<?> event: events) {
+            // standard events
+            if (event == StandardWatchEventKind.ENTRY_CREATE ||
+                event == StandardWatchEventKind.ENTRY_MODIFY ||
+                event == StandardWatchEventKind.ENTRY_DELETE)
+            {
+                eventSet.add(event);
+                continue;
+            }
+
+            // OVERFLOW is ignored
+            if (event == StandardWatchEventKind.OVERFLOW) {
+                if (events.length == 1)
+                    throw new IllegalArgumentException("No events to register");
+                continue;
+            }
+
+            // null/unsupported
+            if (event == null)
+                throw new NullPointerException("An element in event set is 'null'");
+            throw new UnsupportedOperationException(event.name());
+        }
+
+        // A modifier may be used to specify the sensitivity level
+        SensitivityWatchEventModifier sensivity = SensitivityWatchEventModifier.MEDIUM;
+        if (modifiers.length > 0) {
+            for (WatchEvent.Modifier modifier: modifiers) {
+                if (modifier == null)
+                    throw new NullPointerException();
+                if (modifier instanceof SensitivityWatchEventModifier) {
+                    sensivity = (SensitivityWatchEventModifier)modifier;
+                    continue;
+                }
+                throw new UnsupportedOperationException("Modifier not supported");
+            }
+        }
+
+        // check if watch service is closed
+        if (!isOpen())
+            throw new ClosedWatchServiceException();
+
+        // registration is done in privileged block as it requires the
+        // attributes of the entries in the directory.
+        try {
+            final SensitivityWatchEventModifier s = sensivity;
+            return AccessController.doPrivileged(
+                new PrivilegedExceptionAction<PollingWatchKey>() {
+                    @Override
+                    public PollingWatchKey run() throws IOException {
+                        return doPrivilegedRegister(path, eventSet, s);
+                    }
+                });
+        } catch (PrivilegedActionException pae) {
+            Throwable cause = pae.getCause();
+            if (cause != null && cause instanceof IOException)
+                throw (IOException)cause;
+            throw new AssertionError(pae);
+        }
+    }
+
+    // registers directory returning a new key if not already registered or
+    // existing key if already registered
+    private PollingWatchKey doPrivilegedRegister(Path path,
+                                                 Set<? extends WatchEvent.Kind<?>> events,
+                                                 SensitivityWatchEventModifier sensivity)
+        throws IOException
+    {
+        // check file is a directory and get its file key if possible
+        BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path);
+        if (!attrs.isDirectory()) {
+            throw new NotDirectoryException(path.toString());
+        }
+        Object fileKey = attrs.fileKey();
+        if (fileKey == null)
+            throw new AssertionError("File keys must be supported");
+
+        // grab close lock to ensure that watch service cannot be closed
+        synchronized (closeLock()) {
+            if (!isOpen())
+                throw new ClosedWatchServiceException();
+
+            PollingWatchKey watchKey;
+            synchronized (map) {
+                watchKey = map.get(fileKey);
+                if (watchKey == null) {
+                    // new registration
+                    watchKey = new PollingWatchKey(this, path, fileKey);
+                    map.put(fileKey, watchKey);
+                } else {
+                    // update to existing registration
+                    watchKey.disable();
+                }
+            }
+            watchKey.enable(events, sensivity.sensitivityValueInSeconds());
+            return watchKey;
+        }
+
+    }
+
+    @Override
+    void implClose() throws IOException {
+        synchronized (map) {
+            for (Map.Entry<Object,PollingWatchKey> entry: map.entrySet()) {
+                PollingWatchKey watchKey = entry.getValue();
+                watchKey.disable();
+                watchKey.invalidate();
+            }
+            map.clear();
+        }
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run() {
+                scheduledExecutor.shutdown();
+                return null;
+            }
+         });
+    }
+
+    /**
+     * Entry in directory cache to record file last-modified-time and tick-count
+     */
+    private static class CacheEntry {
+        private long lastModified;
+        private int lastTickCount;
+
+        CacheEntry(long lastModified, int lastTickCount) {
+            this.lastModified = lastModified;
+            this.lastTickCount = lastTickCount;
+        }
+
+        int lastTickCount() {
+            return lastTickCount;
+        }
+
+        long lastModified() {
+            return lastModified;
+        }
+
+        void update(long lastModified, int tickCount) {
+            this.lastModified = lastModified;
+            this.lastTickCount = tickCount;
+        }
+    }
+
+    /**
+     * WatchKey implementation that encapsulates a map of the entries of the
+     * entries in the directory. Polling the key causes it to re-scan the
+     * 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
+        private Set<? extends WatchEvent.Kind<?>> events;
+
+        // the result of the periodic task that causes this key to be polled
+        private ScheduledFuture<?> poller;
+
+        // indicates if the key is valid
+        private volatile boolean valid;
+
+        // used to detect files that have been deleted
+        private int tickCount;
+
+        // map of entries in directory
+        private Map<Path,CacheEntry> entries;
+
+        PollingWatchKey(PollingWatchService watcher,
+                        Path dir,
+                        Object fileKey)
+            throws IOException
+        {
+            super(watcher);
+            this.dir = dir;
+            this.fileKey = fileKey;
+            this.valid = true;
+            this.tickCount = 0;
+            this.entries = new HashMap<Path,CacheEntry>();
+
+            // get the initial entries in the directory
+            DirectoryStream<Path> stream = dir.newDirectoryStream();
+            try {
+                for (Path entry: stream) {
+                    // don't follow links
+                    long lastModified = Attributes
+                        .readBasicFileAttributes(entry, LinkOption.NOFOLLOW_LINKS)
+                        .lastModifiedTime();
+                    entries.put(entry.getName(),
+                                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();
+            }
+        }
+
+        FileRef directory() {
+            return dir;
+        }
+
+        Object fileKey() {
+            return fileKey;
+        }
+
+        @Override
+        public boolean isValid() {
+            return valid;
+        }
+
+        void invalidate() {
+            valid = false;
+        }
+
+        // enables periodic polling
+        void enable(Set<? extends WatchEvent.Kind<?>> events, long period) {
+            synchronized (this) {
+                // update the events
+                this.events = events;
+
+                // create the periodic task
+                Runnable thunk = new Runnable() { public void run() { poll(); }};
+                this.poller = scheduledExecutor
+                    .scheduleAtFixedRate(thunk, period, period, TimeUnit.SECONDS);
+            }
+        }
+
+        // disables periodic polling
+        void disable() {
+            synchronized (this) {
+                if (poller != null)
+                    poller.cancel(false);
+            }
+        }
+
+        @Override
+        public void cancel() {
+            valid = false;
+            synchronized (map) {
+                map.remove(fileKey());
+            }
+            disable();
+        }
+
+        /**
+         * Polls the directory to detect for new files, modified files, or
+         * deleted files.
+         */
+        synchronized void poll() {
+            if (!valid) {
+                return;
+            }
+
+            // update tick
+            tickCount++;
+
+            // open directory
+            DirectoryStream<Path> stream = null;
+            try {
+                stream = dir.newDirectoryStream();
+            } catch (IOException x) {
+                // directory is no longer accessible so cancel key
+                cancel();
+                signal();
+                return;
+            }
+
+            // iterate over all entries in directory
+            try {
+                for (Path entry: stream) {
+                    long lastModified = 0L;
+                    try {
+                        lastModified = Attributes
+                            .readBasicFileAttributes(entry, LinkOption.NOFOLLOW_LINKS)
+                            .lastModifiedTime();
+                    } catch (IOException x) {
+                        // unable to get attributes of entry. If file has just
+                        // been deleted then we'll report it as deleted on the
+                        // next poll
+                        continue;
+                    }
+
+                    // lookup cache
+                    CacheEntry e = entries.get(entry.getName());
+                    if (e == null) {
+                        // new file found
+                        entries.put(entry.getName(),
+                                     new CacheEntry(lastModified, tickCount));
+
+                        // queue ENTRY_CREATE if event enabled
+                        if (events.contains(StandardWatchEventKind.ENTRY_CREATE)) {
+                            signalEvent(StandardWatchEventKind.ENTRY_CREATE, entry.getName());
+                            continue;
+                        } else {
+                            // if ENTRY_CREATE is not enabled and ENTRY_MODIFY is
+                            // enabled then queue event to avoid missing out on
+                            // modifications to the file immediately after it is
+                            // created.
+                            if (events.contains(StandardWatchEventKind.ENTRY_MODIFY)) {
+                                signalEvent(StandardWatchEventKind.ENTRY_MODIFY, entry.getName());
+                            }
+                        }
+                        continue;
+                    }
+
+                    // check if file has changed
+                    if (e.lastModified != lastModified) {
+                        if (events.contains(StandardWatchEventKind.ENTRY_MODIFY)) {
+                            signalEvent(StandardWatchEventKind.ENTRY_MODIFY, entry.getName());
+                        }
+                    }
+                    // entry in cache so update poll time
+                    e.update(lastModified, tickCount);
+
+                }
+            } catch (ConcurrentModificationException x) {
+                // FIXME - should handle this
+            } finally {
+
+                // close directory stream
+                try {
+                    stream.close();
+                } catch (IOException x) {
+                    // ignore
+                }
+            }
+
+            // iterate over cache to detect entries that have been deleted
+            Iterator<Map.Entry<Path,CacheEntry>> i = entries.entrySet().iterator();
+            while (i.hasNext()) {
+                Map.Entry<Path,CacheEntry> mapEntry = i.next();
+                CacheEntry entry = mapEntry.getValue();
+                if (entry.lastTickCount() != tickCount) {
+                    Path name = mapEntry.getKey();
+                    // remove from map and queue delete event (if enabled)
+                    i.remove();
+                    if (events.contains(StandardWatchEventKind.ENTRY_DELETE)) {
+                        signalEvent(StandardWatchEventKind.ENTRY_DELETE, name);
+                    }
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/fs/Reflect.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.lang.reflect.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Utility class for reflection.
+ */
+
+class Reflect {
+    private Reflect() {}
+
+    private static void setAccessible(final AccessibleObject ao) {
+        AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                @Override
+                public Object run() {
+                    ao.setAccessible(true);
+                    return null;
+                }});
+    }
+
+    /**
+     * Lookup the field of a given class.
+     */
+    static Field lookupField(String className, String fieldName) {
+        try {
+            Class<?> cl = Class.forName(className);
+            Field f = cl.getDeclaredField(fieldName);
+            setAccessible(f);
+            return f;
+        } catch (ClassNotFoundException x) {
+            throw new AssertionError(x);
+        } catch (NoSuchFieldException x) {
+            throw new AssertionError(x);
+        }
+    }
+}
--- a/jdk/src/share/classes/sun/security/util/SecurityConstants.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/classes/sun/security/util/SecurityConstants.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc.  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
@@ -52,6 +52,7 @@
     public static final String FILE_EXECUTE_ACTION = "execute";
     public static final String FILE_READ_ACTION = "read";
     public static final String FILE_WRITE_ACTION = "write";
+    public static final String FILE_READLINK_ACTION = "readlink";
 
     public static final String SOCKET_RESOLVE_ACTION = "resolve";
     public static final String SOCKET_CONNECT_ACTION = "connect";
--- a/jdk/src/share/native/sun/nio/ch/genSocketOptionRegistry.c	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/share/native/sun/nio/ch/genSocketOptionRegistry.c	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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
@@ -71,9 +71,9 @@
     out("class SocketOptionRegistry {                                                   ");
     out("    private SocketOptionRegistry() { }                                         ");
     out("    private static class RegistryKey {                                         ");
-    out("        private final SocketOption name;                                       ");
+    out("        private final SocketOption<?> name;                                    ");
     out("        private final ProtocolFamily family;                                   ");
-    out("        RegistryKey(SocketOption name, ProtocolFamily family) {                ");
+    out("        RegistryKey(SocketOption<?> name, ProtocolFamily family) {                ");
     out("            this.name = name;                                                  ");
     out("            this.family = family;                                              ");
     out("        }                                                                      ");
@@ -119,7 +119,7 @@
     out("            return map;                                                        ");
     out("        }                                                                      ");
     out("    }                                                                          ");
-    out("    public static OptionKey findOption(SocketOption name, ProtocolFamily family) { ");
+    out("    public static OptionKey findOption(SocketOption<?> name, ProtocolFamily family) { ");
     out("        RegistryKey key = new RegistryKey(name, family);                       ");
     out("        return LazyInitialization.options.get(key);                            ");
     out("    }                                                                          ");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/sample/nio/file/AclEdit.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Sun Microsystems nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * Sample utility for editing a file's ACL.
+ */
+
+public class AclEdit {
+
+    // parse string as list of ACE permissions separated by /
+    static Set<AclEntryPermission> parsePermissions(String permsString) {
+        Set<AclEntryPermission> perms = new HashSet<AclEntryPermission>();
+        String[] result = permsString.split("/");
+        for (String s : result) {
+            if (s.equals(""))
+                continue;
+            try {
+                perms.add(AclEntryPermission.valueOf(s.toUpperCase()));
+            } catch (IllegalArgumentException x) {
+                System.err.format("Invalid permission '%s'\n", s);
+                System.exit(-1);
+            }
+        }
+        return perms;
+    }
+
+    // parse string as list of ACE flags separated by /
+    static Set<AclEntryFlag> parseFlags(String flagsString) {
+        Set<AclEntryFlag> flags = new HashSet<AclEntryFlag>();
+        String[] result = flagsString.split("/");
+        for (String s : result) {
+            if (s.equals(""))
+                continue;
+            try {
+                flags.add(AclEntryFlag.valueOf(s.toUpperCase()));
+            } catch (IllegalArgumentException x) {
+                System.err.format("Invalid flag '%s'\n", s);
+                System.exit(-1);
+            }
+        }
+        return flags;
+    }
+
+    // parse ACE type
+    static AclEntryType parseType(String typeString) {
+        // FIXME: support audit and alarm types in the future
+        if (typeString.equalsIgnoreCase("allow"))
+            return AclEntryType.ALLOW;
+        if (typeString.equalsIgnoreCase("deny"))
+            return AclEntryType.DENY;
+        System.err.format("Invalid type '%s'\n", typeString);
+        System.exit(-1);
+        return null;    // keep compiler happy
+    }
+
+    /**
+     * Parse string of the form:
+     *   [user|group:]<username|groupname>:<perms>[:flags]:<allow|deny>
+     */
+    static AclEntry parseAceString(String s,
+                                   UserPrincipalLookupService lookupService)
+    {
+        String[] result = s.split(":");
+
+        // must have at least 3 components (username:perms:type)
+        if (result.length < 3)
+            usage();
+
+        int index = 0;
+        int remaining = result.length;
+
+        // optional first component can indicate user or group type
+        boolean isGroup = false;
+        if (result[index].equalsIgnoreCase("user") ||
+            result[index].equalsIgnoreCase("group"))
+        {
+            if (--remaining < 3)
+                usage();
+            isGroup = result[index++].equalsIgnoreCase("group");
+        }
+
+        // user and permissions required
+        String userString = result[index++]; remaining--;
+        String permsString = result[index++]; remaining--;
+
+        // flags are optional
+        String flagsString = "";
+        String typeString = null;
+        if (remaining == 1) {
+            typeString = result[index++];
+        } else {
+            if (remaining == 2) {
+                flagsString = result[index++];
+                typeString = result[index++];
+            } else {
+                usage();
+            }
+        }
+
+        // lookup UserPrincipal
+        UserPrincipal user = null;
+        try {
+            user = (isGroup) ?
+                lookupService.lookupPrincipalByGroupName(userString) :
+                lookupService.lookupPrincipalByName(userString);
+        } catch (UserPrincipalNotFoundException x) {
+            System.err.format("Invalid %s '%s'\n",
+                ((isGroup) ? "group" : "user"),
+                userString);
+            System.exit(-1);
+        } catch (IOException x) {
+            System.err.format("Lookup of '%s' failed: %s\n", userString, x);
+            System.exit(-1);
+        }
+
+        // map string representation of permissions, flags, and type
+        Set<AclEntryPermission> perms = parsePermissions(permsString);
+        Set<AclEntryFlag> flags = parseFlags(flagsString);
+        AclEntryType type = parseType(typeString);
+
+        // build the ACL entry
+        return AclEntry.newBuilder()
+            .setType(type)
+            .setPrincipal(user)
+            .setPermissions(perms).setFlags(flags).build();
+    }
+
+    static void usage() {
+        System.err.println("usage: java AclEdit [ACL-operation] file");
+        System.err.println("");
+        System.err.println("Example 1: Prepends access control entry to the begining of the myfile's ACL");
+        System.err.println("       java AclEdit A+alice:read_data/read_attributes:allow myfile");
+        System.err.println("");
+        System.err.println("Example 2: Remove the entry at index 6 of myfile's ACL");
+        System.err.println("       java AclEdit A6- myfile");
+        System.err.println("");
+        System.err.println("Example 3: Replace the entry at index 2 of myfile's ACL");
+        System.err.println("       java AclEdit A2=bob:write_data/append_data:deny myfile");
+        System.exit(-1);
+    }
+
+    static enum Action {
+        PRINT,
+        ADD,
+        REMOVE,
+        REPLACE;
+    }
+
+    /**
+     * Main class: parses arguments and prints or edits ACL
+     */
+    public static void main(String[] args) throws IOException {
+        Action action = null;
+        int index = -1;
+        String entryString = null;
+
+        // parse arguments
+        if (args.length < 1 || args[0].equals("-help") || args[0].equals("-?"))
+            usage();
+
+        if (args.length == 1) {
+            action = Action.PRINT;
+        } else {
+            String s = args[0];
+
+            // A[index]+entry
+            if (Pattern.matches("^A[0-9]*\\+.*", s)) {
+                String[] result = s.split("\\+", 2);
+                if (result.length == 2) {
+                    if (result[0].length() < 2) {
+                        index = 0;
+                    } else {
+                        index = Integer.parseInt(result[0].substring(1));
+                    }
+                    entryString = result[1];
+                    action = Action.ADD;
+                }
+            }
+
+            // Aindex-
+            if (Pattern.matches("^A[0-9]+\\-", s)) {
+                String[] result = s.split("\\-", 2);
+                if (result.length == 2) {
+                    index = Integer.parseInt(result[0].substring(1));
+                    entryString = result[1];
+                    action = Action.REMOVE;
+                }
+            }
+
+            // Aindex=entry
+            if (Pattern.matches("^A[0-9]+=.*", s)) {
+                String[] result = s.split("=", 2);
+                if (result.length == 2) {
+                    index = Integer.parseInt(result[0].substring(1));
+                    entryString = result[1];
+                    action = Action.REPLACE;
+                }
+            }
+        }
+        if (action == null)
+            usage();
+
+        int fileArg = (action == Action.PRINT) ? 0 : 1;
+        Path file = Paths.get(args[fileArg]);
+
+        // read file's ACL
+        AclFileAttributeView view =
+            file.getFileAttributeView(AclFileAttributeView.class);
+        if (view == null) {
+            System.err.println("ACLs not supported on this platform");
+            System.exit(-1);
+        }
+        List<AclEntry> acl = view.getAcl();
+
+        switch (action) {
+            // print ACL
+            case PRINT : {
+                for (int i=0; i<acl.size(); i++) {
+                    System.out.format("%5d: %s\n", i, acl.get(i));
+                }
+                break;
+            }
+
+            // add ACE to existing ACL
+            case ADD: {
+                AclEntry entry = parseAceString(entryString, file
+                    .getFileSystem().getUserPrincipalLookupService());
+                if (index >= acl.size()) {
+                    acl.add(entry);
+                } else {
+                    acl.add(index, entry);
+                }
+                view.setAcl(acl);
+                break;
+            }
+
+            // remove ACE
+            case REMOVE: {
+                if (index >= acl.size()) {
+                    System.err.format("Index '%d' is invalid", index);
+                    System.exit(-1);
+                }
+                acl.remove(index);
+                view.setAcl(acl);
+                break;
+            }
+
+            // replace ACE
+            case REPLACE: {
+                if (index >= acl.size()) {
+                    System.err.format("Index '%d' is invalid", index);
+                    System.exit(-1);
+                }
+                AclEntry entry = parseAceString(entryString, file
+                    .getFileSystem().getUserPrincipalLookupService());
+                acl.set(index, entry);
+                view.setAcl(acl);
+                break;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/sample/nio/file/Chmod.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Sun Microsystems nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import static java.nio.file.attribute.PosixFilePermission.*;
+import static java.nio.file.FileVisitResult.*;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Sample code that changes the permissions of files in a similar manner to the
+ * chmod(1) program.
+ */
+
+public class Chmod {
+
+    /**
+     * Compiles a list of one or more <em>symbolic mode expressions</em> that
+     * may be used to change a set of file permissions. This method is
+     * intended for use where file permissions are required to be changed in
+     * a manner similar to the UNIX <i>chmod</i> program.
+     *
+     * <p> The {@code exprs} parameter is a comma separated list of expressions
+     * where each takes the form:
+     * <blockquote>
+     * <i>who operator</i> [<i>permissions</i>]
+     * </blockquote>
+     * where <i>who</i> is one or more of the characters {@code 'u'}, {@code 'g'},
+     * {@code 'o'}, or {@code 'a'} meaning the owner (user), group, others, or
+     * all (owner, group, and others) respectively.
+     *
+     * <p> <i>operator</i> is the character {@code '+'}, {@code '-'}, or {@code
+     * '='} signifying how permissions are to be changed. {@code '+'} means the
+     * permissions are added, {@code '-'} means the permissions are removed, and
+     * {@code '='} means the permissions are assigned absolutely.
+     *
+     * <p> <i>permissions</i> is a sequence of zero or more of the following:
+     * {@code 'r'} for read permission, {@code 'w'} for write permission, and
+     * {@code 'x'} for execute permission. If <i>permissions</i> is omitted
+     * when assigned absolutely, then the permissions are cleared for
+     * the owner, group, or others as identified by <i>who</i>. When omitted
+     * when adding or removing then the expression is ignored.
+     *
+     * <p> The following examples demonstrate possible values for the {@code
+     * exprs} parameter:
+     *
+     * <table border="0">
+     * <tr>
+     *   <td> {@code u=rw} </td>
+     *   <td> Sets the owner permissions to be read and write. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@code ug+w} </td>
+     *   <td> Sets the owner write and group write permissions. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@code u+w,o-rwx} </td>
+     *   <td> Sets the owner write, and removes the others read, others write
+     *     and others execute permissions. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@code o=} </td>
+     *   <td> Sets the others permission to none (others read, others write and
+     *     others execute permissions are removed if set) </td>
+     * </tr>
+     * </table>
+     *
+     * @param   exprs
+     *          List of one or more <em>symbolic mode expressions</em>
+     *
+     * @return  A {@code Changer} that may be used to changer a set of
+     *          file permissions
+     *
+     * @throws  IllegalArgumentException
+     *          If the value of the {@code exprs} parameter is invalid
+     */
+    public static Changer compile(String exprs) {
+        // minimum is who and operator (u= for example)
+        if (exprs.length() < 2)
+            throw new IllegalArgumentException("Invalid mode");
+
+        // permissions that the changer will add or remove
+        final Set<PosixFilePermission> toAdd = new HashSet<PosixFilePermission>();
+        final Set<PosixFilePermission> toRemove = new HashSet<PosixFilePermission>();
+
+        // iterate over each of expression modes
+        for (String expr: exprs.split(",")) {
+            // minimum of who and operator
+            if (expr.length() < 2)
+                throw new IllegalArgumentException("Invalid mode");
+
+            int pos = 0;
+
+            // who
+            boolean u = false;
+            boolean g = false;
+            boolean o = false;
+            boolean done = false;
+            for (;;) {
+                switch (expr.charAt(pos)) {
+                    case 'u' : u = true; break;
+                    case 'g' : g = true; break;
+                    case 'o' : o = true; break;
+                    case 'a' : u = true; g = true; o = true; break;
+                    default : done = true;
+                }
+                if (done)
+                    break;
+                pos++;
+            }
+            if (!u && !g && !o)
+                throw new IllegalArgumentException("Invalid mode");
+
+            // get operator and permissions
+            char op = expr.charAt(pos++);
+            String mask = (expr.length() == pos) ? "" : expr.substring(pos);
+
+            // operator
+            boolean add = (op == '+');
+            boolean remove = (op == '-');
+            boolean assign = (op == '=');
+            if (!add && !remove && !assign)
+                throw new IllegalArgumentException("Invalid mode");
+
+            // who= means remove all
+            if (assign && mask.length() == 0) {
+                assign = false;
+                remove = true;
+                mask = "rwx";
+            }
+
+            // permissions
+            boolean r = false;
+            boolean w = false;
+            boolean x = false;
+            for (int i=0; i<mask.length(); i++) {
+                switch (mask.charAt(i)) {
+                    case 'r' : r = true; break;
+                    case 'w' : w = true; break;
+                    case 'x' : x = true; break;
+                    default:
+                        throw new IllegalArgumentException("Invalid mode");
+                }
+            }
+
+            // update permissions set
+            if (add) {
+                if (u) {
+                    if (r) toAdd.add(OWNER_READ);
+                    if (w) toAdd.add(OWNER_WRITE);
+                    if (x) toAdd.add(OWNER_EXECUTE);
+                }
+                if (g) {
+                    if (r) toAdd.add(GROUP_READ);
+                    if (w) toAdd.add(GROUP_WRITE);
+                    if (x) toAdd.add(GROUP_EXECUTE);
+                }
+                if (o) {
+                    if (r) toAdd.add(OTHERS_READ);
+                    if (w) toAdd.add(OTHERS_WRITE);
+                    if (x) toAdd.add(OTHERS_EXECUTE);
+                }
+            }
+            if (remove) {
+                if (u) {
+                    if (r) toRemove.add(OWNER_READ);
+                    if (w) toRemove.add(OWNER_WRITE);
+                    if (x) toRemove.add(OWNER_EXECUTE);
+                }
+                if (g) {
+                    if (r) toRemove.add(GROUP_READ);
+                    if (w) toRemove.add(GROUP_WRITE);
+                    if (x) toRemove.add(GROUP_EXECUTE);
+                }
+                if (o) {
+                    if (r) toRemove.add(OTHERS_READ);
+                    if (w) toRemove.add(OTHERS_WRITE);
+                    if (x) toRemove.add(OTHERS_EXECUTE);
+                }
+            }
+            if (assign) {
+                if (u) {
+                    if (r) toAdd.add(OWNER_READ);
+                      else toRemove.add(OWNER_READ);
+                    if (w) toAdd.add(OWNER_WRITE);
+                      else toRemove.add(OWNER_WRITE);
+                    if (x) toAdd.add(OWNER_EXECUTE);
+                      else toRemove.add(OWNER_EXECUTE);
+                }
+                if (g) {
+                    if (r) toAdd.add(GROUP_READ);
+                      else toRemove.add(GROUP_READ);
+                    if (w) toAdd.add(GROUP_WRITE);
+                      else toRemove.add(GROUP_WRITE);
+                    if (x) toAdd.add(GROUP_EXECUTE);
+                      else toRemove.add(GROUP_EXECUTE);
+                }
+                if (o) {
+                    if (r) toAdd.add(OTHERS_READ);
+                      else toRemove.add(OTHERS_READ);
+                    if (w) toAdd.add(OTHERS_WRITE);
+                      else toRemove.add(OTHERS_WRITE);
+                    if (x) toAdd.add(OTHERS_EXECUTE);
+                      else toRemove.add(OTHERS_EXECUTE);
+                }
+            }
+        }
+
+        // return changer
+        return new Changer() {
+            @Override
+            public Set<PosixFilePermission> change(Set<PosixFilePermission> perms) {
+                perms.addAll(toAdd);
+                perms.removeAll(toRemove);
+                return perms;
+            }
+        };
+    }
+
+    /**
+     * A task that <i>changes</i> a set of {@link PosixFilePermission} elements.
+     */
+    public interface Changer {
+        /**
+         * Applies the changes to the given set of permissions.
+         *
+         * @param   perms
+         *          The set of permissions to change
+         *
+         * @return  The {@code perms} parameter
+         */
+        Set<PosixFilePermission> change(Set<PosixFilePermission> perms);
+    }
+
+    /**
+     * Changes the permissions of the file using the given Changer.
+     */
+    static void chmod(FileRef file, Changer changer) {
+        try {
+            Set<PosixFilePermission> perms = Attributes
+                .readPosixFileAttributes(file).permissions();
+            Attributes.setPosixFilePermissions(file, changer.change(perms));
+        } catch (IOException x) {
+            System.err.println(x);
+        }
+    }
+
+    /**
+     * Changes the permission of each file and directory visited
+     */
+    static class TreeVisitor implements FileVisitor<FileRef> {
+        private final Changer changer;
+
+        TreeVisitor(Changer changer) {
+            this.changer = changer;
+        }
+
+        @Override
+        public FileVisitResult preVisitDirectory(FileRef dir) {
+            chmod(dir, changer);
+            return CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult preVisitDirectoryFailed(FileRef dir, IOException exc) {
+            System.err.println("WARNING: " + exc);
+            return CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult visitFile(FileRef file, BasicFileAttributes attrs) {
+            chmod(file, changer);
+            return CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult postVisitDirectory(FileRef dir, IOException exc) {
+            if (exc != null)
+                System.err.println("WARNING: " + exc);
+            return CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult visitFileFailed(FileRef file, IOException exc) {
+            System.err.println("WARNING: " + exc);
+            return CONTINUE;
+        }
+    }
+
+    static void usage() {
+        System.err.println("java Chmod [-R] symbolic-mode-list file...");
+        System.exit(-1);
+    }
+
+    public static void main(String[] args) throws IOException {
+        if (args.length < 2)
+            usage();
+        int argi = 0;
+        int maxDepth = 0;
+        if (args[argi].equals("-R")) {
+            if (args.length < 3)
+                usage();
+            argi++;
+            maxDepth = Integer.MAX_VALUE;
+        }
+
+        // compile the symbolic mode expressions
+        Changer changer = compile(args[argi++]);
+        TreeVisitor visitor = new TreeVisitor(changer);
+
+        Set<FileVisitOption> opts = Collections.emptySet();
+        while (argi < args.length) {
+            Path file = Paths.get(args[argi]);
+            Files.walkFileTree(file, opts, maxDepth, visitor);
+            argi++;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/sample/nio/file/Copy.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Sun Microsystems nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.nio.file.*;
+import static java.nio.file.StandardCopyOption.*;
+import java.nio.file.attribute.*;
+import static java.nio.file.FileVisitResult.*;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Sample code that copies files in a similar manner to the cp(1) program.
+ */
+
+public class Copy {
+
+    /**
+     * Returns {@code true} if okay to overwrite a  file ("cp -i")
+     */
+    static boolean okayToOverwrite(FileRef file) {
+        String answer = System.console().readLine("overwrite %s (yes/no)? ", file);
+        return (answer.equalsIgnoreCase("y") || answer.equalsIgnoreCase("yes"));
+    }
+
+    /**
+     * Copy source file to target location. If {@code prompt} is true then
+     * prompted user to overwrite target if it exists. The {@code preserve}
+     * parameter determines if file attributes should be copied/preserved.
+     */
+    static void copyFile(Path source, Path target, boolean prompt, boolean preserve) {
+        CopyOption[] options = (preserve) ?
+            new CopyOption[] { COPY_ATTRIBUTES, REPLACE_EXISTING } :
+            new CopyOption[] { REPLACE_EXISTING };
+        if (!prompt || target.notExists() || okayToOverwrite(target)) {
+            try {
+                source.copyTo(target, options);
+            } catch (IOException x) {
+                System.err.format("Unable to create: %s: %s%n", target, x);
+            }
+        }
+    }
+
+    /**
+     * A {@code FileVisitor} that copies a file-tree ("cp -r")
+     */
+    static class TreeCopier implements FileVisitor<Path> {
+        private final Path source;
+        private final Path target;
+        private final boolean prompt;
+        private final boolean preserve;
+
+        TreeCopier(Path source, Path target, boolean prompt, boolean preserve) {
+            this.source = source;
+            this.target = target;
+            this.prompt = prompt;
+            this.preserve = preserve;
+        }
+
+        @Override
+        public FileVisitResult preVisitDirectory(Path dir) {
+            // before visiting entries in a directory we copy the directory
+            // (okay if directory already exists).
+            CopyOption[] options = (preserve) ?
+                new CopyOption[] { COPY_ATTRIBUTES } : new CopyOption[0];
+
+            Path newdir = target.resolve(source.relativize(dir));
+            try {
+                dir.copyTo(newdir, options);
+            } catch (FileAlreadyExistsException x) {
+                // ignore
+            } catch (IOException x) {
+                System.err.format("Unable to create: %s: %s%n", newdir, x);
+                return SKIP_SUBTREE;
+            }
+            return CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult preVisitDirectoryFailed(Path dir, IOException exc) {
+            System.err.format("Unable to copy: %s: %s%n", dir, exc);
+            return CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+            if (attrs.isDirectory()) {
+                System.err.println("cycle detected: " + file);
+            } else {
+                copyFile(file, target.resolve(source.relativize(file)),
+                         prompt, preserve);
+            }
+            return CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
+            // fix up modification time of directory when done
+            if (exc == null && preserve) {
+                try {
+                    BasicFileAttributes attrs = Attributes.readBasicFileAttributes(dir);
+                    Path newdir = target.resolve(source.relativize(dir));
+                    Attributes.setLastModifiedTime(newdir,
+                        attrs.lastModifiedTime(), attrs.resolution());
+                } catch (IOException x) {
+                    // ignore
+                }
+            }
+            return CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult visitFileFailed(Path file, IOException exc) {
+            System.err.format("Unable to copy: %s: %s%n", file, exc);
+            return CONTINUE;
+        }
+    }
+
+    static void usage() {
+        System.err.println("java Copy [-ip] source... target");
+        System.err.println("java Copy -r [-ip] source-dir... target");
+        System.exit(-1);
+    }
+
+    public static void main(String[] args) throws IOException {
+        boolean recursive = false;
+        boolean prompt = false;
+        boolean preserve = false;
+
+        // process options
+        int argi = 0;
+        while (argi < args.length) {
+            String arg = args[argi];
+            if (!arg.startsWith("-"))
+                break;
+            if (arg.length() < 2)
+                usage();
+            for (int i=1; i<arg.length(); i++) {
+                char c = arg.charAt(i);
+                switch (c) {
+                    case 'r' : recursive = true; break;
+                    case 'i' : prompt = true; break;
+                    case 'p' : preserve = true; break;
+                    default : usage();
+                }
+            }
+            argi++;
+        }
+
+        // remaining arguments are the source files(s) and the target location
+        int remaining = args.length - argi;
+        if (remaining < 2)
+            usage();
+        Path[] source = new Path[remaining-1];
+        int i=0;
+        while (remaining > 1) {
+            source[i++] = Paths.get(args[argi++]);
+            remaining--;
+        }
+        Path target = Paths.get(args[argi]);
+
+        // check if target is a directory
+        boolean isDir = false;
+        try {
+            isDir = Attributes.readBasicFileAttributes(target).isDirectory();
+        } catch (IOException x) {
+        }
+
+        // copy each source file/directory to target
+        for (i=0; i<source.length; i++) {
+            Path dest = (isDir) ? target.resolve(source[i].getName()) : target;
+
+            if (recursive) {
+                // follow links when copying files
+                EnumSet<FileVisitOption> opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
+                TreeCopier tc = new TreeCopier(source[i], dest, prompt, preserve);
+                Files.walkFileTree(source[i], opts, -1, tc);
+            } else {
+                // not recursive so source must not be a directory
+                try {
+                    if (Attributes.readBasicFileAttributes(source[i]).isDirectory()) {
+                        System.err.format("%s: is a directory%n", source[i]);
+                        continue;
+                    }
+                } catch (IOException x) { }
+                copyFile(source[i], dest, prompt, preserve);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/sample/nio/file/DiskUsage.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Sun Microsystems nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+
+/**
+ * Example utility that works like the df(1M) program to print out disk space
+ * information
+ */
+
+public class DiskUsage {
+
+    static final long K = 1024;
+
+    static void printFileStore(FileStore store) throws IOException {
+        FileStoreSpaceAttributes attrs = Attributes.readFileStoreSpaceAttributes(store);
+
+        long total = attrs.totalSpace() / K;
+        long used = (attrs.totalSpace() - attrs.unallocatedSpace()) / K;
+        long avail = attrs.usableSpace() / K;
+
+        String s = store.toString();
+        if (s.length() > 20) {
+            System.out.println(s);
+            s = "";
+        }
+        System.out.format("%-20s %12d %12d %12d\n", s, total, used, avail);
+    }
+
+    public static void main(String[] args) throws IOException {
+        System.out.format("%-20s %12s %12s %12s\n", "Filesystem", "kbytes", "used", "avail");
+        if (args.length == 0) {
+            FileSystem fs = FileSystems.getDefault();
+            for (FileStore store: fs.getFileStores()) {
+                printFileStore(store);
+            }
+        } else {
+            for (String file: args) {
+                FileStore store = Paths.get(file).getFileStore();
+                printFileStore(store);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/sample/nio/file/FileType.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Sun Microsystems nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+
+public class FileType {
+    public static void main(String[] args) throws IOException {
+        if (args.length == 0) {
+            System.err.println("usage: java FileType file...");
+            System.exit(-1);
+        }
+        for (String arg: args) {
+            Path file = Paths.get(arg);
+            BasicFileAttributes attrs = Attributes.readBasicFileAttributes(file);
+
+            String type;
+            if (attrs.isDirectory()) {
+                type = "directory";
+            } else {
+                type = Files.probeContentType(file);
+                if (type == null)
+                    type = "<not recognized>";
+            }
+            System.out.format("%s\t%s%n", file, type);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/sample/nio/file/WatchDir.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Sun Microsystems nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.nio.file.*;
+import static java.nio.file.StandardWatchEventKind.*;
+import static java.nio.file.LinkOption.*;
+import java.nio.file.attribute.*;
+import java.io.*;
+import java.util.*;
+
+/**
+ * Example to watch a directory (or tree) for changes to files.
+ */
+
+public class WatchDir {
+
+    private final WatchService watcher;
+    private final Map<WatchKey,Path> keys;
+    private final boolean recursive;
+    private boolean trace = false;
+
+    @SuppressWarnings("unchecked")
+    static <T> WatchEvent<T> cast(WatchEvent<?> event) {
+        return (WatchEvent<T>)event;
+    }
+
+    /**
+     * Register the given directory with the WatchService
+     */
+    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);
+            if (prev == null) {
+                System.out.format("register: %s\n", dir);
+            } else {
+                if (!dir.equals(prev)) {
+                    System.out.format("update: %s -> %s\n", prev, dir);
+                }
+            }
+        }
+        keys.put(key, dir);
+    }
+
+    /**
+     * Register the given directory, and all its sub-directories, with the
+     * WatchService.
+     */
+    private void registerAll(final Path start) throws IOException {
+        // register directory and sub-directories
+        Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult preVisitDirectory(Path dir) {
+                try {
+                    register(dir);
+                } catch (IOException x) {
+                    throw new IOError(x);
+                }
+                return FileVisitResult.CONTINUE;
+            }
+        });
+    }
+
+    /**
+     * Creates a WatchService and registers the given directory
+     */
+    WatchDir(Path dir, boolean recursive) throws IOException {
+        this.watcher = FileSystems.getDefault().newWatchService();
+        this.keys = new HashMap<WatchKey,Path>();
+        this.recursive = recursive;
+
+        if (recursive) {
+            System.out.format("Scanning %s ...\n", dir);
+            registerAll(dir);
+            System.out.println("Done.");
+        } else {
+            register(dir);
+        }
+
+        // enable trace after initial registration
+        this.trace = true;
+    }
+
+    /**
+     * Process all events for keys queued to the watcher
+     */
+    void processEvents() {
+        for (;;) {
+
+            // wait for key to be signalled
+            WatchKey key;
+            try {
+                key = watcher.take();
+            } catch (InterruptedException x) {
+                return;
+            }
+
+            Path dir = keys.get(key);
+            if (dir == null) {
+                System.err.println("WatchKey not recognized!!");
+                continue;
+            }
+
+            for (WatchEvent<?> event: key.pollEvents()) {
+                WatchEvent.Kind kind = event.kind();
+
+                // TBD - provide example of how OVERFLOW event is handled
+                if (kind == OVERFLOW) {
+                    continue;
+                }
+
+                // Context for directory entry event is the file name of entry
+                WatchEvent<Path> ev = cast(event);
+                Path name = ev.context();
+                Path child = dir.resolve(name);
+
+                // print out event
+                System.out.format("%s: %s\n", event.kind().name(), child);
+
+                // if directory is created, and watching recursively, then
+                // register it and its sub-directories
+                if (recursive && (kind == ENTRY_CREATE)) {
+                    try {
+                        if (Attributes.readBasicFileAttributes(child, NOFOLLOW_LINKS).isDirectory()) {
+                            registerAll(child);
+                        }
+                    } catch (IOException x) {
+                        // ignore to keep sample readbale
+                    }
+                }
+            }
+
+            // reset key and remove from set if directory no longer accessible
+            boolean valid = key.reset();
+            if (!valid) {
+                keys.remove(key);
+
+                // all directories are inaccessible
+                if (keys.isEmpty()) {
+                    break;
+                }
+            }
+        }
+    }
+
+    static void usage() {
+        System.err.println("usage: java WatchDir [-r] dir");
+        System.exit(-1);
+    }
+
+    public static void main(String[] args) throws IOException {
+        // parse arguments
+        if (args.length == 0 || args.length > 2)
+            usage();
+        boolean recursive = false;
+        int dirArg = 0;
+        if (args[0].equals("-r")) {
+            if (args.length < 2)
+                usage();
+            recursive = true;
+            dirArg++;
+        }
+
+        // register directory and process its events
+        Path dir = Paths.get(args[dirArg]);
+        new WatchDir(dir, recursive).processEvents();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/sample/nio/file/Xdd.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Sun Microsystems nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+
+/**
+ * Example code to list/set/get/delete the user-defined attributes of a file.
+ */
+
+public class Xdd {
+
+    static void usage() {
+        System.out.println("Usage: java Xdd <file>");
+        System.out.println("       java Xdd -set <name>=<value> <file>");
+        System.out.println("       java Xdd -get <name> <file>");
+        System.out.println("       java Xdd -del <name> <file>");
+        System.exit(-1);
+    }
+
+    public static void main(String[] args) throws IOException {
+        // one or three parameters
+        if (args.length != 1 && args.length != 3)
+            usage();
+
+        Path file = (args.length == 1) ?
+            Paths.get(args[0]) : Paths.get(args[2]);
+
+        // check that user defined attributes are supported by the file system
+        FileStore store = file.getFileStore();
+        if (!store.supportsFileAttributeView("xattr")) {
+            System.err.format("UserDefinedFileAttributeView not supported on %s\n", store);
+            System.exit(-1);
+
+        }
+        UserDefinedFileAttributeView view = file.
+            getFileAttributeView(UserDefinedFileAttributeView.class);
+
+        // list user defined attributes
+        if (args.length == 1) {
+            System.out.println("    Size  Name");
+            System.out.println("--------  --------------------------------------");
+            for (String name: view.list()) {
+                System.out.format("%8d  %s\n", view.size(name), name);
+            }
+            return;
+        }
+
+        // Add/replace a file's user defined attribute
+        if (args[0].equals("-set")) {
+            // name=value
+            String[] s = args[1].split("=");
+            if (s.length != 2)
+                usage();
+            String name = s[0];
+            String value = s[1];
+            view.write(name, Charset.defaultCharset().encode(value));
+            return;
+        }
+
+        // Print out the value of a file's user defined attribute
+        if (args[0].equals("-get")) {
+            String name = args[1];
+            int size = view.size(name);
+            ByteBuffer buf = ByteBuffer.allocateDirect(size);
+            view.read(name, buf);
+            buf.flip();
+            System.out.println(Charset.defaultCharset().decode(buf).toString());
+            return;
+        }
+
+        // Delete a file's user defined attribute
+        if (args[0].equals("-del")) {
+            view.delete(args[1]);
+            return;
+        }
+
+        // option not recognized
+        usage();
+    }
+ }
--- a/jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2001-2009 Sun Microsystems, Inc.  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
@@ -56,11 +56,11 @@
     }
 
     void close(FileDescriptor fd) throws IOException {
-        FileDispatcher.close0(fd);
+        FileDispatcherImpl.close0(fd);
     }
 
     void preClose(FileDescriptor fd) throws IOException {
-        FileDispatcher.preClose0(fd);
+        FileDispatcherImpl.preClose0(fd);
     }
 
     static native int read0(FileDescriptor fd, long address, int len)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.security.AccessController;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * Creates this platform's default asynchronous channel provider
+ */
+
+public class DefaultAsynchronousChannelProvider {
+
+    /**
+     * Prevent instantiation.
+     */
+    private DefaultAsynchronousChannelProvider() { }
+
+    /**
+     * Returns the default AsynchronousChannelProvider.
+     */
+    public static AsynchronousChannelProvider create() {
+        String osname = AccessController
+            .doPrivileged(new GetPropertyAction("os.name"));
+        if (osname.equals("SunOS"))
+            return new SolarisAsynchronousChannelProvider();
+        if (osname.equals("Linux"))
+            return new LinuxAsynchronousChannelProvider();
+        throw new InternalError("platform not recognized");
+    }
+
+}
--- a/jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2001-2009 Sun Microsystems, Inc.  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
@@ -172,7 +172,7 @@
     }
 
     void closeDevPollFD() throws IOException {
-        FileDispatcher.closeIntFD(wfd);
+        FileDispatcherImpl.closeIntFD(wfd);
         pollArray.free();
     }
 
--- a/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2001-2009 Sun Microsystems, Inc.  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
@@ -139,8 +139,8 @@
             interruptTriggered = true;
         }
 
-        FileDispatcher.closeIntFD(fd0);
-        FileDispatcher.closeIntFD(fd1);
+        FileDispatcherImpl.closeIntFD(fd0);
+        FileDispatcherImpl.closeIntFD(fd1);
 
         pollWrapper.release(fd0);
         pollWrapper.closeDevPollFD();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/EPoll.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import sun.misc.Unsafe;
+
+/**
+ * Provides access to the Linux epoll facility.
+ */
+
+class EPoll {
+    private EPoll() { }
+
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    /**
+     * typedef union epoll_data {
+     *     void *ptr;
+     *     int fd;
+     *     __uint32_t u32;
+     *     __uint64_t u64;
+     *  } epoll_data_t;
+     *
+     * struct epoll_event {
+     *     __uint32_t events;
+     *     epoll_data_t data;
+     * }
+     */
+    private static final int SIZEOF_EPOLLEVENT   = eventSize();
+    private static final int OFFSETOF_EVENTS     = eventsOffset();
+    private static final int OFFSETOF_FD         = dataOffset();
+
+    // opcodes
+    static final int EPOLL_CTL_ADD  = 1;
+    static final int EPOLL_CTL_DEL  = 2;
+    static final int EPOLL_CTL_MOD  = 3;
+
+    // flags
+    static final int EPOLLONESHOT   = (1 << 30);
+
+    /**
+     * Allocates a poll array to handle up to {@code count} events.
+     */
+    static long allocatePollArray(int count) {
+        return unsafe.allocateMemory(count * SIZEOF_EPOLLEVENT);
+    }
+
+    /**
+     * Free a poll array
+     */
+    static void freePollArray(long address) {
+        unsafe.freeMemory(address);
+    }
+
+    /**
+     * Returns event[i];
+     */
+    static long getEvent(long address, int i) {
+        return address + (SIZEOF_EPOLLEVENT*i);
+    }
+
+    /**
+     * Returns event->data.fd
+     */
+    static int getDescriptor(long eventAddress) {
+        return unsafe.getInt(eventAddress + OFFSETOF_FD);
+    }
+
+    /**
+     * Returns event->events
+     */
+    static int getEvents(long eventAddress) {
+        return unsafe.getInt(eventAddress + OFFSETOF_EVENTS);
+    }
+
+    // -- Native methods --
+
+    private static native void init();
+
+    private static native int eventSize();
+
+    private static native int eventsOffset();
+
+    private static native int dataOffset();
+
+    static native int epollCreate() throws IOException;
+
+    static native int epollCtl(int epfd, int opcode, int fd, int events);
+
+    static native int epollWait(int epfd, long pollAddress, int numfds)
+        throws IOException;
+
+    static {
+        Util.load();
+        init();
+    }
+}
--- a/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2005-2009 Sun Microsystems, Inc.  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
@@ -224,7 +224,7 @@
      * Close epoll file descriptor and free poll array
      */
     void closeEPollFD() throws IOException {
-        FileDispatcher.closeIntFD(epfd);
+        FileDispatcherImpl.closeIntFD(epfd);
         pollArray.free();
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/EPollPort.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.io.IOException;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.atomic.AtomicInteger;
+import static sun.nio.ch.EPoll.*;
+
+/**
+ * AsynchronousChannelGroup implementation based on the Linux epoll facility.
+ */
+
+final class EPollPort
+    extends Port
+{
+    // maximum number of events to poll at a time
+    private static final int MAX_EPOLL_EVENTS = 512;
+
+    // errors
+    private static final int ENOENT     = 2;
+
+    // epoll file descriptor
+    private final int epfd;
+
+    // true if epoll closed
+    private boolean closed;
+
+    // socket pair used for wakeup
+    private final int sp[];
+
+    // number of wakeups pending
+    private final AtomicInteger wakeupCount = new AtomicInteger();
+
+    // address of the poll array passed to epoll_wait
+    private final long address;
+
+    // encapsulates an event for a channel
+    static class Event {
+        final PollableChannel channel;
+        final int events;
+
+        Event(PollableChannel channel, int events) {
+            this.channel = channel;
+            this.events = events;
+        }
+
+        PollableChannel channel()   { return channel; }
+        int events()                { return events; }
+    }
+
+    // queue of events for cases that a polling thread dequeues more than one
+    // event
+    private final ArrayBlockingQueue<Event> queue;
+    private final Event NEED_TO_POLL = new Event(null, 0);
+    private final Event EXECUTE_TASK_OR_SHUTDOWN = new Event(null, 0);
+
+    EPollPort(AsynchronousChannelProvider provider, ThreadPool pool)
+        throws IOException
+    {
+        super(provider, pool);
+
+        // open epoll
+        this.epfd = epollCreate();
+
+        // create socket pair for wakeup mechanism
+        int[] sv = new int[2];
+        try {
+            socketpair(sv);
+            // register one end with epoll
+            epollCtl(epfd, EPOLL_CTL_ADD, sv[0], POLLIN);
+        } catch (IOException x) {
+            close0(epfd);
+            throw x;
+        }
+        this.sp = sv;
+
+        // allocate the poll array
+        this.address = allocatePollArray(MAX_EPOLL_EVENTS);
+
+        // create the queue and offer the special event to ensure that the first
+        // threads polls
+        this.queue = new ArrayBlockingQueue<Event>(MAX_EPOLL_EVENTS);
+        this.queue.offer(NEED_TO_POLL);
+    }
+
+    EPollPort start() {
+        startThreads(new EventHandlerTask());
+        return this;
+    }
+
+    /**
+     * Release all resources
+     */
+    private void implClose() {
+        synchronized (this) {
+            if (closed)
+                return;
+            closed = true;
+        }
+        freePollArray(address);
+        close0(sp[0]);
+        close0(sp[1]);
+        close0(epfd);
+    }
+
+    private void wakeup() {
+        if (wakeupCount.incrementAndGet() == 1) {
+            // write byte to socketpair to force wakeup
+            try {
+                interrupt(sp[1]);
+            } catch (IOException x) {
+                throw new AssertionError(x);
+            }
+        }
+    }
+
+    @Override
+    void executeOnHandlerTask(Runnable task) {
+        synchronized (this) {
+            if (closed)
+                throw new RejectedExecutionException();
+            offerTask(task);
+            wakeup();
+        }
+    }
+
+    @Override
+    void shutdownHandlerTasks() {
+        /*
+         * If no tasks are running then just release resources; otherwise
+         * write to the one end of the socketpair to wakeup any polling threads.
+         */
+        int nThreads = threadCount();
+        if (nThreads == 0) {
+            implClose();
+        } else {
+            // send interrupt to each thread
+            while (nThreads-- > 0) {
+                wakeup();
+            }
+        }
+    }
+
+    // invoke by clients to register a file descriptor
+    @Override
+    void startPoll(int fd, int events) {
+        // update events (or add to epoll on first usage)
+        int err = epollCtl(epfd, EPOLL_CTL_MOD, fd, (events | EPOLLONESHOT));
+        if (err == ENOENT)
+            err = epollCtl(epfd, EPOLL_CTL_ADD, fd, (events | EPOLLONESHOT));
+        if (err != 0)
+            throw new AssertionError();     // should not happen
+    }
+
+    /*
+     * Task to process events from epoll and dispatch to the channel's
+     * onEvent handler.
+     *
+     * Events are retreived from epoll in batch and offered to a BlockingQueue
+     * where they are consumed by handler threads. A special "NEED_TO_POLL"
+     * event is used to signal one consumer to re-poll when all events have
+     * been consumed.
+     */
+    private class EventHandlerTask implements Runnable {
+        private Event poll() throws IOException {
+            try {
+                for (;;) {
+                    int n = epollWait(epfd, address, MAX_EPOLL_EVENTS);
+                    /*
+                     * 'n' events have been read. Here we map them to their
+                     * corresponding channel in batch and queue n-1 so that
+                     * they can be handled by other handler threads. The last
+                     * event is handled by this thread (and so is not queued).
+                     */
+                    fdToChannelLock.readLock().lock();
+                    try {
+                        while (n-- > 0) {
+                            long eventAddress = getEvent(address, n);
+                            int fd = getDescriptor(eventAddress);
+
+                            // wakeup
+                            if (fd == sp[0]) {
+                                if (wakeupCount.decrementAndGet() == 0) {
+                                    // no more wakeups so drain pipe
+                                    drain1(sp[0]);
+                                }
+
+                                // queue special event if there are more events
+                                // to handle.
+                                if (n > 0) {
+                                    queue.offer(EXECUTE_TASK_OR_SHUTDOWN);
+                                    continue;
+                                }
+                                return EXECUTE_TASK_OR_SHUTDOWN;
+                            }
+
+                            PollableChannel channel = fdToChannel.get(fd);
+                            if (channel != null) {
+                                int events = getEvents(eventAddress);
+                                Event ev = new Event(channel, events);
+
+                                // n-1 events are queued; This thread handles
+                                // the last one except for the wakeup
+                                if (n > 0) {
+                                    queue.offer(ev);
+                                } else {
+                                    return ev;
+                                }
+                            }
+                        }
+                    } finally {
+                        fdToChannelLock.readLock().unlock();
+                    }
+                }
+            } finally {
+                // to ensure that some thread will poll when all events have
+                // been consumed
+                queue.offer(NEED_TO_POLL);
+            }
+        }
+
+        public void run() {
+            Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
+                Invoker.getGroupAndInvokeCount();
+            boolean replaceMe = false;
+            Event ev;
+            try {
+                for (;;) {
+                    // reset invoke count
+                    if (myGroupAndInvokeCount != null)
+                        myGroupAndInvokeCount.resetInvokeCount();
+
+                    try {
+                        replaceMe = false;
+                        ev = queue.take();
+
+                        // no events and this thread has been "selected" to
+                        // poll for more.
+                        if (ev == NEED_TO_POLL) {
+                            try {
+                                ev = poll();
+                            } catch (IOException x) {
+                                x.printStackTrace();
+                                return;
+                            }
+                        }
+                    } catch (InterruptedException x) {
+                        continue;
+                    }
+
+                    // handle wakeup to execute task or shutdown
+                    if (ev == EXECUTE_TASK_OR_SHUTDOWN) {
+                        Runnable task = pollTask();
+                        if (task == null) {
+                            // shutdown request
+                            return;
+                        }
+                        // run task (may throw error/exception)
+                        replaceMe = true;
+                        task.run();
+                        continue;
+                    }
+
+                    // process event
+                    try {
+                        ev.channel().onEvent(ev.events());
+                    } catch (Error x) {
+                        replaceMe = true; throw x;
+                    } catch (RuntimeException x) {
+                        replaceMe = true; throw x;
+                    }
+                }
+            } finally {
+                // last handler to exit when shutdown releases resources
+                int remaining = threadExit(this, replaceMe);
+                if (remaining == 0 && isShutdown()) {
+                    implClose();
+                }
+            }
+        }
+    }
+
+    // -- Native methods --
+
+    private static native void socketpair(int[] sv) throws IOException;
+
+    private static native void interrupt(int fd) throws IOException;
+
+    private static native void drain1(int fd) throws IOException;
+
+    private static native void close0(int fd);
+
+    static {
+        Util.load();
+    }
+}
--- a/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2005-2009 Sun Microsystems, Inc.  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
@@ -136,8 +136,8 @@
             interruptTriggered = true;
         }
 
-        FileDispatcher.closeIntFD(fd0);
-        FileDispatcher.closeIntFD(fd1);
+        FileDispatcherImpl.closeIntFD(fd0);
+        FileDispatcherImpl.closeIntFD(fd1);
 
         pollWrapper.release(fd0);
         pollWrapper.closeEPollFD();
--- a/jdk/src/solaris/classes/sun/nio/ch/FileDispatcher.java	Wed Feb 11 13:16:53 2009 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-/*
- * Copyright 2000-2002 Sun Microsystems, Inc.  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.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.nio.ch;
-
-import java.io.*;
-
-/**
- * Allows different platforms to call different native methods
- * for read and write operations.
- */
-
-class FileDispatcher extends NativeDispatcher
-{
-
-    static {
-        Util.load();
-        init();
-    }
-
-    int read(FileDescriptor fd, long address, int len) throws IOException {
-        return read0(fd, address, len);
-    }
-
-    int pread(FileDescriptor fd, long address, int len,
-                             long position, Object lock) throws IOException {
-        return pread0(fd, address, len, position);
-    }
-
-    long readv(FileDescriptor fd, long address, int len) throws IOException {
-        return readv0(fd, address, len);
-    }
-
-    int write(FileDescriptor fd, long address, int len) throws IOException {
-        return write0(fd, address, len);
-    }
-
-    int pwrite(FileDescriptor fd, long address, int len,
-                             long position, Object lock) throws IOException
-    {
-        return pwrite0(fd, address, len, position);
-    }
-
-    long writev(FileDescriptor fd, long address, int len)
-        throws IOException
-    {
-        return writev0(fd, address, len);
-    }
-
-    void close(FileDescriptor fd) throws IOException {
-        close0(fd);
-    }
-
-    void preClose(FileDescriptor fd) throws IOException {
-        preClose0(fd);
-    }
-
-    // -- Native methods --
-
-    static native int read0(FileDescriptor fd, long address, int len)
-        throws IOException;
-
-    static native int pread0(FileDescriptor fd, long address, int len,
-                             long position) throws IOException;
-
-    static native long readv0(FileDescriptor fd, long address, int len)
-        throws IOException;
-
-    static native int write0(FileDescriptor fd, long address, int len)
-        throws IOException;
-
-    static native int pwrite0(FileDescriptor fd, long address, int len,
-                             long position) throws IOException;
-
-    static native long writev0(FileDescriptor fd, long address, int len)
-        throws IOException;
-
-    static native void close0(FileDescriptor fd) throws IOException;
-
-    static native void preClose0(FileDescriptor fd) throws IOException;
-
-    static native void closeIntFD(int fd) throws IOException;
-
-    static native void init();
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.io.*;
+
+class FileDispatcherImpl extends FileDispatcher
+{
+
+    static {
+        Util.load();
+        init();
+    }
+
+    int read(FileDescriptor fd, long address, int len) throws IOException {
+        return read0(fd, address, len);
+    }
+
+    int pread(FileDescriptor fd, long address, int len,
+                             long position, Object lock) throws IOException {
+        return pread0(fd, address, len, position);
+    }
+
+    long readv(FileDescriptor fd, long address, int len) throws IOException {
+        return readv0(fd, address, len);
+    }
+
+    int write(FileDescriptor fd, long address, int len) throws IOException {
+        return write0(fd, address, len);
+    }
+
+    int pwrite(FileDescriptor fd, long address, int len,
+                             long position, Object lock) throws IOException
+    {
+        return pwrite0(fd, address, len, position);
+    }
+
+    long writev(FileDescriptor fd, long address, int len)
+        throws IOException
+    {
+        return writev0(fd, address, len);
+    }
+
+    int force(FileDescriptor fd, boolean metaData) throws IOException {
+        return force0(fd, metaData);
+    }
+
+    int truncate(FileDescriptor fd, long size) throws IOException {
+        return truncate0(fd, size);
+    }
+
+    long size(FileDescriptor fd) throws IOException {
+        return size0(fd);
+    }
+
+    int lock(FileDescriptor fd, boolean blocking, long pos, long size,
+             boolean shared) throws IOException
+    {
+        return lock0(fd, blocking, pos, size, shared);
+    }
+
+    void release(FileDescriptor fd, long pos, long size) throws IOException {
+        release0(fd, pos, size);
+    }
+
+    void close(FileDescriptor fd) throws IOException {
+        close0(fd);
+    }
+
+    void preClose(FileDescriptor fd) throws IOException {
+        preClose0(fd);
+    }
+
+    // -- Native methods --
+
+    static native int read0(FileDescriptor fd, long address, int len)
+        throws IOException;
+
+    static native int pread0(FileDescriptor fd, long address, int len,
+                             long position) throws IOException;
+
+    static native long readv0(FileDescriptor fd, long address, int len)
+        throws IOException;
+
+    static native int write0(FileDescriptor fd, long address, int len)
+        throws IOException;
+
+    static native int pwrite0(FileDescriptor fd, long address, int len,
+                             long position) throws IOException;
+
+    static native long writev0(FileDescriptor fd, long address, int len)
+        throws IOException;
+
+    static native int force0(FileDescriptor fd, boolean metaData)
+        throws IOException;
+
+    static native int truncate0(FileDescriptor fd, long size)
+        throws IOException;
+
+    static native long size0(FileDescriptor fd) throws IOException;
+
+    static native int lock0(FileDescriptor fd, boolean blocking, long pos,
+                            long size, boolean shared) throws IOException;
+
+    static native void release0(FileDescriptor fd, long pos, long size)
+        throws IOException;
+
+    static native void close0(FileDescriptor fd) throws IOException;
+
+    static native void preClose0(FileDescriptor fd) throws IOException;
+
+    static native void closeIntFD(int fd) throws IOException;
+
+    static native void init();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/LinuxAsynchronousChannelProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.net.ProtocolFamily;
+import java.io.IOException;
+
+public class LinuxAsynchronousChannelProvider
+    extends AsynchronousChannelProvider
+{
+    private static volatile EPollPort defaultPort;
+
+    private EPollPort defaultEventPort() throws IOException {
+        if (defaultPort == null) {
+            synchronized (LinuxAsynchronousChannelProvider.class) {
+                if (defaultPort == null) {
+                    defaultPort = new EPollPort(this, ThreadPool.getDefault()).start();
+                }
+            }
+        }
+        return defaultPort;
+    }
+
+    public LinuxAsynchronousChannelProvider() {
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory)
+        throws IOException
+    {
+        return new EPollPort(this, ThreadPool.create(nThreads, factory)).start();
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
+        throws IOException
+    {
+        return new EPollPort(this, ThreadPool.wrap(executor, initialSize)).start();
+    }
+
+    private Port toPort(AsynchronousChannelGroup group) throws IOException {
+        if (group == null) {
+            return defaultEventPort();
+        } else {
+            if (!(group instanceof EPollPort))
+                throw new IllegalChannelGroupException();
+            return (Port)group;
+        }
+    }
+
+    @Override
+    public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group)
+        throws IOException
+    {
+        return new UnixAsynchronousServerSocketChannelImpl(toPort(group));
+    }
+
+    @Override
+    public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group)
+        throws IOException
+    {
+        return new UnixAsynchronousSocketChannelImpl(toPort(group));
+    }
+
+    @Override
+    public AsynchronousDatagramChannel openAsynchronousDatagramChannel(ProtocolFamily family,
+                                                                       AsynchronousChannelGroup group)
+        throws IOException
+    {
+        return new SimpleAsynchronousDatagramChannelImpl(family, toPort(group));
+    }
+}
--- a/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2001-2009 Sun Microsystems, Inc.  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
@@ -93,8 +93,8 @@
         synchronized (interruptLock) {
             interruptTriggered = true;
         }
-        FileDispatcher.closeIntFD(fd0);
-        FileDispatcher.closeIntFD(fd1);
+        FileDispatcherImpl.closeIntFD(fd0);
+        FileDispatcherImpl.closeIntFD(fd1);
         fd0 = -1;
         fd1 = -1;
         pollWrapper.release(0);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/Port.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.nio.channels.*;
+import java.io.IOException;
+import java.io.Closeable;
+import java.io.FileDescriptor;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Base implementation of AsynchronousChannelGroupImpl for Unix systems.
+ */
+
+abstract class Port extends AsynchronousChannelGroupImpl {
+    static final short POLLIN       = 0x0001;
+    static final short POLLOUT      = 0x0004;
+    static final short POLLERR      = 0x0008;
+    static final short POLLHUP      = 0x0010;
+
+    /**
+     * Implemented by clients registered with this port.
+     */
+    interface PollableChannel extends Closeable {
+        void onEvent(int events);
+    }
+
+    // maps fd to "pollable" channel
+    protected final ReadWriteLock fdToChannelLock = new ReentrantReadWriteLock();
+    protected final Map<Integer,PollableChannel> fdToChannel =
+        new HashMap<Integer,PollableChannel>();
+
+
+    Port(AsynchronousChannelProvider provider, ThreadPool pool) {
+        super(provider, pool);
+    }
+
+    /**
+     * Register channel identified by its file descriptor
+     */
+    final void register(int fd, PollableChannel ch) {
+        fdToChannelLock.writeLock().lock();
+        try {
+            if (isShutdown())
+                throw new ShutdownChannelGroupException();
+            fdToChannel.put(Integer.valueOf(fd), ch);
+        } finally {
+            fdToChannelLock.writeLock().unlock();
+        }
+    }
+
+    /**
+     * Unregister channel identified by its file descriptor
+     */
+    final void unregister(int fd) {
+        boolean checkForShutdown = false;
+
+        fdToChannelLock.writeLock().lock();
+        try {
+            fdToChannel.remove(Integer.valueOf(fd));
+
+            // last key to be removed so check if group is shutdown
+            if (fdToChannel.isEmpty())
+                checkForShutdown = true;
+
+        } finally {
+            fdToChannelLock.writeLock().unlock();
+        }
+
+        // continue shutdown
+        if (checkForShutdown && isShutdown()) {
+            try {
+                shutdownNow();
+            } catch (IOException ignore) { }
+        }
+    }
+    /**
+     * Register file descriptor with polling mechanism for given events.
+     * The implementation should translate the events as required.
+     */
+    abstract void startPoll(int fd, int events);
+
+    @Override
+    final boolean isEmpty() {
+        fdToChannelLock.writeLock().lock();
+        try {
+            return fdToChannel.isEmpty();
+        } finally {
+            fdToChannelLock.writeLock().unlock();
+        }
+    }
+
+    @Override
+    final Object attachForeignChannel(final Channel channel, FileDescriptor fd) {
+        int fdVal = IOUtil.fdVal(fd);
+        register(fdVal, new PollableChannel() {
+            public void onEvent(int events) { }
+            public void close() throws IOException {
+                channel.close();
+            }
+        });
+        return Integer.valueOf(fdVal);
+    }
+
+    @Override
+    final void detachForeignChannel(Object key) {
+        unregister((Integer)key);
+    }
+
+    @Override
+    final void closeAllChannels() {
+        /**
+         * Close channels in batches of up to 128 channels. This allows close
+         * to remove the channel from the map without interference.
+         */
+        final int MAX_BATCH_SIZE = 128;
+        PollableChannel channels[] = new PollableChannel[MAX_BATCH_SIZE];
+        int count;
+        do {
+            // grab a batch of up to 128 channels
+            fdToChannelLock.writeLock().lock();
+            count = 0;
+            try {
+                for (Integer fd: fdToChannel.keySet()) {
+                    channels[count++] = fdToChannel.get(fd);
+                    if (count >= MAX_BATCH_SIZE)
+                        break;
+                }
+            } finally {
+                fdToChannelLock.writeLock().unlock();
+            }
+
+            // close them
+            for (int i=0; i<count; i++) {
+                try {
+                    channels[i].close();
+                } catch (IOException ignore) { }
+            }
+        } while (count > 0);
+    }
+}
--- a/jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -208,7 +208,7 @@
 
     static {
         Util.load();
-        nd = new FileDispatcher();
+        nd = new FileDispatcherImpl();
     }
 
 }
--- a/jdk/src/solaris/classes/sun/nio/ch/SocketDispatcher.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SocketDispatcher.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -36,26 +36,26 @@
 {
 
     int read(FileDescriptor fd, long address, int len) throws IOException {
-        return FileDispatcher.read0(fd, address, len);
+        return FileDispatcherImpl.read0(fd, address, len);
     }
 
     long readv(FileDescriptor fd, long address, int len) throws IOException {
-        return FileDispatcher.readv0(fd, address, len);
+        return FileDispatcherImpl.readv0(fd, address, len);
     }
 
     int write(FileDescriptor fd, long address, int len) throws IOException {
-        return FileDispatcher.write0(fd, address, len);
+        return FileDispatcherImpl.write0(fd, address, len);
     }
 
     long writev(FileDescriptor fd, long address, int len) throws IOException {
-        return FileDispatcher.writev0(fd, address, len);
+        return FileDispatcherImpl.writev0(fd, address, len);
     }
 
     void close(FileDescriptor fd) throws IOException {
-        FileDispatcher.close0(fd);
+        FileDispatcherImpl.close0(fd);
     }
 
     void preClose(FileDescriptor fd) throws IOException {
-        FileDispatcher.preClose0(fd);
+        FileDispatcherImpl.preClose0(fd);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.net.ProtocolFamily;
+import java.io.IOException;
+
+public class SolarisAsynchronousChannelProvider
+    extends AsynchronousChannelProvider
+{
+    private static volatile SolarisEventPort defaultEventPort;
+
+    private SolarisEventPort defaultEventPort() throws IOException {
+        if (defaultEventPort == null) {
+            synchronized (SolarisAsynchronousChannelProvider.class) {
+                if (defaultEventPort == null) {
+                    defaultEventPort =
+                        new SolarisEventPort(this, ThreadPool.getDefault()).start();
+                }
+            }
+        }
+        return defaultEventPort;
+    }
+
+    public SolarisAsynchronousChannelProvider() {
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory)
+        throws IOException
+    {
+        return new SolarisEventPort(this, ThreadPool.create(nThreads, factory)).start();
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
+        throws IOException
+    {
+        return new SolarisEventPort(this, ThreadPool.wrap(executor, initialSize)).start();
+    }
+
+    private SolarisEventPort toEventPort(AsynchronousChannelGroup group)
+        throws IOException
+    {
+        if (group == null) {
+            return defaultEventPort();
+        } else {
+            if (!(group instanceof SolarisEventPort))
+                throw new IllegalChannelGroupException();
+            return (SolarisEventPort)group;
+        }
+    }
+
+    @Override
+    public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group)
+        throws IOException
+    {
+        return new UnixAsynchronousServerSocketChannelImpl(toEventPort(group));
+    }
+
+    @Override
+    public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group)
+        throws IOException
+    {
+        return new UnixAsynchronousSocketChannelImpl(toEventPort(group));
+    }
+
+    @Override
+    public AsynchronousDatagramChannel openAsynchronousDatagramChannel(ProtocolFamily family,
+                                                                       AsynchronousChannelGroup group)
+        throws IOException
+    {
+        return new SimpleAsynchronousDatagramChannelImpl(family, toEventPort(group));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.util.concurrent.RejectedExecutionException;
+import java.io.IOException;
+import sun.misc.Unsafe;
+
+/**
+ * AsynchronousChannelGroup implementation based on the Solaris 10 event port
+ * framework.
+ */
+
+class SolarisEventPort
+    extends Port
+{
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private static final int addressSize = unsafe.addressSize();
+
+    private static int dependsArch(int value32, int value64) {
+        return (addressSize == 4) ? value32 : value64;
+    }
+
+    /*
+     * typedef struct port_event {
+     *     int             portev_events;
+     *     ushort_t        portev_source;
+     *     ushort_t        portev_pad;
+     *     uintptr_t       portev_object;
+     *     void            *portev_user;
+     * } port_event_t;
+     */
+    private static final int SIZEOF_PORT_EVENT  = dependsArch(16, 24);
+    private static final int OFFSETOF_EVENTS    = 0;
+    private static final int OFFSETOF_SOURCE    = 4;
+    private static final int OFFSETOF_OBJECT    = 8;
+
+    // port sources
+    private static final short PORT_SOURCE_USER     = 3;
+    private static final short PORT_SOURCE_FD       = 4;
+
+    // file descriptor to event port.
+    private final int port;
+
+    // true when port is closed
+    private boolean closed;
+
+    SolarisEventPort(AsynchronousChannelProvider provider, ThreadPool pool)
+        throws IOException
+    {
+        super(provider, pool);
+
+        // create event port
+        this.port = portCreate();
+    }
+
+    SolarisEventPort start() {
+        startThreads(new EventHandlerTask());
+        return this;
+    }
+
+    // releass resources
+    private void implClose() {
+        synchronized (this) {
+            if (closed)
+                return;
+            closed = true;
+        }
+        portClose(port);
+    }
+
+    private void wakeup() {
+        try {
+            portSend(port, 0);
+        } catch (IOException x) {
+            throw new AssertionError(x);
+        }
+    }
+
+    @Override
+    void executeOnHandlerTask(Runnable task) {
+        synchronized (this) {
+            if (closed)
+                throw new RejectedExecutionException();
+            offerTask(task);
+            wakeup();
+        }
+    }
+
+    @Override
+    void shutdownHandlerTasks() {
+       /*
+         * If no tasks are running then just release resources; otherwise
+         * write to the one end of the socketpair to wakeup any polling threads..
+         */
+        int nThreads = threadCount();
+        if (nThreads == 0) {
+            implClose();
+        } else {
+            // send user event to wakeup each thread
+            while (nThreads-- > 0) {
+                try {
+                    portSend(port, 0);
+                } catch (IOException x) {
+                    throw new AssertionError(x);
+                }
+            }
+        }
+    }
+
+    @Override
+    void startPoll(int fd, int events) {
+        // (re-)associate file descriptor
+        // no need to translate events
+        try {
+            portAssociate(port, PORT_SOURCE_FD, fd, events);
+        } catch (IOException x) {
+            throw new AssertionError();     // should not happen
+        }
+    }
+
+    /*
+     * Task to read a single event from the port and dispatch it to the
+     * channel's onEvent handler.
+     */
+    private class EventHandlerTask implements Runnable {
+        public void run() {
+            Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
+                Invoker.getGroupAndInvokeCount();
+            boolean replaceMe = false;
+            long address = unsafe.allocateMemory(SIZEOF_PORT_EVENT);
+            try {
+                for (;;) {
+                    // reset invoke count
+                    if (myGroupAndInvokeCount != null)
+                        myGroupAndInvokeCount.resetInvokeCount();
+
+                    // wait for I/O completion event
+                    // A error here is fatal (thread will not be replaced)
+                    replaceMe = false;
+                    try {
+                        portGet(port, address);
+                    } catch (IOException x) {
+                        x.printStackTrace();
+                        return;
+                    }
+
+                    // event source
+                    short source = unsafe.getShort(address + OFFSETOF_SOURCE);
+                    if (source != PORT_SOURCE_FD) {
+                        // user event is trigger to invoke task or shutdown
+                        if (source == PORT_SOURCE_USER) {
+                            Runnable task = pollTask();
+                            if (task == null) {
+                                // shutdown request
+                                return;
+                            }
+                            // run task (may throw error/exception)
+                            replaceMe = true;
+                            task.run();
+                        }
+                        // ignore
+                        continue;
+                    }
+
+                    // pe->portev_object is file descriptor
+                    int fd = (int)unsafe.getAddress(address + OFFSETOF_OBJECT);
+                    // pe->portev_events
+                    int events = unsafe.getInt(address + OFFSETOF_EVENTS);
+
+                    // lookup channel
+                    PollableChannel ch;
+                    fdToChannelLock.readLock().lock();
+                    try {
+                        ch = fdToChannel.get(fd);
+                    } finally {
+                        fdToChannelLock.readLock().unlock();
+                    }
+
+                    // notify channel
+                    if (ch != null) {
+                        replaceMe = true;
+                        // no need to translate events
+                        ch.onEvent(events);
+                    }
+                }
+            } finally {
+                // free per-thread resources
+                unsafe.freeMemory(address);
+                // last task to exit when shutdown release resources
+                int remaining = threadExit(this, replaceMe);
+                if (remaining == 0 && isShutdown())
+                    implClose();
+            }
+        }
+    }
+
+    // -- Native methods --
+
+    private static native void init();
+
+    private static native int portCreate() throws IOException;
+
+    private static native void portAssociate(int port, int source, long object,
+        int events) throws IOException;
+
+    private static native void portGet(int port, long pe) throws IOException;
+
+    private static native int portGetn(int port, long address, int max)
+        throws IOException;
+
+    private static native void portSend(int port, int events) throws IOException;
+
+    private static native void portClose(int port);
+
+    static {
+        Util.load();
+        init();
+    }
+}
--- a/jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -208,7 +208,7 @@
 
     static {
         Util.load();
-        nd = new FileDispatcher();
+        nd = new FileDispatcherImpl();
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.util.concurrent.*;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.net.InetSocketAddress;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Unix implementation of AsynchronousServerSocketChannel
+ */
+
+class UnixAsynchronousServerSocketChannelImpl
+    extends AsynchronousServerSocketChannelImpl
+    implements Port.PollableChannel
+{
+    private final static NativeDispatcher nd = new SocketDispatcher();
+
+    private final Port port;
+    private final int fdVal;
+
+    // flag to indicate an accept is outstanding
+    private final AtomicBoolean accepting = new AtomicBoolean();
+    private void enableAccept() {
+        accepting.set(false);
+    }
+
+    // used to ensure that the context for an asynchronous accept is visible
+    // the pooled thread that handles the I/O event
+    private final Object updateLock = new Object();
+
+    // pending accept
+    private PendingFuture<AsynchronousSocketChannel,Object> pendingAccept;
+
+    // context for permission check when security manager set
+    private AccessControlContext acc;
+
+
+    UnixAsynchronousServerSocketChannelImpl(Port port)
+        throws IOException
+    {
+        super(port);
+
+        try {
+            IOUtil.configureBlocking(fd, false);
+        } catch (IOException x) {
+            nd.close(fd);  // prevent leak
+            throw x;
+        }
+        this.port = port;
+        this.fdVal = IOUtil.fdVal(fd);
+
+        // add mapping from file descriptor to this channel
+        port.register(fdVal, this);
+    }
+
+    // returns and clears the result of a pending accept
+    private PendingFuture<AsynchronousSocketChannel,Object> grabPendingAccept() {
+        synchronized (updateLock) {
+            PendingFuture<AsynchronousSocketChannel,Object> result = pendingAccept;
+            pendingAccept = null;
+            return result;
+        }
+    }
+
+    @Override
+    void implClose() throws IOException {
+        // remove the mapping
+        port.unregister(fdVal);
+
+        // close file descriptor
+        nd.close(fd);
+
+        // if there is a pending accept then complete it
+        final PendingFuture<AsynchronousSocketChannel,Object> result =
+            grabPendingAccept();
+        if (result != null) {
+            // discard the stack trace as otherwise it may appear that implClose
+            // has thrown the exception.
+            AsynchronousCloseException x = new AsynchronousCloseException();
+            x.setStackTrace(new StackTraceElement[0]);
+            result.setFailure(x);
+
+            // invoke by submitting task rather than directly
+            Invoker.invokeIndirectly(result.handler(), result);
+        }
+    }
+
+    @Override
+    public AsynchronousChannelGroupImpl group() {
+        return port;
+    }
+
+    /**
+     * Invoked by event handling thread when listener socket is polled
+     */
+    @Override
+    public void onEvent(int events) {
+        PendingFuture<AsynchronousSocketChannel,Object> result = grabPendingAccept();
+        if (result == null)
+            return; // may have been grabbed by asynchronous close
+
+        // attempt to accept connection
+        FileDescriptor newfd = new FileDescriptor();
+        InetSocketAddress[] isaa = new InetSocketAddress[1];
+        boolean accepted = false;
+        try {
+            begin();
+            int n = accept0(this.fd, newfd, isaa);
+
+            // spurious wakeup, is this possible?
+            if (n == IOStatus.UNAVAILABLE) {
+                synchronized (updateLock) {
+                    this.pendingAccept = result;
+                }
+                port.startPoll(fdVal, Port.POLLIN);
+                return;
+            }
+
+            // connection accepted
+            accepted = true;
+
+        } catch (Throwable x) {
+            if (x instanceof ClosedChannelException)
+                x = new AsynchronousCloseException();
+            enableAccept();
+            result.setFailure(x);
+        } finally {
+            end();
+        }
+
+        // Connection accepted so finish it when not holding locks.
+        AsynchronousSocketChannel child = null;
+        if (accepted) {
+            try {
+                child = finishAccept(newfd, isaa[0], acc);
+                enableAccept();
+                result.setResult(child);
+            } catch (Throwable x) {
+                enableAccept();
+                if (!(x instanceof IOException) && !(x instanceof SecurityException))
+                    x = new IOException(x);
+                result.setFailure(x);
+            }
+        }
+
+        // if an async cancel has already cancelled the operation then
+        // close the new channel so as to free resources
+        if (child != null && result.isCancelled()) {
+            try {
+                child.close();
+            } catch (IOException ignore) { }
+        }
+
+        // invoke the handler
+        Invoker.invoke(result.handler(), result);
+    }
+
+    /**
+     * Completes the accept by creating the AsynchronousSocketChannel for
+     * the given file descriptor and remote address. If this method completes
+     * with an IOException or SecurityException then the channel/file descriptor
+     * will be closed.
+     */
+    private AsynchronousSocketChannel finishAccept(FileDescriptor newfd,
+                                                   final InetSocketAddress remote,
+                                                   AccessControlContext acc)
+        throws IOException, SecurityException
+    {
+        AsynchronousSocketChannel ch = null;
+        try {
+            ch = new UnixAsynchronousSocketChannelImpl(port, newfd, remote);
+        } catch (IOException x) {
+            nd.close(newfd);
+            throw x;
+        }
+
+        // permission check must always be in initiator's context
+        try {
+            if (acc != null) {
+                AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                    public Void run() {
+                        SecurityManager sm = System.getSecurityManager();
+                        if (sm != null) {
+                            sm.checkAccept(remote.getAddress().getHostAddress(),
+                                           remote.getPort());
+                        }
+                        return null;
+                    }
+                }, acc);
+            } else {
+                SecurityManager sm = System.getSecurityManager();
+                if (sm != null) {
+                    sm.checkAccept(remote.getAddress().getHostAddress(),
+                                   remote.getPort());
+                }
+            }
+        } catch (SecurityException x) {
+            try {
+                ch.close();
+            } catch (IOException ignore) { }
+            throw x;
+        }
+        return ch;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <A> Future<AsynchronousSocketChannel> accept(A attachment,
+        final CompletionHandler<AsynchronousSocketChannel,? super A> handler)
+    {
+        // complete immediately if channel is closed
+        if (!isOpen()) {
+            CompletedFuture<AsynchronousSocketChannel,A> result = CompletedFuture
+                .withFailure(this, new ClosedChannelException(), attachment);
+            Invoker.invokeIndirectly(handler, result);
+            return result;
+        }
+        if (localAddress == null)
+            throw new NotYetBoundException();
+
+        // cancel was invoked with pending accept so connection may have been
+        // dropped.
+        if (isAcceptKilled())
+            throw new RuntimeException("Accept not allowed due cancellation");
+
+        // check and set flag to prevent concurrent accepting
+        if (!accepting.compareAndSet(false, true))
+            throw new AcceptPendingException();
+
+        // attempt accept
+        AbstractFuture<AsynchronousSocketChannel,A> result = null;
+        FileDescriptor newfd = new FileDescriptor();
+        InetSocketAddress[] isaa = new InetSocketAddress[1];
+        try {
+            begin();
+
+            int n = accept0(this.fd, newfd, isaa);
+            if (n == IOStatus.UNAVAILABLE) {
+                // no connection to accept
+                result = new PendingFuture<AsynchronousSocketChannel,A>(this, handler, attachment);
+
+                // need calling context when there is security manager as
+                // permission check may be done in a different thread without
+                // any application call frames on the stack
+                synchronized (this) {
+                    this.acc = (System.getSecurityManager() == null) ?
+                        null : AccessController.getContext();
+                    this.pendingAccept =
+                        (PendingFuture<AsynchronousSocketChannel,Object>)result;
+                }
+
+                // register for connections
+                port.startPoll(fdVal, Port.POLLIN);
+                return result;
+            }
+        } catch (Throwable x) {
+            // accept failed
+            if (x instanceof ClosedChannelException)
+                x = new AsynchronousCloseException();
+            result = CompletedFuture.withFailure(this, x, attachment);
+        } finally {
+            end();
+        }
+
+        // connection accepted immediately
+        if (result == null) {
+            try {
+                AsynchronousSocketChannel ch = finishAccept(newfd, isaa[0], null);
+                result = CompletedFuture.withResult(this, ch, attachment);
+            } catch (Throwable x) {
+                result = CompletedFuture.withFailure(this, x, attachment);
+            }
+        }
+
+        // re-enable accepting and invoke handler
+        enableAccept();
+        Invoker.invokeIndirectly(handler, result);
+        return result;
+    }
+
+    // -- Native methods --
+
+    private static native void initIDs();
+
+    // Accepts a new connection, setting the given file descriptor to refer to
+    // the new socket and setting isaa[0] to the socket's remote address.
+    // Returns 1 on success, or IOStatus.UNAVAILABLE.
+    //
+    private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,
+                               InetSocketAddress[] isaa)
+        throws IOException;
+
+    static {
+        Util.load();
+        initIDs();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,673 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 conne02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.nio.ByteBuffer;
+import java.net.*;
+import java.util.concurrent.*;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.security.AccessController;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * Unix implementation of AsynchronousSocketChannel
+ */
+
+class UnixAsynchronousSocketChannelImpl
+    extends AsynchronousSocketChannelImpl implements Port.PollableChannel
+{
+    private final static NativeDispatcher nd = new SocketDispatcher();
+    private static enum OpType { CONNECT, READ, WRITE };
+
+    private static final boolean disableSynchronousRead;
+    static {
+        String propValue = AccessController.doPrivileged(
+            new GetPropertyAction("sun.nio.ch.disableSynchronousRead", "false"));
+        disableSynchronousRead = (propValue.length() == 0) ?
+            true : Boolean.valueOf(propValue);
+    }
+
+    private final Port port;
+    private final int fdVal;
+
+    // used to ensure that the context for I/O operations that complete
+    // ascynrhonously is visible to the pooled threads handling I/O events.
+    private final Object updateLock = new Object();
+
+    // pending connect (updateLock)
+    private PendingFuture<Void,Object> pendingConnect;
+
+    // pending remote address (statLock)
+    private SocketAddress pendingRemote;
+
+    // pending read (updateLock)
+    private ByteBuffer[] readBuffers;
+    private boolean scatteringRead;
+    private PendingFuture<Number,Object> pendingRead;
+
+    // pending write (updateLock)
+    private ByteBuffer[] writeBuffers;
+    private boolean gatheringWrite;
+    private PendingFuture<Number,Object> pendingWrite;
+
+
+    UnixAsynchronousSocketChannelImpl(Port port)
+        throws IOException
+    {
+        super(port);
+
+        // set non-blocking
+        try {
+            IOUtil.configureBlocking(fd, false);
+        } catch (IOException x) {
+            nd.close(fd);
+            throw x;
+        }
+
+        this.port = port;
+        this.fdVal = IOUtil.fdVal(fd);
+
+        // add mapping from file descriptor to this channel
+        port.register(fdVal, this);
+    }
+
+    // Constructor for sockets created by UnixAsynchronousServerSocketChannelImpl
+    UnixAsynchronousSocketChannelImpl(Port port,
+                                      FileDescriptor fd,
+                                      InetSocketAddress remote)
+        throws IOException
+    {
+        super(port, fd, remote);
+
+        this.fdVal = IOUtil.fdVal(fd);
+        IOUtil.configureBlocking(fd, false);
+
+        try {
+            port.register(fdVal, this);
+        } catch (ShutdownChannelGroupException x) {
+            // ShutdownChannelGroupException thrown if we attempt to register a
+            // new channel after the group is shutdown
+            throw new IOException(x);
+        }
+
+        this.port = port;
+    }
+
+    @Override
+    public AsynchronousChannelGroupImpl group() {
+        return port;
+    }
+
+    // register for events if there are outstanding I/O operations
+    private void updateEvents() {
+        assert Thread.holdsLock(updateLock);
+        int events = 0;
+        if (pendingRead != null)
+            events |= Port.POLLIN;
+        if (pendingConnect != null || pendingWrite != null)
+            events |= Port.POLLOUT;
+        if (events != 0)
+            port.startPoll(fdVal, events);
+    }
+
+    /**
+     * Invoked by event handler thread when file descriptor is polled
+     */
+    @Override
+    public void onEvent(int events) {
+        boolean readable = (events & Port.POLLIN) > 0;
+        boolean writable = (events & Port.POLLOUT) > 0;
+        if ((events & (Port.POLLERR | Port.POLLHUP)) > 0) {
+            readable = true;
+            writable = true;
+        }
+
+        PendingFuture<Void,Object> connectResult = null;
+        PendingFuture<Number,Object> readResult = null;
+        PendingFuture<Number,Object> writeResult = null;
+
+        // map event to pending result
+        synchronized (updateLock) {
+            if (readable && (pendingRead != null)) {
+                readResult = pendingRead;
+                pendingRead = null;
+            }
+            if (writable) {
+                if (pendingWrite != null) {
+                    writeResult = pendingWrite;
+                    pendingWrite = null;
+                } else if (pendingConnect != null) {
+                    connectResult = pendingConnect;
+                    pendingConnect = null;
+                }
+            }
+        }
+
+        // complete the I/O operation. Special case for when channel is
+        // ready for both reading and writing. In that case, submit task to
+        // complete write if write operation has a completion handler.
+        if (readResult != null) {
+            if (writeResult != null)
+                finishWrite(writeResult, false);
+            finishRead(readResult, true);
+            return;
+        }
+        if (writeResult != null) {
+            finishWrite(writeResult, true);
+        }
+        if (connectResult != null) {
+            finishConnect(connectResult, true);
+        }
+    }
+
+    // returns and clears the result of a pending read
+    PendingFuture<Number,Object> grabPendingRead() {
+        synchronized (updateLock) {
+            PendingFuture<Number,Object> result = pendingRead;
+            pendingRead = null;
+            return result;
+        }
+    }
+
+    // returns and clears the result of a pending write
+    PendingFuture<Number,Object> grabPendingWrite() {
+        synchronized (updateLock) {
+            PendingFuture<Number,Object> result = pendingWrite;
+            pendingWrite = null;
+            return result;
+        }
+    }
+
+    @Override
+    void implClose() throws IOException {
+        // remove the mapping
+        port.unregister(fdVal);
+
+        // close file descriptor
+        nd.close(fd);
+
+        // All outstanding I/O operations are required to fail
+        final PendingFuture<Void,Object> readyToConnect;
+        final PendingFuture<Number,Object> readyToRead;
+        final PendingFuture<Number,Object> readyToWrite;
+        synchronized (updateLock) {
+            readyToConnect = pendingConnect;
+            pendingConnect = null;
+            readyToRead = pendingRead;
+            pendingRead = null;
+            readyToWrite = pendingWrite;
+            pendingWrite = null;
+        }
+        if (readyToConnect != null) {
+            finishConnect(readyToConnect, false);
+        }
+        if (readyToRead != null) {
+            finishRead(readyToRead, false);
+        }
+        if (readyToWrite != null) {
+            finishWrite(readyToWrite, false);
+        }
+    }
+
+    @Override
+    public void onCancel(PendingFuture<?,?> task) {
+        if (task.getContext() == OpType.CONNECT)
+            killConnect();
+        if (task.getContext() == OpType.READ)
+            killConnect();
+        if (task.getContext() == OpType.WRITE)
+            killConnect();
+    }
+
+    // -- connect --
+
+    private void setConnected() throws IOException {
+        synchronized (stateLock) {
+            state = ST_CONNECTED;
+            localAddress = Net.localAddress(fd);
+            remoteAddress = pendingRemote;
+        }
+    }
+
+    private void finishConnect(PendingFuture<Void,Object> result,
+                               boolean invokeDirect)
+    {
+        Throwable e = null;
+        try {
+            begin();
+            checkConnect(fdVal);
+            setConnected();
+            result.setResult(null);
+        } catch (Throwable x) {
+            if (x instanceof ClosedChannelException)
+                x = new AsynchronousCloseException();
+            e = x;
+        } finally {
+            end();
+        }
+        if (e != null) {
+            // close channel if connection cannot be established
+            try {
+                close();
+            } catch (IOException ignore) { }
+            result.setFailure(e);
+        }
+        if (invokeDirect) {
+            Invoker.invoke(result.handler(), result);
+        } else {
+            Invoker.invokeIndirectly(result.handler(), result);
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <A> Future<Void> connect(SocketAddress remote,
+                                    A attachment,
+                                    CompletionHandler<Void,? super A> handler)
+    {
+        if (!isOpen()) {
+            CompletedFuture<Void,A> result = CompletedFuture
+                .withFailure(this, new ClosedChannelException(), attachment);
+            Invoker.invoke(handler, result);
+            return result;
+        }
+
+        InetSocketAddress isa = Net.checkAddress(remote);
+
+        // permission check
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
+
+        // check and set state
+        synchronized (stateLock) {
+            if (state == ST_CONNECTED)
+                throw new AlreadyConnectedException();
+            if (state == ST_PENDING)
+                throw new ConnectionPendingException();
+            state = ST_PENDING;
+            pendingRemote = remote;
+        }
+
+        AbstractFuture<Void,A> result = null;
+        Throwable e = null;
+        try {
+            begin();
+            int n = Net.connect(fd, isa.getAddress(), isa.getPort());
+            if (n == IOStatus.UNAVAILABLE) {
+                // connection could not be established immediately
+                result = new PendingFuture<Void,A>(this, handler, attachment, OpType.CONNECT);
+                synchronized (updateLock) {
+                    this.pendingConnect = (PendingFuture<Void,Object>)result;
+                    updateEvents();
+                }
+                return result;
+            }
+            setConnected();
+            result = CompletedFuture.withResult(this, null, attachment);
+        } catch (Throwable x) {
+            if (x instanceof ClosedChannelException)
+                x = new AsynchronousCloseException();
+            e = x;
+        } finally {
+            end();
+        }
+
+        // close channel if connect fails
+        if (e != null) {
+            try {
+                close();
+            } catch (IOException ignore) { }
+            result = CompletedFuture.withFailure(this, e, attachment);
+        }
+
+        Invoker.invoke(handler, result);
+        return result;
+    }
+
+    // -- read --
+
+    @SuppressWarnings("unchecked")
+    private void finishRead(PendingFuture<Number,Object> result,
+                            boolean invokeDirect)
+    {
+        int n = -1;
+        PendingFuture<Number,Object> pending = null;
+        try {
+            begin();
+
+            ByteBuffer[] dsts = readBuffers;
+            if (dsts.length == 1) {
+                n = IOUtil.read(fd, dsts[0], -1, nd, null);
+            } else {
+                n = (int)IOUtil.read(fd, dsts, nd);
+            }
+            if (n == IOStatus.UNAVAILABLE) {
+                // spurious wakeup, is this possible?
+                pending = result;
+                return;
+            }
+
+            // allow buffer(s) to be GC'ed.
+            readBuffers = null;
+
+            // allow another read to be initiated
+            boolean wasScatteringRead = scatteringRead;
+            enableReading();
+
+            // result is Integer or Long
+            if (wasScatteringRead) {
+                result.setResult(Long.valueOf(n));
+            } else {
+                result.setResult(Integer.valueOf(n));
+            }
+
+        } catch (Throwable x) {
+            enableReading();
+            if (x instanceof ClosedChannelException)
+                x = new AsynchronousCloseException();
+            result.setFailure(x);
+        } finally {
+            // restart poll in case of concurrent write
+            synchronized (updateLock) {
+                if (pending != null)
+                    this.pendingRead = pending;
+                updateEvents();
+            }
+            end();
+        }
+
+        if (invokeDirect) {
+            Invoker.invoke(result.handler(), result);
+        } else {
+            Invoker.invokeIndirectly(result.handler(), result);
+        }
+    }
+
+    private Runnable readTimeoutTask = new Runnable() {
+        public void run() {
+            PendingFuture<Number,Object> result = grabPendingRead();
+            if (result == null)
+                return;     // already completed
+
+            // kill further reading before releasing waiters
+            enableReading(true);
+
+            // set completed and invoke handler
+            result.setFailure(new InterruptedByTimeoutException());
+            Invoker.invokeIndirectly(result.handler(), result);
+        }
+    };
+
+    /**
+     * Initiates a read or scattering read operation
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    <V extends Number,A> Future<V> readImpl(ByteBuffer[] dsts,
+                                            boolean isScatteringRead,
+                                            long timeout,
+                                            TimeUnit unit,
+                                            A attachment,
+                                            CompletionHandler<V,? super A> handler)
+    {
+        // A synchronous read is not attempted if disallowed by system property
+        // or, we are using a fixed thread pool and the completion handler may
+        // not be invoked directly (because the thread is not a pooled thread or
+        // there are too many handlers on the stack).
+        Invoker.GroupAndInvokeCount myGroupAndInvokeCount = null;
+        boolean invokeDirect = false;
+        boolean attemptRead = false;
+        if (!disableSynchronousRead) {
+            myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount();
+            invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port);
+            attemptRead = (handler == null) || invokeDirect ||
+                !port.isFixedThreadPool();  // okay to attempt read with user thread pool
+        }
+
+        AbstractFuture<V,A> result;
+        try {
+            begin();
+
+            int n;
+            if (attemptRead) {
+                if (isScatteringRead) {
+                    n = (int)IOUtil.read(fd, dsts, nd);
+                } else {
+                    n = IOUtil.read(fd, dsts[0], -1, nd, null);
+                }
+            } else {
+                n = IOStatus.UNAVAILABLE;
+            }
+
+            if (n == IOStatus.UNAVAILABLE) {
+                result = new PendingFuture<V,A>(this, handler, attachment, OpType.READ);
+
+                // update evetns so that read will complete asynchronously
+                synchronized (updateLock) {
+                    this.readBuffers = dsts;
+                    this.scatteringRead = isScatteringRead;
+                    this.pendingRead = (PendingFuture<Number,Object>)result;
+                    updateEvents();
+                }
+
+                // schedule timeout
+                if (timeout > 0L) {
+                    Future<?> timeoutTask =
+                        port.schedule(readTimeoutTask, timeout, unit);
+                    ((PendingFuture<V,A>)result).setTimeoutTask(timeoutTask);
+                }
+                return result;
+            }
+
+            // data available
+            enableReading();
+
+            // result type is Long or Integer
+            if (isScatteringRead) {
+                result = (CompletedFuture<V,A>)CompletedFuture
+                    .withResult(this, Long.valueOf(n), attachment);
+            } else {
+                result = (CompletedFuture<V,A>)CompletedFuture
+                    .withResult(this, Integer.valueOf(n), attachment);
+            }
+        } catch (Throwable x) {
+            enableReading();
+            if (x instanceof ClosedChannelException)
+                x = new AsynchronousCloseException();
+            result = CompletedFuture.withFailure(this, x, attachment);
+        } finally {
+            end();
+        }
+
+        if (invokeDirect) {
+            Invoker.invokeDirect(myGroupAndInvokeCount, handler, result);
+        } else {
+            Invoker.invokeIndirectly(handler, result);
+        }
+        return result;
+    }
+
+    // -- write --
+
+    private void finishWrite(PendingFuture<Number,Object> result,
+                             boolean invokeDirect)
+    {
+        PendingFuture<Number,Object> pending = null;
+        try {
+            begin();
+
+            ByteBuffer[] srcs = writeBuffers;
+            int n;
+            if (srcs.length == 1) {
+                n = IOUtil.write(fd, srcs[0], -1, nd, null);
+            } else {
+                n = (int)IOUtil.write(fd, srcs, nd);
+            }
+            if (n == IOStatus.UNAVAILABLE) {
+                // spurious wakeup, is this possible?
+                pending = result;
+                return;
+            }
+
+            // allow buffer(s) to be GC'ed.
+            writeBuffers = null;
+
+            // allow another write to be initiated
+            boolean wasGatheringWrite = gatheringWrite;
+            enableWriting();
+
+            // result is a Long or Integer
+            if (wasGatheringWrite) {
+                result.setResult(Long.valueOf(n));
+            } else {
+                result.setResult(Integer.valueOf(n));
+            }
+
+        } catch (Throwable x) {
+            enableWriting();
+            if (x instanceof ClosedChannelException)
+                x = new AsynchronousCloseException();
+            result.setFailure(x);
+        } finally {
+            // restart poll in case of concurrent read
+            synchronized (this) {
+                if (pending != null)
+                    this.pendingWrite = pending;
+                updateEvents();
+            }
+            end();
+        }
+        if (invokeDirect) {
+            Invoker.invoke(result.handler(), result);
+        } else {
+            Invoker.invokeIndirectly(result.handler(), result);
+        }
+    }
+
+    private Runnable writeTimeoutTask = new Runnable() {
+        public void run() {
+            PendingFuture<Number,Object> result = grabPendingWrite();
+            if (result == null)
+                return;     // already completed
+
+            // kill further writing before releasing waiters
+            enableWriting(true);
+
+            // set completed and invoke handler
+            result.setFailure(new InterruptedByTimeoutException());
+            Invoker.invokeIndirectly(result.handler(), result);
+        }
+    };
+
+    /**
+     * Initiates a read or scattering read operation
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    <V extends Number,A> Future<V> writeImpl(ByteBuffer[] srcs,
+                                             boolean isGatheringWrite,
+                                             long timeout,
+                                             TimeUnit unit,
+                                             A attachment,
+                                             CompletionHandler<V,? super A> handler)
+    {
+        Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
+            Invoker.getGroupAndInvokeCount();
+        boolean invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port);
+        boolean attemptWrite = (handler == null) || invokeDirect ||
+            !port.isFixedThreadPool();  // okay to attempt read with user thread pool
+
+        AbstractFuture<V,A> result;
+        try {
+            begin();
+
+            int n;
+            if (attemptWrite) {
+                if (isGatheringWrite) {
+                    n = (int)IOUtil.write(fd, srcs, nd);
+                } else {
+                    n = IOUtil.write(fd, srcs[0], -1, nd, null);
+                }
+            } else {
+                n = IOStatus.UNAVAILABLE;
+            }
+
+            if (n == IOStatus.UNAVAILABLE) {
+                result = new PendingFuture<V,A>(this, handler, attachment, OpType.WRITE);
+
+                // update evetns so that read will complete asynchronously
+                synchronized (updateLock) {
+                    this.writeBuffers = srcs;
+                    this.gatheringWrite = isGatheringWrite;
+                    this.pendingWrite = (PendingFuture<Number,Object>)result;
+                    updateEvents();
+                }
+
+                // schedule timeout
+                if (timeout > 0L) {
+                    Future<?> timeoutTask =
+                        port.schedule(writeTimeoutTask, timeout, unit);
+                    ((PendingFuture<V,A>)result).setTimeoutTask(timeoutTask);
+                }
+                return result;
+            }
+
+            // data available
+            enableWriting();
+            if (isGatheringWrite) {
+                result = (CompletedFuture<V,A>)CompletedFuture
+                    .withResult(this, Long.valueOf(n), attachment);
+            } else {
+                result = (CompletedFuture<V,A>)CompletedFuture
+                    .withResult(this, Integer.valueOf(n), attachment);
+            }
+        } catch (Throwable x) {
+            enableWriting();
+            if (x instanceof ClosedChannelException)
+                x = new AsynchronousCloseException();
+            result = CompletedFuture.withFailure(this, x, attachment);
+        } finally {
+            end();
+        }
+        if (invokeDirect) {
+            Invoker.invokeDirect(myGroupAndInvokeCount, handler, result);
+        } else {
+            Invoker.invokeIndirectly(handler, result);
+        }
+        return result;
+    }
+
+    // -- Native methods --
+
+    private static native void checkConnect(int fdVal) throws IOException;
+
+    static {
+        Util.load();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.spi.FileSystemProvider;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * Creates this platform's default FileSystemProvider.
+ */
+
+public class DefaultFileSystemProvider {
+    private DefaultFileSystemProvider() { }
+
+    @SuppressWarnings("unchecked")
+    private static FileSystemProvider createProvider(final String cn) {
+        return AccessController
+            .doPrivileged(new PrivilegedAction<FileSystemProvider>() {
+                public FileSystemProvider run() {
+                    Class<FileSystemProvider> c;
+                    try {
+                        c = (Class<FileSystemProvider>)Class.forName(cn, true, null);
+                    } catch (ClassNotFoundException x) {
+                        throw new AssertionError(x);
+                    }
+                    try {
+                        return c.newInstance();
+                    } catch (IllegalAccessException x) {
+                        throw new AssertionError(x);
+                    } catch (InstantiationException x) {
+                        throw new AssertionError(x);
+                    }
+            }});
+    }
+
+    /**
+     * Returns the default FileSystemProvider.
+     */
+    public static FileSystemProvider create() {
+        String osname = AccessController
+            .doPrivileged(new GetPropertyAction("os.name"));
+        if (osname.equals("SunOS"))
+            return createProvider("sun.nio.fs.SolarisFileSystemProvider");
+        if (osname.equals("Linux"))
+            return createProvider("sun.nio.fs.LinuxFileSystemProvider");
+        throw new AssertionError("Platform not recognized");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/DefaultFileTypeDetector.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.spi.FileTypeDetector;
+
+public class DefaultFileTypeDetector {
+    private DefaultFileTypeDetector() { }
+
+    public static FileTypeDetector create() {
+        return new GnomeFileTypeDetector();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.FileRef;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * File type detector that uses the GNOME I/O library or the deprecated
+ * GNOME VFS to guess the MIME type of a file.
+ */
+
+public class GnomeFileTypeDetector
+    extends AbstractFileTypeDetector
+{
+    private static final String GNOME_VFS_MIME_TYPE_UNKNOWN =
+        "application/octet-stream";
+
+    // true if GIO available
+    private final boolean gioAvailable;
+
+    // true if GNOME VFS available and GIO is not available
+    private final boolean gnomeVfsAvailable;
+
+    public GnomeFileTypeDetector() {
+        gioAvailable = initializeGio();
+        if (gioAvailable) {
+            gnomeVfsAvailable = false;
+        } else {
+            gnomeVfsAvailable = initializeGnomeVfs();
+        }
+    }
+
+    @Override
+    public String implProbeContentType(FileRef obj) throws IOException {
+        if (!gioAvailable && !gnomeVfsAvailable)
+            return null;
+        if (!(obj instanceof UnixPath))
+            return null;
+
+        UnixPath path = (UnixPath)obj;
+        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path.getByteArrayForSysCalls());
+        try {
+            if (gioAvailable) {
+                byte[] type = probeUsingGio(buffer.address());
+                return (type == null) ? null : new String(type);
+            } else {
+                byte[] type = probeUsingGnomeVfs(buffer.address());
+                if (type == null)
+                    return null;
+                String s = new String(type);
+                return s.equals(GNOME_VFS_MIME_TYPE_UNKNOWN) ? null : s;
+            }
+
+        } finally {
+            buffer.release();
+        }
+
+    }
+
+    // GIO
+    private static native boolean initializeGio();
+    private static native byte[] probeUsingGio(long pathAddress);
+
+    // GNOME VFS
+    private static native boolean initializeGnomeVfs();
+    private static native byte[] probeUsingGnomeVfs(long pathAddress);
+
+    static {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                System.loadLibrary("nio");
+                return null;
+        }});
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.io.IOException;
+import sun.misc.Unsafe;
+
+import static sun.nio.fs.UnixNativeDispatcher.*;
+import static sun.nio.fs.UnixConstants.*;
+
+/**
+ * Linux implementation of DosFileAttributeView for use on file systems such
+ * as ext3 that have extended attributes enabled and SAMBA configured to store
+ * DOS attributes.
+ */
+
+class LinuxDosFileAttributeView
+    extends UnixFileAttributeViews.Basic implements DosFileAttributeView
+{
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    private static final String READONLY_NAME = "readonly";
+    private static final String ARCHIVE_NAME = "archive";
+    private static final String SYSTEM_NAME = "system";
+    private static final String HIDDEN_NAME = "hidden";
+
+    private static final String DOS_XATTR_NAME = "user.DOSATTRIB";
+    private static final byte[] DOS_XATTR_NAME_AS_BYTES = DOS_XATTR_NAME.getBytes();
+
+    private static final int DOS_XATTR_READONLY = 0x01;
+    private static final int DOS_XATTR_HIDDEN   = 0x02;
+    private static final int DOS_XATTR_SYSTEM   = 0x04;
+    private static final int DOS_XATTR_ARCHIVE  = 0x20;
+
+    LinuxDosFileAttributeView(UnixPath file, boolean followLinks) {
+        super(file, followLinks);
+    }
+
+    @Override
+    public String name() {
+        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
+    {
+        if (attribute.equals(READONLY_NAME)) {
+            setReadOnly((Boolean)value);
+            return;
+        }
+        if (attribute.equals(ARCHIVE_NAME)) {
+            setArchive((Boolean)value);
+            return;
+        }
+        if (attribute.equals(SYSTEM_NAME)) {
+            setSystem((Boolean)value);
+            return;
+        }
+        if (attribute.equals(HIDDEN_NAME)) {
+            setHidden((Boolean)value);
+            return;
+        }
+        super.setAttribute(attribute, value);
+    }
+
+    @Override
+    public Map<String,?> readAttributes(String first, String[] rest)
+        throws IOException
+    {
+        AttributesBuilder builder = AttributesBuilder.create(first, rest);
+        DosFileAttributes attrs = readAttributes();
+        addBasicAttributesToBuilder(attrs, builder);
+        if (builder.match(READONLY_NAME))
+            builder.add(READONLY_NAME, attrs.isReadOnly());
+        if (builder.match(ARCHIVE_NAME))
+            builder.add(ARCHIVE_NAME, attrs.isArchive());
+        if (builder.match(SYSTEM_NAME))
+            builder.add(SYSTEM_NAME, attrs.isSystem());
+        if (builder.match(HIDDEN_NAME))
+            builder.add(HIDDEN_NAME, attrs.isHidden());
+        return builder.unmodifiableMap();
+    }
+
+    @Override
+    public DosFileAttributes readAttributes() throws IOException {
+        file.checkRead();
+
+        int fd = file.openForAttributeAccess(followLinks);
+        try {
+             final UnixFileAttributes attrs = UnixFileAttributes.get(fd);
+             final int dosAttribute = getDosAttribute(fd);
+
+             return new DosFileAttributes() {
+                @Override
+                public long lastModifiedTime() {
+                    return attrs.lastModifiedTime();
+                }
+                @Override
+                public long lastAccessTime() {
+                    return attrs.lastAccessTime();
+                }
+                @Override
+                public long creationTime() {
+                    return attrs.creationTime();
+                }
+                @Override
+                public TimeUnit resolution() {
+                    return attrs.resolution();
+                }
+                @Override
+                public boolean isRegularFile() {
+                    return attrs.isRegularFile();
+                }
+                @Override
+                public boolean isDirectory() {
+                    return attrs.isDirectory();
+                }
+                @Override
+                public boolean isSymbolicLink() {
+                    return attrs.isSymbolicLink();
+                }
+                @Override
+                public boolean isOther() {
+                    return attrs.isOther();
+                }
+                @Override
+                public long size() {
+                    return attrs.size();
+                }
+                @Override
+                public int linkCount() {
+                    return attrs.linkCount();
+                }
+                @Override
+                public Object fileKey() {
+                    return attrs.fileKey();
+                }
+                @Override
+                public boolean isReadOnly() {
+                    return (dosAttribute & DOS_XATTR_READONLY) != 0;
+                }
+                @Override
+                public boolean isHidden() {
+                    return (dosAttribute & DOS_XATTR_HIDDEN) != 0;
+                }
+                @Override
+                public boolean isArchive() {
+                    return (dosAttribute & DOS_XATTR_ARCHIVE) != 0;
+                }
+                @Override
+                public boolean isSystem() {
+                    return (dosAttribute & DOS_XATTR_SYSTEM) != 0;
+                }
+             };
+
+        } catch (UnixException x) {
+            x.rethrowAsIOException(file);
+            return null;    // keep compiler happy
+        } finally {
+            close(fd);
+        }
+    }
+
+    @Override
+    public void setReadOnly(boolean value) throws IOException {
+        updateDosAttribute(DOS_XATTR_READONLY, value);
+    }
+
+    @Override
+    public void setHidden(boolean value) throws IOException {
+        updateDosAttribute(DOS_XATTR_HIDDEN, value);
+    }
+
+    @Override
+    public void setArchive(boolean value) throws IOException {
+        updateDosAttribute(DOS_XATTR_ARCHIVE, value);
+    }
+
+    @Override
+    public void setSystem(boolean value) throws IOException {
+        updateDosAttribute(DOS_XATTR_SYSTEM, value);
+    }
+
+    /**
+     * Reads the value of the user.DOSATTRIB extended attribute
+     */
+    private int getDosAttribute(int fd) throws UnixException {
+        final int size = 24;
+
+        NativeBuffer buffer = NativeBuffers.getNativeBuffer(size);
+        try {
+            int len = LinuxNativeDispatcher
+                .fgetxattr(fd, DOS_XATTR_NAME_AS_BYTES, buffer.address(), size);
+
+            if (len > 0) {
+                // ignore null terminator
+                if (unsafe.getByte(buffer.address()+len-1) == 0)
+                    len--;
+
+                // convert to String and parse
+                byte[] buf = new byte[len];
+                unsafe.copyMemory(null, buffer.address(), buf,
+                    Unsafe.ARRAY_BYTE_BASE_OFFSET, len);
+                String value = new String(buf); // platform encoding
+
+                // should be something like 0x20
+                if (value.length() >= 3 && value.startsWith("0x")) {
+                    try {
+                        return Integer.parseInt(value.substring(2), 16);
+                    } catch (NumberFormatException x) {
+                        // ignore
+                    }
+                }
+            }
+            throw new UnixException("Value of " + DOS_XATTR_NAME + " attribute is invalid");
+        } catch (UnixException x) {
+            // default value when attribute does not exist
+            if (x.errno() == ENODATA)
+                return 0;
+            throw x;
+        } finally {
+            buffer.release();
+        }
+    }
+
+    /**
+     * Updates the value of the user.DOSATTRIB extended attribute
+     */
+    private void updateDosAttribute(int flag, boolean enable) throws IOException {
+        file.checkWrite();
+
+        int fd = file.openForAttributeAccess(followLinks);
+        try {
+            int oldValue = getDosAttribute(fd);
+            int newValue = oldValue;
+            if (enable) {
+                newValue |= flag;
+            } else {
+                newValue &= ~flag;
+            }
+            if (newValue != oldValue) {
+                byte[] value = ("0x" + Integer.toHexString(newValue)).getBytes();
+                NativeBuffer buffer = NativeBuffers.asNativeBuffer(value);
+                try {
+                    LinuxNativeDispatcher.fsetxattr(fd, DOS_XATTR_NAME_AS_BYTES,
+                        buffer.address(), value.length+1);
+                } finally {
+                    buffer.release();
+                }
+            }
+        } catch (UnixException x) {
+            x.rethrowAsIOException(file);
+        } finally {
+            close(fd);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxFileStore.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.util.*;
+import java.io.IOException;
+
+/**
+ * Linux implementation of FileStore
+ */
+
+class LinuxFileStore
+    extends UnixFileStore
+{
+    // used when checking if extended attributes are enabled or not
+    private volatile boolean xattrChecked;
+    private volatile boolean xattrEnabled;
+
+    LinuxFileStore(UnixPath file) throws IOException {
+        super(file);
+    }
+
+    LinuxFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException {
+        super(fs, entry);
+    }
+
+    /**
+     * Finds, and returns, the mount entry for the file system where the file
+     * resides.
+     */
+    @Override
+    UnixMountEntry findMountEntry() throws IOException {
+        UnixFileSystem fs = file().getFileSystem();
+
+        // step 1: get realpath
+        UnixPath path = null;
+        try {
+            byte[] rp = UnixNativeDispatcher.realpath(file());
+            path = new UnixPath(fs, rp);
+        } catch (UnixException x) {
+            x.rethrowAsIOException(file());
+        }
+
+        // step 2: find mount point
+        UnixPath parent = path.getParent();
+        while (parent != null) {
+            UnixFileAttributes attrs = null;
+            try {
+                attrs = UnixFileAttributes.get(parent, true);
+            } catch (UnixException x) {
+                x.rethrowAsIOException(parent);
+            }
+            if (attrs.dev() != dev())
+                break;
+            path = parent;
+            parent = parent.getParent();
+        }
+
+        // step 3: lookup mounted file systems
+        byte[] dir = path.asByteArray();
+        for (UnixMountEntry entry: fs.getMountEntries()) {
+            if (Arrays.equals(dir, entry.dir()))
+                return entry;
+        }
+
+        throw new IOException("Mount point not found in mtab");
+    }
+
+    // returns true if extended attributes enabled on file system where given
+    // file resides, returns false if disabled or unable to determine.
+    private boolean isExtendedAttributesEnabled(UnixPath path) {
+        try {
+            int fd = path.openForAttributeAccess(false);
+            try {
+                // fgetxattr returns size if called with size==0
+                LinuxNativeDispatcher.fgetxattr(fd, "user.java".getBytes(), 0L, 0);
+                return true;
+            } catch (UnixException e) {
+                // attribute does not exist
+                if (e.errno() == UnixConstants.ENODATA)
+                    return true;
+            } finally {
+                UnixNativeDispatcher.close(fd);
+            }
+        } catch (IOException ignore) {
+            // nothing we can do
+        }
+        return false;
+    }
+
+    @Override
+    public boolean supportsFileAttributeView(String name) {
+        // support DosFileAttributeView and NamedAttributeView if extended
+        // attributes enabled
+        if (name.equals("dos") || name.equals("xattr")) {
+            // lookup fstypes.properties
+            FeatureStatus status = checkIfFeaturePresent("user_xattr");
+            if (status == FeatureStatus.PRESENT)
+                return true;
+            if (status == FeatureStatus.NOT_PRESENT)
+                return false;
+
+            // if file system is mounted with user_xattr option then assume
+            // extended attributes are enabled
+            if ((entry().hasOption("user_xattr")))
+                return true;
+
+            // user_xattr option not present but we special-case ext3/4 as we
+            // know that extended attributes are not enabled by default.
+            if (entry().fstype().equals("ext3") || entry().fstype().equals("ext4"))
+                return false;
+
+            // not ext3/4 so probe mount point
+            if (!xattrChecked) {
+                UnixPath dir = new UnixPath(file().getFileSystem(), entry().dir());
+                xattrEnabled = isExtendedAttributesEnabled(dir);
+                xattrChecked = true;
+            }
+            return xattrEnabled;
+        }
+
+        return super.supportsFileAttributeView(name);
+    }
+
+    @Override
+    boolean isLoopback() {
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+import java.security.AccessController;
+import sun.security.action.GetPropertyAction;
+import static sun.nio.fs.LinuxNativeDispatcher.*;
+
+/**
+ * Linux implementation of FileSystem
+ */
+
+class LinuxFileSystem extends UnixFileSystem {
+    private final boolean hasInotify;
+    private final boolean hasAtSysCalls;
+
+    LinuxFileSystem(UnixFileSystemProvider provider, String dir) {
+        super(provider, dir);
+
+        // assume X.Y[-Z] format
+        String osversion = AccessController
+            .doPrivileged(new GetPropertyAction("os.version"));
+        String[] vers = osversion.split("\\.", 0);
+        assert vers.length >= 2;
+
+        int majorVersion = Integer.parseInt(vers[0]);
+        int minorVersion = Integer.parseInt(vers[1]);
+        int microVersion = 0;
+        if (vers.length > 2) {
+            String[] microVers = vers[2].split("-", 0);
+            microVersion = (microVers.length > 0) ?
+                Integer.parseInt(microVers[0]) : 0;
+        }
+
+        // inotify available since 2.6.13
+        this.hasInotify = ((majorVersion > 2) ||
+            (majorVersion == 2 && minorVersion > 6) ||
+            ((majorVersion == 2) && (minorVersion == 6) && (microVersion >= 13)));
+
+        // openat etc. available since 2.6.16
+        this.hasAtSysCalls = ((majorVersion > 2) ||
+            (majorVersion == 2 && minorVersion > 6) ||
+            ((majorVersion == 2) && (minorVersion == 6) && (microVersion >= 16)));
+    }
+
+    @Override
+    public WatchService newWatchService()
+        throws IOException
+    {
+        if (hasInotify) {
+            return new LinuxWatchService(this);
+        } else {
+            // use polling implementation on older kernels
+            return new PollingWatchService();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <V extends FileAttributeView> V newFileAttributeView(Class<V> 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 FileAttributeView newFileAttributeView(String name,
+                                                  UnixPath file,
+                                                  LinkOption... options)
+    {
+        if (name.equals("dos"))
+            return new LinuxDosFileAttributeView(file, followLinks(options));
+        if (name.equals("xattr"))
+            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<String> supportedFileAttributeViews =
+            supportedFileAttributeViews();
+        private static Set<String> supportedFileAttributeViews() {
+            Set<String> result = new HashSet<String>();
+            result.addAll(UnixFileSystem.standardFileAttributeViews());
+            // additional Linux-specific views
+            result.add("dos");
+            result.add("xattr");
+            return Collections.unmodifiableSet(result);
+        }
+    }
+
+    @Override
+    public Set<String> supportedFileAttributeViews() {
+        return SupportedFileFileAttributeViewsHolder.supportedFileAttributeViews;
+    }
+
+    @Override
+    void copyNonPosixAttributes(int ofd, int nfd) {
+        LinuxUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd);
+    }
+
+    @Override
+    boolean supportsSecureDirectoryStreams() {
+        return hasAtSysCalls;
+    }
+
+    /**
+     * Returns object to iterate over entries in /etc/mtab
+     */
+    @Override
+    Iterable<UnixMountEntry> getMountEntries() {
+        ArrayList<UnixMountEntry> entries = new ArrayList<UnixMountEntry>();
+        try {
+            long fp = setmntent("/etc/mtab".getBytes(), "r".getBytes());
+            try {
+                for (;;) {
+                    UnixMountEntry entry = new UnixMountEntry();
+                    int res = getextmntent(fp, entry);
+                    if (res < 0)
+                        break;
+                    entries.add(entry);
+                }
+            } finally {
+                endmntent(fp);
+            }
+
+        } catch (UnixException x) {
+            // nothing we can do
+        }
+        return entries;
+    }
+
+    @Override
+    FileStore getFileStore(UnixPath path) throws IOException {
+        return new LinuxFileStore(path);
+    }
+
+    @Override
+    FileStore getFileStore(UnixMountEntry entry) throws IOException {
+        return new LinuxFileStore(this, entry);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystemProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+/**
+ * Linux implementation of FileSystemProvider
+ */
+
+public class LinuxFileSystemProvider extends UnixFileSystemProvider {
+    public LinuxFileSystemProvider() {
+        super();
+    }
+
+    @Override
+    LinuxFileSystem newFileSystem(String dir) {
+        return new LinuxFileSystem(this, dir);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxNativeDispatcher.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Linux specific system calls.
+ */
+
+class LinuxNativeDispatcher extends UnixNativeDispatcher {
+    private LinuxNativeDispatcher() { }
+
+   /**
+    * FILE *setmntent(const char *filename, const char *type);
+    */
+    static long setmntent(byte[] filename, byte[] type) throws UnixException {
+        NativeBuffer pathBuffer = NativeBuffers.asNativeBuffer(filename);
+        NativeBuffer typeBuffer = NativeBuffers.asNativeBuffer(type);
+        try {
+            return setmntent0(pathBuffer.address(), typeBuffer.address());
+        } finally {
+            typeBuffer.release();
+            pathBuffer.release();
+        }
+    }
+    private static native long setmntent0(long pathAddress, long typeAddress)
+        throws UnixException;
+
+   /**
+    * int endmntent(FILE* filep);
+    */
+    static native void endmntent(long stream) throws UnixException;
+
+    /**
+     * ssize_t fgetxattr(int filedes, const char *name, void *value, size_t size);
+     */
+    static int fgetxattr(int filedes, byte[] name, long valueAddress,
+                         int valueLen) throws UnixException
+    {
+        NativeBuffer buffer = NativeBuffers.asNativeBuffer(name);
+        try {
+            return fgetxattr0(filedes, buffer.address(), valueAddress, valueLen);
+        } finally {
+            buffer.release();
+        }
+    }
+
+    private static native int fgetxattr0(int filedes, long nameAddress,
+        long valueAdddress, int valueLen) throws UnixException;
+
+    /**
+     *  fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags);
+     */
+    static void fsetxattr(int filedes, byte[] name, long valueAddress,
+        int valueLen) throws UnixException
+    {
+        NativeBuffer buffer = NativeBuffers.asNativeBuffer(name);
+        try {
+            fsetxattr0(filedes, buffer.address(), valueAddress, valueLen);
+        } finally {
+            buffer.release();
+        }
+    }
+
+    private static native void fsetxattr0(int filedes, long nameAddress,
+        long valueAdddress, int valueLen) throws UnixException;
+
+
+    /**
+     * fremovexattr(int filedes, const char *name);
+     */
+    static void fremovexattr(int filedes, byte[] name) throws UnixException {
+        NativeBuffer buffer = NativeBuffers.asNativeBuffer(name);
+        try {
+            fremovexattr0(filedes, buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+
+    private static native void fremovexattr0(int filedes, long nameAddress)
+        throws UnixException;
+
+    /**
+     * size_t flistxattr(int filedes, const char *list, size_t size)
+     */
+    static native int flistxattr(int filedes, long listAddress, int size)
+        throws UnixException;
+
+    // initialize
+    private static native void init();
+
+    static {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                System.loadLibrary("nio");
+                return null;
+        }});
+        init();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.ByteBuffer;
+import java.io.IOException;
+import java.util.*;
+import sun.misc.Unsafe;
+
+import static sun.nio.fs.UnixConstants.*;
+import static sun.nio.fs.LinuxNativeDispatcher.*;
+
+/**
+ * Linux implementation of UserDefinedFileAttributeView using extended attributes.
+ */
+
+class LinuxUserDefinedFileAttributeView
+    extends AbstractUserDefinedFileAttributeView
+{
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    // namespace for extended user attributes
+    private static final String USER_NAMESPACE = "user.";
+
+    // maximum bytes in extended attribute name (includes namespace)
+    private static final int XATTR_NAME_MAX = 255;
+
+    private byte[] nameAsBytes(UnixPath file, String name) throws IOException {
+        if (name == null)
+            throw new NullPointerException("'name' is null");
+        name = USER_NAMESPACE + name;
+        byte[] bytes = name.getBytes();
+        if (bytes.length > XATTR_NAME_MAX) {
+            throw new FileSystemException(file.getPathForExecptionMessage(),
+                null, "'" + name + "' is too big");
+        }
+        return bytes;
+    }
+
+    // Parses buffer as array of NULL-terminated C strings.
+    private List<String> asList(long address, int size) {
+        final List<String> list = new ArrayList<String>();
+        int start = 0;
+        int pos = 0;
+        while (pos < size) {
+            if (unsafe.getByte(address + pos) == 0) {
+                int len = pos - start;
+                byte[] value = new byte[len];
+                unsafe.copyMemory(null, address+start, value,
+                    Unsafe.ARRAY_BYTE_BASE_OFFSET, len);
+                String s = new String(value);
+                if (s.startsWith(USER_NAMESPACE)) {
+                    s = s.substring(USER_NAMESPACE.length());
+                    list.add(s);
+                }
+                start = pos + 1;
+            }
+            pos++;
+        }
+        return list;
+    }
+
+    private final UnixPath file;
+    private final boolean followLinks;
+
+    LinuxUserDefinedFileAttributeView(UnixPath file, boolean followLinks) {
+        this.file = file;
+        this.followLinks = followLinks;
+    }
+
+    @Override
+    public List<String> list() throws IOException  {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), true, false);
+
+        int fd = file.openForAttributeAccess(followLinks);
+        NativeBuffer buffer = null;
+        try {
+            int size = 1024;
+            buffer = NativeBuffers.getNativeBuffer(size);
+            for (;;) {
+                try {
+                    int n = flistxattr(fd, buffer.address(), size);
+                    List<String> list = asList(buffer.address(), n);
+                    return Collections.unmodifiableList(list);
+                } catch (UnixException x) {
+                    // allocate larger buffer if required
+                    if (x.errno() == ERANGE && size < 32*1024) {
+                        buffer.release();
+                        size *= 2;
+                        buffer = null;
+                        buffer = NativeBuffers.getNativeBuffer(size);
+                        continue;
+                    }
+                    throw new FileSystemException(file.getPathForExecptionMessage(),
+                        null, "Unable to get list of extended attributes: " +
+                        x.getMessage());
+                }
+            }
+        } finally {
+            if (buffer != null)
+                buffer.release();
+            close(fd);
+        }
+    }
+
+    @Override
+    public int size(String name) throws IOException  {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), true, false);
+
+        int fd = file.openForAttributeAccess(followLinks);
+        try {
+            // fgetxattr returns size if called with size==0
+            return fgetxattr(fd, nameAsBytes(file,name), 0L, 0);
+        } catch (UnixException x) {
+            throw new FileSystemException(file.getPathForExecptionMessage(),
+                null, "Unable to get size of extended attribute '" + name +
+                "': " + x.getMessage());
+        } finally {
+            close(fd);
+        }
+    }
+
+    @Override
+    public int read(String name, ByteBuffer dst) throws IOException {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), true, false);
+
+        if (dst.isReadOnly())
+            throw new IllegalArgumentException("Read-only buffer");
+        int pos = dst.position();
+        int lim = dst.limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+
+        NativeBuffer nb;
+        long address;
+        if (dst instanceof sun.nio.ch.DirectBuffer) {
+            nb = null;
+            address = ((sun.nio.ch.DirectBuffer)dst).address() + pos;
+        } else {
+            // substitute with native buffer
+            nb = NativeBuffers.getNativeBuffer(rem);
+            address = nb.address();
+        }
+
+        int fd = file.openForAttributeAccess(followLinks);
+        try {
+            try {
+                int n = fgetxattr(fd, nameAsBytes(file,name), address, rem);
+
+                // if remaining is zero then fgetxattr returns the size
+                if (rem == 0) {
+                    if (n > 0)
+                        throw new UnixException(ERANGE);
+                    return 0;
+                }
+
+                // copy from buffer into backing array if necessary
+                if (nb != null) {
+                    int off = dst.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET;
+                    unsafe.copyMemory(null, address, dst.array(), off, n);
+                }
+                dst.position(pos + n);
+                return n;
+            } catch (UnixException x) {
+                String msg = (x.errno() == ERANGE) ?
+                    "Insufficient space in buffer" : x.getMessage();
+                throw new FileSystemException(file.getPathForExecptionMessage(),
+                    null, "Error reading extended attribute '" + name + "': " + msg);
+            } finally {
+                close(fd);
+            }
+        } finally {
+            if (nb != null)
+                nb.release();
+        }
+    }
+
+    @Override
+    public int write(String name, ByteBuffer src) throws IOException {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), false, true);
+
+        int pos = src.position();
+        int lim = src.limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+
+        NativeBuffer nb;
+        long address;
+        if (src instanceof sun.nio.ch.DirectBuffer) {
+            nb = null;
+            address = ((sun.nio.ch.DirectBuffer)src).address() + pos;
+        } else {
+            // substitute with native buffer
+            nb = NativeBuffers.getNativeBuffer(rem);
+            address = nb.address();
+
+            if (src.hasArray()) {
+                // copy from backing array into buffer
+                int off = src.arrayOffset() + pos + Unsafe.ARRAY_BYTE_BASE_OFFSET;
+                unsafe.copyMemory(src.array(), off, null, address, rem);
+            } else {
+                // backing array not accessible so transfer via temporary array
+                byte[] tmp = new byte[rem];
+                src.get(tmp);
+                src.position(pos);  // reset position as write may fail
+                unsafe.copyMemory(tmp, Unsafe.ARRAY_BYTE_BASE_OFFSET, null,
+                    address, rem);
+            }
+        }
+
+        int fd = file.openForAttributeAccess(followLinks);
+        try {
+            try {
+                fsetxattr(fd, nameAsBytes(file,name), address, rem);
+                src.position(pos + rem);
+                return rem;
+            } catch (UnixException x) {
+                throw new FileSystemException(file.getPathForExecptionMessage(),
+                    null, "Error writing extended attribute '" + name + "': " +
+                    x.getMessage());
+            } finally {
+                close(fd);
+            }
+        } finally {
+            if (nb != null)
+                nb.release();
+        }
+    }
+
+    @Override
+    public void delete(String name) throws IOException {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), false, true);
+
+        int fd = file.openForAttributeAccess(followLinks);
+        try {
+            fremovexattr(fd, nameAsBytes(file,name));
+        } catch (UnixException x) {
+            throw new FileSystemException(file.getPathForExecptionMessage(),
+                null, "Unable to delete extended attribute '" + name + "': " + x.getMessage());
+        } finally {
+            close(fd);
+        }
+    }
+
+    /**
+     * Used by copyTo/moveTo to copy extended attributes from source to target.
+     *
+     * @param   ofd
+     *          file descriptor for source file
+     * @param   nfd
+     *          file descriptor for target file
+     */
+    static void copyExtendedAttributes(int ofd, int nfd) {
+        NativeBuffer buffer = null;
+        try {
+
+            // call flistxattr to get list of extended attributes.
+            int size = 1024;
+            buffer = NativeBuffers.getNativeBuffer(size);
+            for (;;) {
+                try {
+                    size = flistxattr(ofd, buffer.address(), size);
+                    break;
+                } catch (UnixException x) {
+                    // allocate larger buffer if required
+                    if (x.errno() == ERANGE && size < 32*1024) {
+                        buffer.release();
+                        size *= 2;
+                        buffer = null;
+                        buffer = NativeBuffers.getNativeBuffer(size);
+                        continue;
+                    }
+
+                    // unable to get list of attributes
+                    return;
+                }
+            }
+
+            // parse buffer as array of NULL-terminated C strings.
+            long address = buffer.address();
+            int start = 0;
+            int pos = 0;
+            while (pos < size) {
+                if (unsafe.getByte(address + pos) == 0) {
+                    // extract attribute name and copy attribute to target.
+                    // FIXME: We can avoid needless copying by using address+pos
+                    // as the address of the name.
+                    int len = pos - start;
+                    byte[] name = new byte[len];
+                    unsafe.copyMemory(null, address+start, name,
+                        Unsafe.ARRAY_BYTE_BASE_OFFSET, len);
+                    try {
+                        copyExtendedAttribute(ofd, name, nfd);
+                    } catch (UnixException ignore) {
+                        // ignore
+                    }
+                    start = pos + 1;
+                }
+                pos++;
+            }
+
+        } finally {
+            if (buffer != null)
+                buffer.release();
+        }
+    }
+
+    private static void copyExtendedAttribute(int ofd, byte[] name, int nfd)
+        throws UnixException
+    {
+        int size = fgetxattr(ofd, name, 0L, 0);
+        NativeBuffer buffer = NativeBuffers.getNativeBuffer(size);
+        try {
+            long address = buffer.address();
+            size = fgetxattr(ofd, name, address, size);
+            fsetxattr(nfd, name, address, size);
+        } finally {
+            buffer.release();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxWatchService.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,466 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.*;
+import java.io.IOException;
+import sun.misc.Unsafe;
+
+import static sun.nio.fs.UnixNativeDispatcher.*;
+import static sun.nio.fs.UnixConstants.*;
+
+/**
+ * Linux implementation of WatchService based on inotify.
+ *
+ * In summary a background thread polls inotify plus a socket used for the wakeup
+ * mechanism. Requests to add or remove a watch, or close the watch service,
+ * cause the thread to wakeup and process the request. Events are processed
+ * by the thread which causes it to signal/queue the corresponding watch keys.
+ */
+
+class LinuxWatchService
+    extends AbstractWatchService
+{
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    // background thread to read change events
+    private final Poller poller;
+
+    LinuxWatchService(UnixFileSystem fs) throws IOException {
+        // initialize inotify
+        int ifd = - 1;
+        try {
+            ifd = inotifyInit();
+        } catch (UnixException x) {
+            throw new IOException(x.errorString());
+        }
+
+        // configure inotify to be non-blocking
+        // create socketpair used in the close mechanism
+        int sp[] = new int[2];
+        try {
+            configureBlocking(ifd, false);
+            socketpair(sp);
+            configureBlocking(sp[0], false);
+        } catch (UnixException x) {
+            UnixNativeDispatcher.close(ifd);
+            throw new IOException(x.errorString());
+        }
+
+        this.poller = new Poller(fs, this, ifd, sp);
+        this.poller.start();
+    }
+
+    @Override
+    WatchKey register(Path dir,
+                      WatchEvent.Kind<?>[] events,
+                      WatchEvent.Modifier... modifiers)
+         throws IOException
+    {
+        // delegate to poller
+        return poller.register(dir, events, modifiers);
+    }
+
+    @Override
+    void implClose() throws IOException {
+        // delegate to poller
+        poller.close();
+    }
+
+    /**
+     * WatchKey implementation
+     */
+    private static class LinuxWatchKey extends AbstractWatchKey {
+        // inotify descriptor
+        private final int ifd;
+        // watch descriptor
+        private volatile int wd;
+
+        LinuxWatchKey(LinuxWatchService watcher, int ifd, int wd) {
+            super(watcher);
+            this.ifd = ifd;
+            this.wd = wd;
+        }
+
+        int descriptor() {
+            return wd;
+        }
+
+        void invalidate(boolean remove) {
+            if (remove) {
+                try {
+                    inotifyRmWatch(ifd, wd);
+                } catch (UnixException x) {
+                    // ignore
+                }
+            }
+            wd = -1;
+        }
+
+        @Override
+        public boolean isValid() {
+            return (wd != -1);
+        }
+
+        @Override
+        public void cancel() {
+            if (isValid()) {
+                // delegate to poller
+                ((LinuxWatchService)watcher()).poller.cancel(this);
+            }
+        }
+    }
+
+    /**
+     * Background thread to read from inotify
+     */
+    private static class Poller extends AbstractPoller {
+        /**
+         * struct inotify_event {
+         *     int          wd;
+         *     uint32_t     mask;
+         *     uint32_t     len;
+         *     char name    __flexarr;  // present if len > 0
+         * } act_t;
+         */
+        private static final int SIZEOF_INOTIFY_EVENT  = eventSize();
+        private static final int[] offsets             = eventOffsets();
+        private static final int OFFSETOF_WD           = offsets[0];
+        private static final int OFFSETOF_MASK         = offsets[1];
+        private static final int OFFSETOF_LEN          = offsets[3];
+        private static final int OFFSETOF_NAME         = offsets[4];
+
+        private static final int IN_MODIFY          = 0x00000002;
+        private static final int IN_ATTRIB          = 0x00000004;
+        private static final int IN_MOVED_FROM      = 0x00000040;
+        private static final int IN_MOVED_TO        = 0x00000080;
+        private static final int IN_CREATE          = 0x00000100;
+        private static final int IN_DELETE          = 0x00000200;
+
+        private static final int IN_UNMOUNT         = 0x00002000;
+        private static final int IN_Q_OVERFLOW      = 0x00004000;
+        private static final int IN_IGNORED         = 0x00008000;
+
+        // sizeof buffer for when polling inotify
+        private static final int BUFFER_SIZE = 8192;
+
+        private final UnixFileSystem fs;
+        private final LinuxWatchService watcher;
+
+        // inotify file descriptor
+        private final int ifd;
+        // socketpair used to shutdown polling thread
+        private final int socketpair[];
+        // maps watch descriptor to Key
+        private final Map<Integer,LinuxWatchKey> wdToKey;
+        // address of read buffer
+        private final long address;
+
+        Poller(UnixFileSystem fs, LinuxWatchService watcher, int ifd, int[] sp) {
+            this.fs = fs;
+            this.watcher = watcher;
+            this.ifd = ifd;
+            this.socketpair = sp;
+            this.wdToKey = new HashMap<Integer,LinuxWatchKey>();
+            this.address = unsafe.allocateMemory(BUFFER_SIZE);
+        }
+
+        @Override
+        void wakeup() throws IOException {
+            // write to socketpair to wakeup polling thread
+            try {
+                write(socketpair[1], address, 1);
+            } catch (UnixException x) {
+                throw new IOException(x.errorString());
+            }
+        }
+
+        @Override
+        Object implRegister(Path obj,
+                            Set<? extends WatchEvent.Kind<?>> events,
+                            WatchEvent.Modifier... modifiers)
+        {
+            UnixPath dir = (UnixPath)obj;
+
+            int mask = 0;
+            for (WatchEvent.Kind<?> event: events) {
+                if (event == StandardWatchEventKind.ENTRY_CREATE) {
+                    mask |= IN_CREATE | IN_MOVED_TO;
+                    continue;
+                }
+                if (event == StandardWatchEventKind.ENTRY_DELETE) {
+                    mask |= IN_DELETE | IN_MOVED_FROM;
+                    continue;
+                }
+                if (event == StandardWatchEventKind.ENTRY_MODIFY) {
+                    mask |= IN_MODIFY | IN_ATTRIB;
+                    continue;
+                }
+            }
+
+            // no modifiers supported at this time
+            if (modifiers.length > 0) {
+                for (WatchEvent.Modifier modifier: modifiers) {
+                    if (modifier == null)
+                        return new NullPointerException();
+                    if (modifier instanceof com.sun.nio.file.SensitivityWatchEventModifier)
+                        continue; // ignore
+                    return new UnsupportedOperationException("Modifier not supported");
+                }
+            }
+
+            // check file is directory
+            UnixFileAttributes attrs = null;
+            try {
+                attrs = UnixFileAttributes.get(dir, true);
+            } catch (UnixException x) {
+                return x.asIOException(dir);
+            }
+            if (!attrs.isDirectory()) {
+                return new NotDirectoryException(dir.getPathForExecptionMessage());
+            }
+
+            // register with inotify (replaces existing mask if already registered)
+            int wd = -1;
+            try {
+                NativeBuffer buffer =
+                    NativeBuffers.asNativeBuffer(dir.getByteArrayForSysCalls());
+                try {
+                    wd = inotifyAddWatch(ifd, buffer.address(), mask);
+                } finally {
+                    buffer.release();
+                }
+            } catch (UnixException x) {
+                if (x.errno() == ENOSPC) {
+                    return new IOException("User limit of inotify watches reached");
+                }
+                return x.asIOException(dir);
+            }
+
+            // ensure watch descriptor is in map
+            LinuxWatchKey key = wdToKey.get(wd);
+            if (key == null) {
+                key = new LinuxWatchKey(watcher, ifd, wd);
+                wdToKey.put(wd, key);
+            }
+            return key;
+        }
+
+        // cancel single key
+        @Override
+        void implCancelKey(WatchKey obj) {
+            LinuxWatchKey key = (LinuxWatchKey)obj;
+            if (key.isValid()) {
+                wdToKey.remove(key.descriptor());
+                key.invalidate(true);
+            }
+        }
+
+        // close watch service
+        @Override
+        void implCloseAll() {
+            // invalidate all keys
+            for (Map.Entry<Integer,LinuxWatchKey> entry: wdToKey.entrySet()) {
+                entry.getValue().invalidate(true);
+            }
+            wdToKey.clear();
+
+            // free resources
+            unsafe.freeMemory(address);
+            UnixNativeDispatcher.close(socketpair[0]);
+            UnixNativeDispatcher.close(socketpair[1]);
+            UnixNativeDispatcher.close(ifd);
+        }
+
+        /**
+         * Poller main loop
+         */
+        @Override
+        public void run() {
+            try {
+                for (;;) {
+                    int nReady, bytesRead;
+
+                    // wait for close or inotify event
+                    nReady = poll(ifd, socketpair[0]);
+
+                    // read from inotify
+                    try {
+                        bytesRead = read(ifd, address, BUFFER_SIZE);
+                    } catch (UnixException x) {
+                        if (x.errno() != EAGAIN)
+                            throw x;
+                        bytesRead = 0;
+                    }
+
+                    // process any pending requests
+                    if ((nReady > 1) || (nReady == 1 && bytesRead == 0)) {
+                        try {
+                            read(socketpair[0], address, BUFFER_SIZE);
+                            boolean shutdown = processRequests();
+                            if (shutdown)
+                                break;
+                        } catch (UnixException x) {
+                            if (x.errno() != UnixConstants.EAGAIN)
+                                throw x;
+                        }
+                    }
+
+                    // iterate over buffer to decode events
+                    int offset = 0;
+                    while (offset < bytesRead) {
+                        long event = address + offset;
+                        int wd = unsafe.getInt(event + OFFSETOF_WD);
+                        int mask = unsafe.getInt(event + OFFSETOF_MASK);
+                        int len = unsafe.getInt(event + OFFSETOF_LEN);
+
+                        // file name
+                        UnixPath name = null;
+                        if (len > 0) {
+                            int actual = len;
+
+                            // null-terminated and maybe additional null bytes to
+                            // align the next event
+                            while (actual > 0) {
+                                long last = event + OFFSETOF_NAME + actual - 1;
+                                if (unsafe.getByte(last) != 0)
+                                    break;
+                                actual--;
+                            }
+                            if (actual > 0) {
+                                byte[] buf = new byte[actual];
+                                unsafe.copyMemory(null, event + OFFSETOF_NAME,
+                                    buf, Unsafe.ARRAY_BYTE_BASE_OFFSET, actual);
+                                name = new UnixPath(fs, buf);
+                            }
+                        }
+
+                        // process event
+                        processEvent(wd, mask, name);
+
+                        offset += (SIZEOF_INOTIFY_EVENT + len);
+                    }
+                }
+            } catch (UnixException x) {
+                x.printStackTrace();
+            }
+        }
+
+
+        /**
+         * map inotify event to WatchEvent.Kind
+         */
+        private WatchEvent.Kind<?> maskToEventKind(int mask) {
+            if ((mask & IN_MODIFY) > 0)
+                return StandardWatchEventKind.ENTRY_MODIFY;
+            if ((mask & IN_ATTRIB) > 0)
+                return StandardWatchEventKind.ENTRY_MODIFY;
+            if ((mask & IN_CREATE) > 0)
+                return StandardWatchEventKind.ENTRY_CREATE;
+            if ((mask & IN_MOVED_TO) > 0)
+                return StandardWatchEventKind.ENTRY_CREATE;
+            if ((mask & IN_DELETE) > 0)
+                return StandardWatchEventKind.ENTRY_DELETE;
+            if ((mask & IN_MOVED_FROM) > 0)
+                return StandardWatchEventKind.ENTRY_DELETE;
+            return null;
+        }
+
+        /**
+         * Process event from inotify
+         */
+        private void processEvent(int wd, int mask, final UnixPath name) {
+            // overflow - signal all keys
+            if ((mask & IN_Q_OVERFLOW) > 0) {
+                for (Map.Entry<Integer,LinuxWatchKey> entry: wdToKey.entrySet()) {
+                    entry.getValue()
+                        .signalEvent(StandardWatchEventKind.OVERFLOW, null);
+                }
+                return;
+            }
+
+            // lookup wd to get key
+            LinuxWatchKey key = wdToKey.get(wd);
+            if (key == null)
+                return; // should not happen
+
+            // file deleted
+            if ((mask & IN_IGNORED) > 0) {
+                wdToKey.remove(wd);
+                key.invalidate(false);
+                key.signal();
+                return;
+            }
+
+            // event for directory itself
+            if (name == null)
+                return;
+
+            // map to event and queue to key
+            WatchEvent.Kind<?> kind = maskToEventKind(mask);
+            if (kind != null) {
+                key.signalEvent(kind, name);
+            }
+        }
+    }
+
+    // -- native methods --
+
+    private static native void init();
+
+    // sizeof inotify_event
+    private static native int eventSize();
+
+    // offsets of inotify_event
+    private static native int[] eventOffsets();
+
+    private static native int inotifyInit() throws UnixException;
+
+    private static native int inotifyAddWatch(int fd, long pathAddress, int mask)
+        throws UnixException;
+
+    private static native void inotifyRmWatch(int fd, int wd)
+        throws UnixException;
+
+    private static native void configureBlocking(int fd, boolean blocking)
+        throws UnixException;
+
+    private static native void socketpair(int[] sv) throws UnixException;
+
+    private static native int poll(int fd1, int fd2) throws UnixException;
+
+    static {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                System.loadLibrary("nio");
+                return null;
+        }});
+        init();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,408 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.io.IOException;
+import sun.misc.Unsafe;
+
+import static sun.nio.fs.UnixConstants.*;
+import static sun.nio.fs.SolarisConstants.*;
+import static sun.nio.fs.SolarisNativeDispatcher.*;
+
+
+/**
+ * Solaris implementation of AclFileAttributeView with native support for
+ * NFSv4 ACLs on ZFS.
+ */
+
+class SolarisAclFileAttributeView
+    extends AbstractAclFileAttributeView
+{
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    // Maximum number of entries allowed in an ACL
+    private static final int MAX_ACL_ENTRIES = 1024;
+
+    /**
+     * typedef struct ace {
+     *     uid_t        a_who;
+     *     uitn32_t     a_access_mark;
+     *     uint16_t     a_flags;
+     *     uint16_t     a_type;
+     * } act_t;
+     */
+    private static final short SIZEOF_ACE_T     = 12;
+    private static final short OFFSETOF_UID     = 0;
+    private static final short OFFSETOF_MASK    = 4;
+    private static final short OFFSETOF_FLAGS   = 8;
+    private static final short OFFSETOF_TYPE    = 10;
+
+    private final UnixPath file;
+    private final boolean followLinks;
+
+    SolarisAclFileAttributeView(UnixPath file, boolean followLinks) {
+        this.file = file;
+        this.followLinks = followLinks;
+    }
+
+    /**
+     * Permission checks to access file
+     */
+    private void checkAccess(UnixPath file,
+                             boolean checkRead,
+                             boolean checkWrite)
+    {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            if (checkRead)
+                file.checkRead();
+            if (checkWrite)
+                file.checkWrite();
+            sm.checkPermission(new RuntimePermission("accessUserInformation"));
+        }
+    }
+
+    /**
+     * Encode the ACL to the given buffer
+     */
+    private static void encode(List<AclEntry> acl, long address) {
+        long offset = address;
+        for (AclEntry ace: acl) {
+            int flags = 0;
+
+            // map UserPrincipal to uid and flags
+            UserPrincipal who = ace.principal();
+            if (!(who instanceof UnixUserPrincipals))
+                throw new ProviderMismatchException();
+            UnixUserPrincipals.User user = (UnixUserPrincipals.User)who;
+            int uid;
+            if (user.isSpecial()) {
+                uid = -1;
+                if (who.getName().equals(UnixUserPrincipals.SPECIAL_OWNER.getName()))
+                    flags |= ACE_OWNER;
+                else if (who.getName().equals(UnixUserPrincipals.SPECIAL_GROUP.getName()))
+                    flags |= ACE_GROUP;
+                else if (who.getName().equals(UnixUserPrincipals.SPECIAL_EVERYONE.getName()))
+                    flags |= ACE_EVERYONE;
+                else
+                    throw new AssertionError("Unable to map special identifier");
+            } else {
+                if (user instanceof UnixUserPrincipals.Group) {
+                    uid = user.gid();
+                    flags |= ACE_IDENTIFIER_GROUP;
+                } else {
+                    uid = user.uid();
+                }
+            }
+
+            // map ACE type
+            int type;
+            switch (ace.type()) {
+                case ALLOW:
+                    type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+                    break;
+                case DENY:
+                    type = ACE_ACCESS_DENIED_ACE_TYPE;
+                    break;
+                case AUDIT:
+                    type = ACE_SYSTEM_AUDIT_ACE_TYPE;
+                    break;
+                case ALARM:
+                    type = ACE_SYSTEM_ALARM_ACE_TYPE;
+                    break;
+                default:
+                    throw new AssertionError("Unable to map ACE type");
+            }
+
+            // map permissions
+            Set<AclEntryPermission> aceMask = ace.permissions();
+            int mask = 0;
+            if (aceMask.contains(AclEntryPermission.READ_DATA))
+                mask |= ACE_READ_DATA;
+            if (aceMask.contains(AclEntryPermission.WRITE_DATA))
+                mask |= ACE_WRITE_DATA;
+            if (aceMask.contains(AclEntryPermission.APPEND_DATA))
+                mask |= ACE_APPEND_DATA;
+            if (aceMask.contains(AclEntryPermission.READ_NAMED_ATTRS))
+                mask |= ACE_READ_NAMED_ATTRS;
+            if (aceMask.contains(AclEntryPermission.WRITE_NAMED_ATTRS))
+                mask |= ACE_WRITE_NAMED_ATTRS;
+            if (aceMask.contains(AclEntryPermission.EXECUTE))
+                mask |= ACE_EXECUTE;
+            if (aceMask.contains(AclEntryPermission.DELETE_CHILD))
+                mask |= ACE_DELETE_CHILD;
+            if (aceMask.contains(AclEntryPermission.READ_ATTRIBUTES))
+                mask |= ACE_READ_ATTRIBUTES;
+            if (aceMask.contains(AclEntryPermission.WRITE_ATTRIBUTES))
+                mask |= ACE_WRITE_ATTRIBUTES;
+            if (aceMask.contains(AclEntryPermission.DELETE))
+                mask |= ACE_DELETE;
+            if (aceMask.contains(AclEntryPermission.READ_ACL))
+                mask |= ACE_READ_ACL;
+            if (aceMask.contains(AclEntryPermission.WRITE_ACL))
+                mask |= ACE_WRITE_ACL;
+            if (aceMask.contains(AclEntryPermission.WRITE_OWNER))
+                mask |= ACE_WRITE_OWNER;
+            if (aceMask.contains(AclEntryPermission.SYNCHRONIZE))
+                mask |= ACE_SYNCHRONIZE;
+
+            // FIXME - it would be desirable to know here if the file is a
+            // directory or not. Solaris returns EINVAL if an ACE has a directory
+            // -only flag and the file is not a directory.
+            Set<AclEntryFlag> aceFlags = ace.flags();
+            if (aceFlags.contains(AclEntryFlag.FILE_INHERIT))
+                flags |= ACE_FILE_INHERIT_ACE;
+            if (aceFlags.contains(AclEntryFlag.DIRECTORY_INHERIT))
+                flags |= ACE_DIRECTORY_INHERIT_ACE;
+            if (aceFlags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT))
+                flags |= ACE_NO_PROPAGATE_INHERIT_ACE;
+            if (aceFlags.contains(AclEntryFlag.INHERIT_ONLY))
+                flags |= ACE_INHERIT_ONLY_ACE;
+
+            unsafe.putInt(offset + OFFSETOF_UID, uid);
+            unsafe.putInt(offset + OFFSETOF_MASK, mask);
+            unsafe.putShort(offset + OFFSETOF_FLAGS, (short)flags);
+            unsafe.putShort(offset + OFFSETOF_TYPE, (short)type);
+
+            offset += SIZEOF_ACE_T;
+        }
+    }
+
+    /**
+     * Decode the buffer, returning an ACL
+     */
+    private static List<AclEntry> decode(long address, int n) {
+        ArrayList<AclEntry> acl = new ArrayList<AclEntry>(n);
+        for (int i=0; i<n; i++) {
+            long offset = address + i*SIZEOF_ACE_T;
+
+            int uid = unsafe.getInt(offset + OFFSETOF_UID);
+            int mask = unsafe.getInt(offset + OFFSETOF_MASK);
+            int flags = (int)unsafe.getShort(offset + OFFSETOF_FLAGS);
+            int type = (int)unsafe.getShort(offset + OFFSETOF_TYPE);
+
+            // map uid and flags to UserPrincipal
+            UnixUserPrincipals.User who = null;
+            if (uid == -1) {
+                if ((flags & ACE_OWNER) > 0)
+                    who = UnixUserPrincipals.SPECIAL_OWNER;
+                if ((flags & ACE_GROUP) > 0)
+                    who = UnixUserPrincipals.SPECIAL_GROUP;
+                if ((flags & ACE_EVERYONE) > 0)
+                    who = UnixUserPrincipals.SPECIAL_EVERYONE;
+                if (who == null)
+                    throw new AssertionError("ACE who not handled");
+            } else {
+                // can be gid
+                if ((flags & ACE_IDENTIFIER_GROUP) > 0)
+                    who = UnixUserPrincipals.fromGid(uid);
+                else
+                    who = UnixUserPrincipals.fromUid(uid);
+            }
+
+            AclEntryType aceType = null;
+            switch (type) {
+                case ACE_ACCESS_ALLOWED_ACE_TYPE:
+                    aceType = AclEntryType.ALLOW;
+                    break;
+                case ACE_ACCESS_DENIED_ACE_TYPE:
+                    aceType = AclEntryType.DENY;
+                    break;
+                case ACE_SYSTEM_AUDIT_ACE_TYPE:
+                    aceType = AclEntryType.AUDIT;
+                    break;
+                case ACE_SYSTEM_ALARM_ACE_TYPE:
+                    aceType = AclEntryType.ALARM;
+                    break;
+                default:
+                    assert false;
+            }
+
+            HashSet<AclEntryPermission> aceMask = new HashSet<AclEntryPermission>();
+            if ((mask & ACE_READ_DATA) > 0)
+                aceMask.add(AclEntryPermission.READ_DATA);
+            if ((mask & ACE_WRITE_DATA) > 0)
+                aceMask.add(AclEntryPermission.WRITE_DATA);
+            if ((mask & ACE_APPEND_DATA ) > 0)
+                aceMask.add(AclEntryPermission.APPEND_DATA);
+            if ((mask & ACE_READ_NAMED_ATTRS) > 0)
+                aceMask.add(AclEntryPermission.READ_NAMED_ATTRS);
+            if ((mask & ACE_WRITE_NAMED_ATTRS) > 0)
+                aceMask.add(AclEntryPermission.WRITE_NAMED_ATTRS);
+            if ((mask & ACE_EXECUTE) > 0)
+                aceMask.add(AclEntryPermission.EXECUTE);
+            if ((mask & ACE_DELETE_CHILD ) > 0)
+                aceMask.add(AclEntryPermission.DELETE_CHILD);
+            if ((mask & ACE_READ_ATTRIBUTES) > 0)
+                aceMask.add(AclEntryPermission.READ_ATTRIBUTES);
+            if ((mask & ACE_WRITE_ATTRIBUTES) > 0)
+                aceMask.add(AclEntryPermission.WRITE_ATTRIBUTES);
+            if ((mask & ACE_DELETE) > 0)
+                aceMask.add(AclEntryPermission.DELETE);
+            if ((mask & ACE_READ_ACL) > 0)
+                aceMask.add(AclEntryPermission.READ_ACL);
+            if ((mask & ACE_WRITE_ACL) > 0)
+                aceMask.add(AclEntryPermission.WRITE_ACL);
+            if ((mask & ACE_WRITE_OWNER) > 0)
+                aceMask.add(AclEntryPermission.WRITE_OWNER);
+            if ((mask & ACE_SYNCHRONIZE) > 0)
+                aceMask.add(AclEntryPermission.SYNCHRONIZE);
+
+            HashSet<AclEntryFlag> aceFlags = new HashSet<AclEntryFlag>();
+            if ((flags & ACE_FILE_INHERIT_ACE) > 0)
+                aceFlags.add(AclEntryFlag.FILE_INHERIT);
+            if ((flags & ACE_DIRECTORY_INHERIT_ACE) > 0)
+                aceFlags.add(AclEntryFlag.DIRECTORY_INHERIT);
+            if ((flags & ACE_NO_PROPAGATE_INHERIT_ACE) > 0)
+                aceFlags.add(AclEntryFlag.NO_PROPAGATE_INHERIT);
+            if ((flags & ACE_INHERIT_ONLY_ACE ) > 0)
+                aceFlags.add(AclEntryFlag.INHERIT_ONLY);
+
+            // build the ACL entry and add it to the list
+            AclEntry ace = AclEntry.newBuilder()
+                .setType(aceType)
+                .setPrincipal(who)
+                .setPermissions(aceMask).setFlags(aceFlags).build();
+            acl.add(ace);
+        }
+
+        return acl;
+    }
+
+    // Retrns true if NFSv4 ACLs not enabled on file system
+    private static boolean isAclsEnabled(int fd) {
+        try {
+            long enabled = fpathconf(fd, _PC_ACL_ENABLED);
+            if (enabled == _ACL_ACE_ENABLED)
+                return true;
+        } catch (UnixException x) {
+        }
+        return false;
+    }
+
+    @Override
+    public List<AclEntry> getAcl()
+        throws IOException
+    {
+        // permission check
+        checkAccess(file, true, false);
+
+        // open file (will fail if file is a link and not following links)
+        int fd = file.openForAttributeAccess(followLinks);
+        try {
+            long address = unsafe.allocateMemory(SIZEOF_ACE_T * MAX_ACL_ENTRIES);
+            try {
+                // read ACL and decode it
+                int n = facl(fd, ACE_GETACL, MAX_ACL_ENTRIES, address);
+                assert n >= 0;
+                return decode(address, n);
+            } catch (UnixException x) {
+                if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) {
+                    throw new FileSystemException(file.getPathForExecptionMessage(),
+                        null, x.getMessage() + " (file system does not support NFSv4 ACLs)");
+                }
+                x.rethrowAsIOException(file);
+                return null;    // keep compiler happy
+            } finally {
+                unsafe.freeMemory(address);
+            }
+        } finally {
+            close(fd);
+        }
+    }
+
+    @Override
+    public void setAcl(List<AclEntry> acl) throws IOException {
+        // permission check
+        checkAccess(file, false, true);
+
+        // open file (will fail if file is a link and not following links)
+        int fd = file.openForAttributeAccess(followLinks);
+        try {
+            // SECURITY: need to copy list as can change during processing
+            acl = new ArrayList<AclEntry>(acl);
+            int n = acl.size();
+
+            long address = unsafe.allocateMemory(SIZEOF_ACE_T * n);
+            try {
+                encode(acl, address);
+                facl(fd, ACE_SETACL, n, address);
+            } catch (UnixException x) {
+                if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) {
+                    throw new FileSystemException(file.getPathForExecptionMessage(),
+                        null, x.getMessage() + " (file system does not support NFSv4 ACLs)");
+                }
+                if (x.errno() == EINVAL && (n < 3))
+                    throw new IOException("ACL must contain at least 3 entries");
+                x.rethrowAsIOException(file);
+            } finally {
+                unsafe.freeMemory(address);
+            }
+        } finally {
+            close(fd);
+        }
+    }
+
+    @Override
+    public UserPrincipal getOwner()
+        throws IOException
+    {
+        checkAccess(file, true, false);
+
+        try {
+            UnixFileAttributes attrs =
+                UnixFileAttributes.get(file, followLinks);
+            return UnixUserPrincipals.fromUid(attrs.uid());
+        } catch (UnixException x) {
+            x.rethrowAsIOException(file);
+            return null; // keep compile happy
+        }
+    }
+
+    @Override
+    public void setOwner(UserPrincipal owner) throws IOException {
+        checkAccess(file, true, false);
+
+        if (!(owner instanceof UnixUserPrincipals.User))
+            throw new ProviderMismatchException();
+        if (owner instanceof UnixUserPrincipals.Group)
+            throw new IOException("'owner' parameter is a group");
+        int uid = ((UnixUserPrincipals.User)owner).uid();
+
+        try {
+            if (followLinks) {
+                lchown(file, uid, -1);
+            } else {
+                chown(file, uid, -1);
+            }
+        } catch (UnixException x) {
+            x.rethrowAsIOException(file);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisFileStore.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.io.IOException;
+
+import static sun.nio.fs.UnixNativeDispatcher.*;
+import static sun.nio.fs.SolarisConstants.*;
+
+/**
+ * Solaris implementation of FileStore
+ */
+
+class SolarisFileStore
+    extends UnixFileStore
+{
+    private final boolean xattrEnabled;
+
+    SolarisFileStore(UnixPath file) throws IOException {
+        super(file);
+        this.xattrEnabled = xattrEnabled();
+    }
+
+    SolarisFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException {
+        super(fs, entry);
+        this.xattrEnabled = xattrEnabled();
+    }
+
+    // returns true if extended attributes enabled
+    private boolean xattrEnabled() {
+        long res = 0L;
+        try {
+            res = pathconf(file(), _PC_XATTR_ENABLED);
+        } catch (UnixException x) {
+            // ignore
+        }
+        return (res != 0L);
+    }
+
+    @Override
+    UnixMountEntry findMountEntry() throws IOException {
+        // On Solaris iterate over the entries in the mount table to find device
+        for (UnixMountEntry entry: file().getFileSystem().getMountEntries()) {
+            if (entry.dev() == dev()) {
+                return entry;
+            }
+        }
+        throw new IOException("Device not found in mnttab");
+    }
+
+    @Override
+    public boolean supportsFileAttributeView(String name) {
+        if (name.equals("acl")) {
+            // lookup fstypes.properties
+            FeatureStatus status = checkIfFeaturePresent("nfsv4acl");
+            if (status == FeatureStatus.PRESENT)
+                return true;
+            if (status == FeatureStatus.NOT_PRESENT)
+                return false;
+            // AclFileAttributeView available on ZFS
+            return (type().equals("zfs"));
+        }
+        if (name.equals("xattr")) {
+            // lookup fstypes.properties
+            FeatureStatus status = checkIfFeaturePresent("xattr");
+            if (status == FeatureStatus.PRESENT)
+                return true;
+            if (status == FeatureStatus.NOT_PRESENT)
+                return false;
+            return xattrEnabled;
+        }
+
+        return super.supportsFileAttributeView(name);
+    }
+
+    @Override
+    boolean isLoopback() {
+        return type().equals("lofs");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+import java.security.AccessController;
+import sun.security.action.GetPropertyAction;
+import static sun.nio.fs.UnixNativeDispatcher.*;
+
+/**
+ * Solaris implementation of FileSystem
+ */
+
+class SolarisFileSystem extends UnixFileSystem {
+    private final boolean hasSolaris11Features;
+
+    SolarisFileSystem(UnixFileSystemProvider provider, String dir) {
+        super(provider, dir);
+
+        // check os.version
+        String osversion = AccessController
+            .doPrivileged(new GetPropertyAction("os.version"));
+        String[] vers = osversion.split("\\.", 0);
+        assert vers.length >= 2;
+        int majorVersion = Integer.parseInt(vers[0]);
+        int minorVersion = Integer.parseInt(vers[1]);
+        this.hasSolaris11Features =
+            (majorVersion > 5 || (majorVersion == 5 && minorVersion >= 11));
+    }
+
+    @Override
+    boolean isSolaris() {
+        return true;
+    }
+
+    @Override
+    public WatchService newWatchService()
+        throws IOException
+    {
+        // FEN available since Solaris 11
+        if (hasSolaris11Features) {
+            return new SolarisWatchService(this);
+        } else {
+            return new PollingWatchService();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <V extends FileAttributeView> V newFileAttributeView(Class<V> 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 FileAttributeView newFileAttributeView(String name,
+                                                     UnixPath file,
+                                                     LinkOption... options)
+    {
+        if (name.equals("acl"))
+            return new SolarisAclFileAttributeView(file, followLinks(options));
+        if (name.equals("xattr"))
+            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<String> supportedFileAttributeViews =
+            supportedFileAttributeViews();
+        private static Set<String> supportedFileAttributeViews() {
+            Set<String> result = new HashSet<String>();
+            result.addAll(UnixFileSystem.standardFileAttributeViews());
+            // additional Solaris-specific views
+            result.add("acl");
+            result.add("xattr");
+            return Collections.unmodifiableSet(result);
+        }
+    }
+
+    @Override
+    public Set<String> supportedFileAttributeViews() {
+        return SupportedFileFileAttributeViewsHolder.supportedFileAttributeViews;
+    }
+
+    @Override
+    void copyNonPosixAttributes(int ofd, int nfd) {
+        SolarisUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd);
+        // TDB: copy ACL from source to target
+    }
+
+    @Override
+    boolean supportsSecureDirectoryStreams() {
+        return true;
+    }
+
+    /**
+     * Returns object to iterate over entries in /etc/mnttab
+     */
+    @Override
+    Iterable<UnixMountEntry> getMountEntries() {
+        ArrayList<UnixMountEntry> entries = new ArrayList<UnixMountEntry>();
+        try {
+            UnixPath mnttab = new UnixPath(this, "/etc/mnttab");
+            long fp = fopen(mnttab, "r");
+            try {
+                for (;;) {
+                    UnixMountEntry entry = new UnixMountEntry();
+                    int res = getextmntent(fp, entry);
+                    if (res < 0)
+                        break;
+                    entries.add(entry);
+                }
+            } finally {
+                fclose(fp);
+            }
+        } catch (UnixException x) {
+            // nothing we can do
+        }
+        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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+/**
+ * Solaris implementation of FileSystemProvider
+ */
+
+public class SolarisFileSystemProvider extends UnixFileSystemProvider {
+    public SolarisFileSystemProvider() {
+        super();
+    }
+
+    @Override
+    SolarisFileSystem newFileSystem(String dir) {
+        return new SolarisFileSystem(this, dir);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Solaris specific system calls.
+ */
+
+class SolarisNativeDispatcher extends UnixNativeDispatcher {
+    private SolarisNativeDispatcher() { }
+
+    /**
+     * int facl(int filedes, int cmd, int nentries, void aclbufp)
+     */
+    static native int facl(int fd, int cmd, int nentries, long aclbufp)
+        throws UnixException;
+
+
+    // initialize
+    private static native void init();
+
+    static {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                System.loadLibrary("nio");
+                return null;
+        }});
+        init();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.io.IOException;
+import java.util.*;
+
+import static sun.nio.fs.UnixNativeDispatcher.*;
+import static sun.nio.fs.UnixConstants.*;
+import static sun.nio.fs.SolarisConstants.*;
+
+/**
+ * Solaris emulation of NamedAttributeView using extended attributes.
+ */
+
+class SolarisUserDefinedFileAttributeView
+    extends AbstractUserDefinedFileAttributeView
+{
+    private byte[] nameAsBytes(UnixPath file, String name) throws IOException {
+        byte[] bytes = name.getBytes();
+        //  "", "." and ".." not allowed
+        if (bytes.length == 0 || bytes[0] == '.') {
+            if (bytes.length <= 1 ||
+                (bytes.length == 2 && bytes[1] == '.'))
+            {
+                throw new FileSystemException(file.getPathForExecptionMessage(),
+                    null, "'" + name + "' is not a valid name");
+            }
+        }
+        return bytes;
+    }
+
+    private final UnixPath file;
+    private final boolean followLinks;
+
+    SolarisUserDefinedFileAttributeView(UnixPath file, boolean followLinks) {
+        this.file = file;
+        this.followLinks = followLinks;
+    }
+
+    @Override
+    public List<String> list() throws IOException  {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), true, false);
+
+        int fd = file.openForAttributeAccess(followLinks);
+        try {
+            try {
+                // open extended attribute directory
+                int dfd = openat(fd, ".".getBytes(), (O_RDONLY|O_XATTR), 0);
+                long dp;
+                try {
+                    dp = fdopendir(dfd);
+                } catch (UnixException x) {
+                    close(dfd);
+                    throw x;
+                }
+
+                // read list of extended attributes
+                final List<String> list = new ArrayList<String>();
+                try {
+                    byte[] name;
+                    while ((name = readdir(dp)) != null) {
+                        String s = new String(name);
+                        if (!s.equals(".") && !s.equals(".."))
+                            list.add(s);
+                    }
+                } finally {
+                    closedir(dp);
+                }
+                return Collections.unmodifiableList(list);
+            } catch (UnixException x) {
+                throw new FileSystemException(file.getPathForExecptionMessage(),
+                    null, "Unable to get list of extended attributes: " +
+                    x.getMessage());
+            }
+        } finally {
+            close(fd);
+        }
+    }
+
+    @Override
+    public int size(String name) throws IOException  {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), true, false);
+
+        int fd = file.openForAttributeAccess(followLinks);
+        try {
+            try {
+                // open attribute file
+                int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0);
+                try {
+                    // read attribute's attributes
+                    UnixFileAttributes attrs = UnixFileAttributes.get(afd);
+                    long size = attrs.size();
+                    if (size > Integer.MAX_VALUE)
+                        throw new ArithmeticException("Extended attribute value too large");
+                    return (int)size;
+                } finally {
+                    close(afd);
+                }
+            } catch (UnixException x) {
+                throw new FileSystemException(file.getPathForExecptionMessage(),
+                    null, "Unable to get size of extended attribute '" + name +
+                    "': " + x.getMessage());
+            }
+        } finally {
+            close(fd);
+        }
+    }
+
+    @Override
+    public int read(String name, ByteBuffer dst) throws IOException {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), true, false);
+
+        int fd = file.openForAttributeAccess(followLinks);
+        try {
+            try {
+                // open attribute file
+                int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0);
+
+                // wrap with channel
+                FileChannel fc = UnixChannelFactory.newFileChannel(afd, true, false);
+
+                // read to EOF (nothing we can do if I/O error occurs)
+                try {
+                    if (fc.size() > dst.remaining())
+                        throw new IOException("Extended attribute file too large");
+                    int total = 0;
+                    while (dst.hasRemaining()) {
+                        int n = fc.read(dst);
+                        if (n < 0)
+                            break;
+                        total += n;
+                    }
+                    return total;
+                } finally {
+                    fc.close();
+                }
+            } catch (UnixException x) {
+                throw new FileSystemException(file.getPathForExecptionMessage(),
+                    null, "Unable to read extended attribute '" + name +
+                    "': " + x.getMessage());
+            }
+        } finally {
+            close(fd);
+        }
+    }
+
+    @Override
+    public int write(String name, ByteBuffer src) throws IOException {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), false, true);
+
+        int fd = file.openForAttributeAccess(followLinks);
+        try {
+            try {
+                // open/create attribute file
+                int afd = openat(fd, nameAsBytes(file,name),
+                                 (O_CREAT|O_WRONLY|O_TRUNC|O_XATTR),
+                                 UnixFileModeAttribute.ALL_PERMISSIONS);
+
+                // wrap with channel
+                FileChannel fc = UnixChannelFactory.newFileChannel(afd, false, true);
+
+                // write value (nothing we can do if I/O error occurs)
+                try {
+                    int rem = src.remaining();
+                    while (src.hasRemaining()) {
+                        fc.write(src);
+                    }
+                    return rem;
+                } finally {
+                    fc.close();
+                }
+            } catch (UnixException x) {
+                throw new FileSystemException(file.getPathForExecptionMessage(),
+                    null, "Unable to write extended attribute '" + name +
+                    "': " + x.getMessage());
+            }
+        } finally {
+            close(fd);
+        }
+    }
+
+    @Override
+    public void delete(String name) throws IOException {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), false, true);
+
+        int fd = file.openForAttributeAccess(followLinks);
+        try {
+            int dfd = openat(fd, ".".getBytes(), (O_RDONLY|O_XATTR), 0);
+            try {
+                unlinkat(dfd, nameAsBytes(file,name), 0);
+            } finally {
+                close(dfd);
+            }
+        } catch (UnixException x) {
+            throw new FileSystemException(file.getPathForExecptionMessage(),
+                null, "Unable to delete extended attribute '" + name +
+                "': " + x.getMessage());
+        } finally {
+            close(fd);
+        }
+    }
+
+    /**
+     * Used by copyTo/moveTo to copy extended attributes from source to target.
+     *
+     * @param   ofd
+     *          file descriptor for source file
+     * @param   nfd
+     *          file descriptor for target file
+     */
+    static void copyExtendedAttributes(int ofd, int nfd) {
+        try {
+            // open extended attribute directory
+            int dfd = openat(ofd, ".".getBytes(), (O_RDONLY|O_XATTR), 0);
+            long dp = 0L;
+            try {
+                dp = fdopendir(dfd);
+            } catch (UnixException x) {
+                close(dfd);
+                throw x;
+            }
+
+            // copy each extended attribute
+            try {
+                byte[] name;
+                while ((name = readdir(dp)) != null) {
+                    // ignore "." and ".."
+                    if (name[0] == '.') {
+                        if (name.length == 1)
+                            continue;
+                        if (name.length == 2 && name[1] == '.')
+                            continue;
+                    }
+                    copyExtendedAttribute(ofd, name, nfd);
+                }
+            } finally {
+                closedir(dp);
+            }
+        } catch (UnixException ignore) {
+        }
+    }
+
+    private static void copyExtendedAttribute(int ofd, byte[] name, int nfd)
+        throws UnixException
+    {
+        // open source attribute file
+        int src = openat(ofd, name, (O_RDONLY|O_XATTR), 0);
+        try {
+            // create target attribute file
+            int dst = openat(nfd, name, (O_CREAT|O_WRONLY|O_TRUNC|O_XATTR),
+                UnixFileModeAttribute.ALL_PERMISSIONS);
+            try {
+                UnixCopyFile.transfer(dst, src, 0L);
+            } finally {
+                close(dst);
+            }
+        } finally {
+            close(src);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisWatchService.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,770 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.*;
+import java.io.IOException;
+import sun.misc.Unsafe;
+
+import static sun.nio.fs.UnixConstants.*;
+
+/**
+ * Solaris implementation of WatchService based on file events notification
+ * facility.
+ */
+
+class SolarisWatchService
+    extends AbstractWatchService
+{
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private static int addressSize = unsafe.addressSize();
+
+    private static int dependsArch(int value32, int value64) {
+        return (addressSize == 4) ? value32 : value64;
+    }
+
+    /*
+     * typedef struct port_event {
+     *     int             portev_events;
+     *     ushort_t        portev_source;
+     *     ushort_t        portev_pad;
+     *     uintptr_t       portev_object;
+     *     void            *portev_user;
+     * } port_event_t;
+     */
+    private static final int SIZEOF_PORT_EVENT  = dependsArch(16, 24);
+    private static final int OFFSETOF_EVENTS    = 0;
+    private static final int OFFSETOF_SOURCE    = 4;
+    private static final int OFFSETOF_OBJECT    = 8;
+
+    /*
+     * typedef struct file_obj {
+     *     timestruc_t     fo_atime;
+     *     timestruc_t     fo_mtime;
+     *     timestruc_t     fo_ctime;
+     *     uintptr_t       fo_pad[3];
+     *     char            *fo_name;
+     * } file_obj_t;
+     */
+    private static final int SIZEOF_FILEOBJ    = dependsArch(40, 80);
+    private static final int OFFSET_FO_NAME    = dependsArch(36, 72);
+
+    // port sources
+    private static final short PORT_SOURCE_USER     = 3;
+    private static final short PORT_SOURCE_FILE     = 7;
+
+    // user-watchable events
+    private static final int FILE_MODIFIED      = 0x00000002;
+    private static final int FILE_ATTRIB        = 0x00000004;
+    private static final int FILE_NOFOLLOW      = 0x10000000;
+
+    // exception events
+    private static final int FILE_DELETE        = 0x00000010;
+    private static final int FILE_RENAME_TO     = 0x00000020;
+    private static final int FILE_RENAME_FROM   = 0x00000040;
+    private static final int UNMOUNTED          = 0x20000000;
+    private static final int MOUNTEDOVER        = 0x40000000;
+
+    // background thread to read change events
+    private final Poller poller;
+
+    SolarisWatchService(UnixFileSystem fs) throws IOException {
+        int port = -1;
+        try {
+            port = portCreate();
+        } catch (UnixException x) {
+            throw new IOException(x.errorString());
+        }
+
+        this.poller = new Poller(fs, this, port);
+        this.poller.start();
+    }
+
+    @Override
+    WatchKey register(Path dir,
+                      WatchEvent.Kind<?>[] events,
+                      WatchEvent.Modifier... modifiers)
+         throws IOException
+    {
+        // delegate to poller
+        return poller.register(dir, events, modifiers);
+    }
+
+    @Override
+    void implClose() throws IOException {
+        // delegate to poller
+        poller.close();
+    }
+
+    /**
+     * WatchKey implementation
+     */
+    private class SolarisWatchKey extends AbstractWatchKey
+        implements DirectoryNode
+    {
+        private final UnixPath dir;
+        private final UnixFileKey fileKey;
+
+        // pointer to native file_obj object
+        private final long object;
+
+        // events (may be changed). set to null when watch key is invalid
+        private volatile Set<? extends WatchEvent.Kind<?>> events;
+
+        // map of entries in directory; created lazily; accessed only by
+        // poller thread.
+        private Map<Path,EntryNode> children;
+
+        SolarisWatchKey(SolarisWatchService watcher,
+                        UnixPath dir,
+                        UnixFileKey fileKey,
+                        long object,
+                        Set<? extends WatchEvent.Kind<?>> events)
+        {
+            super(watcher);
+            this.dir = dir;
+            this.fileKey = fileKey;
+            this.object = object;
+            this.events = events;
+        }
+
+        UnixPath getFileRef() {
+            return dir;
+        }
+
+        UnixFileKey getFileKey() {
+            return fileKey;
+        }
+
+        @Override
+        public long object() {
+            return object;
+        }
+
+        void invalidate() {
+            events = null;
+        }
+
+        Set<? extends WatchEvent.Kind<?>> events() {
+            return events;
+        }
+
+        void setEvents(Set<? extends WatchEvent.Kind<?>> events) {
+            this.events = events;
+        }
+
+        @Override
+        public boolean isValid() {
+            return events != null;
+        }
+
+        @Override
+        public void cancel() {
+            if (isValid()) {
+                // delegate to poller
+                poller.cancel(this);
+            }
+        }
+
+        @Override
+        public void addChild(Path name, EntryNode node) {
+            if (children == null)
+                children = new HashMap<Path,EntryNode>();
+            children.put(name, node);
+        }
+
+        @Override
+        public void removeChild(Path name) {
+            children.remove(name);
+        }
+
+        @Override
+        public EntryNode getChild(Path name) {
+            if (children != null)
+                return children.get(name);
+            return null;
+        }
+    }
+
+    /**
+     * Background thread to read from port
+     */
+    private class Poller extends AbstractPoller {
+
+        // maximum number of events to read per call to port_getn
+        private static final int MAX_EVENT_COUNT            = 128;
+
+        // events that map to ENTRY_DELETE
+        private static final int FILE_REMOVED =
+            (FILE_DELETE|FILE_RENAME_TO|FILE_RENAME_FROM);
+
+        // events that tell us not to re-associate the object
+        private static final int FILE_EXCEPTION =
+            (FILE_REMOVED|UNMOUNTED|MOUNTEDOVER);
+
+        // address of event buffers (used to receive events with port_getn)
+        private final long bufferAddress;
+
+        private final SolarisWatchService watcher;
+
+        // the I/O port
+        private final int port;
+
+        // maps file key (dev/inode) to WatchKey
+        private final Map<UnixFileKey,SolarisWatchKey> fileKey2WatchKey;
+
+        // maps file_obj object to Node
+        private final Map<Long,Node> object2Node;
+
+        /**
+         * Create a new instance
+         */
+        Poller(UnixFileSystem fs, SolarisWatchService watcher, int port) {
+            this.watcher = watcher;
+            this.port = port;
+            this.bufferAddress =
+                unsafe.allocateMemory(SIZEOF_PORT_EVENT * MAX_EVENT_COUNT);
+            this.fileKey2WatchKey = new HashMap<UnixFileKey,SolarisWatchKey>();
+            this.object2Node = new HashMap<Long,Node>();
+        }
+
+        @Override
+        void wakeup() throws IOException {
+            // write to port to wakeup polling thread
+            try {
+                portSend(port, 0);
+            } catch (UnixException x) {
+                throw new IOException(x.errorString());
+            }
+        }
+
+        @Override
+        Object implRegister(Path obj,
+                            Set<? extends WatchEvent.Kind<?>> events,
+                            WatchEvent.Modifier... modifiers)
+        {
+            // no modifiers supported at this time
+            if (modifiers.length > 0) {
+                for (WatchEvent.Modifier modifier: modifiers) {
+                    if (modifier == null)
+                        return new NullPointerException();
+                    if (modifier instanceof com.sun.nio.file.SensitivityWatchEventModifier)
+                        continue; // ignore
+                    return new UnsupportedOperationException("Modifier not supported");
+                }
+            }
+
+            UnixPath dir = (UnixPath)obj;
+
+            // check file is directory
+            UnixFileAttributes attrs = null;
+            try {
+                attrs = UnixFileAttributes.get(dir, true);
+            } catch (UnixException x) {
+                return x.asIOException(dir);
+            }
+            if (!attrs.isDirectory()) {
+                return new NotDirectoryException(dir.getPathForExecptionMessage());
+            }
+
+            // return existing watch key after updating events if already
+            // registered
+            UnixFileKey fileKey = attrs.fileKey();
+            SolarisWatchKey watchKey = fileKey2WatchKey.get(fileKey);
+            if (watchKey != null) {
+                updateEvents(watchKey, events);
+                return watchKey;
+            }
+
+            // register directory
+            long object = 0L;
+            try {
+                object = registerImpl(dir, (FILE_MODIFIED | FILE_ATTRIB));
+            } catch (UnixException x) {
+                return x.asIOException(dir);
+            }
+
+            // create watch key and insert it into maps
+            watchKey = new SolarisWatchKey(watcher, dir, fileKey, object, events);
+            object2Node.put(object, watchKey);
+            fileKey2WatchKey.put(fileKey, watchKey);
+
+            // register all entries in directory
+            registerChildren(dir, watchKey, false);
+
+            return watchKey;
+        }
+
+        // cancel single key
+        @Override
+        void implCancelKey(WatchKey obj) {
+           SolarisWatchKey key = (SolarisWatchKey)obj;
+           if (key.isValid()) {
+               fileKey2WatchKey.remove(key.getFileKey());
+
+               // release resources for entries in directory
+               if (key.children != null) {
+                   for (Map.Entry<Path,EntryNode> entry: key.children.entrySet()) {
+                       EntryNode node = entry.getValue();
+                       long object = node.object();
+                       object2Node.remove(object);
+                       releaseObject(object, true);
+                   }
+               }
+
+               // release resources for directory
+               long object = key.object();
+               object2Node.remove(object);
+               releaseObject(object, true);
+
+               // and finally invalidate the key
+               key.invalidate();
+           }
+        }
+
+        // close watch service
+        @Override
+        void implCloseAll() {
+            // release all native resources
+            for (Long object: object2Node.keySet()) {
+                releaseObject(object, true);
+            }
+
+            // invalidate all keys
+            for (Map.Entry<UnixFileKey,SolarisWatchKey> entry: fileKey2WatchKey.entrySet()) {
+                entry.getValue().invalidate();
+            }
+
+            // clean-up
+            object2Node.clear();
+            fileKey2WatchKey.clear();
+
+            // free global resources
+            unsafe.freeMemory(bufferAddress);
+            UnixNativeDispatcher.close(port);
+        }
+
+        /**
+         * Poller main loop. Blocks on port_getn waiting for events and then
+         * processes them.
+         */
+        @Override
+        public void run() {
+            try {
+                for (;;) {
+                    int n = portGetn(port, bufferAddress, MAX_EVENT_COUNT);
+                    assert n > 0;
+
+                    long address = bufferAddress;
+                    for (int i=0; i<n; i++) {
+                        boolean shutdown = processEvent(address);
+                        if (shutdown)
+                            return;
+                        address += SIZEOF_PORT_EVENT;
+                    }
+                }
+            } catch (UnixException x) {
+                x.printStackTrace();
+            }
+        }
+
+        /**
+         * Process a single port_event
+         *
+         * Returns true if poller thread is requested to shutdown.
+         */
+        boolean processEvent(long address) {
+            // pe->portev_source
+            short source = unsafe.getShort(address + OFFSETOF_SOURCE);
+            // pe->portev_object
+            long object = unsafe.getAddress(address + OFFSETOF_OBJECT);
+            // pe->portev_events
+            int events = unsafe.getInt(address + OFFSETOF_EVENTS);
+
+            // user event is trigger to process pending requests
+            if (source != PORT_SOURCE_FILE) {
+                if (source == PORT_SOURCE_USER) {
+                    // process any pending requests
+                    boolean shutdown = processRequests();
+                    if (shutdown)
+                        return true;
+                }
+                return false;
+            }
+
+            // lookup object to get Node
+            Node node = object2Node.get(object);
+            if (node == null) {
+                // should not happen
+                return false;
+            }
+
+            // As a workaround for 6642290 and 6636438/6636412 we don't use
+            // FILE_EXCEPTION events to tell use not to register the file.
+            // boolean reregister = (events & FILE_EXCEPTION) == 0;
+            boolean reregister = true;
+
+            // If node is EntryNode then event relates to entry in directory
+            // If node is a SolarisWatchKey (DirectoryNode) then event relates
+            // to a watched directory.
+            boolean isDirectory = (node instanceof SolarisWatchKey);
+            if (isDirectory) {
+                processDirectoryEvents((SolarisWatchKey)node, events);
+            } else {
+                boolean ignore = processEntryEvents((EntryNode)node, events);
+                if (ignore)
+                    reregister = false;
+            }
+
+            // need to re-associate to get further events
+            if (reregister) {
+                try {
+                    events = FILE_MODIFIED | FILE_ATTRIB;
+                    if (!isDirectory) events |= FILE_NOFOLLOW;
+                    portAssociate(port,
+                                  PORT_SOURCE_FILE,
+                                  object,
+                                  events);
+                } catch (UnixException x) {
+                    // unable to re-register
+                    reregister = false;
+                }
+            }
+
+            // object is not re-registered so release resources. If
+            // object is a watched directory then signal key
+            if (!reregister) {
+                // release resources
+                object2Node.remove(object);
+                releaseObject(object, false);
+
+                // if watch key then signal it
+                if (isDirectory) {
+                    SolarisWatchKey key = (SolarisWatchKey)node;
+                    fileKey2WatchKey.remove( key.getFileKey() );
+                    key.invalidate();
+                    key.signal();
+                } else {
+                    // if entry then remove it from parent
+                    EntryNode entry = (EntryNode)node;
+                    SolarisWatchKey key = (SolarisWatchKey)entry.parent();
+                    key.removeChild(entry.name());
+                }
+            }
+
+            return false;
+        }
+
+        /**
+         * Process directory events. If directory is modified then re-scan
+         * directory to register any new entries
+         */
+        void processDirectoryEvents(SolarisWatchKey key, int mask) {
+            if ((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) {
+                registerChildren(key.getFileRef(), key,
+                    key.events().contains(StandardWatchEventKind.ENTRY_CREATE));
+            }
+        }
+
+        /**
+         * Process events for entries in registered directories. Returns {@code
+         * true} if events are ignored because the watch key has been cancelled.
+         */
+        boolean processEntryEvents(EntryNode node, int mask) {
+            SolarisWatchKey key = (SolarisWatchKey)node.parent();
+            Set<? extends WatchEvent.Kind<?>> events = key.events();
+            if (events == null) {
+                // key has been cancelled so ignore event
+                return true;
+            }
+
+            // entry modified
+            if (((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) &&
+                events.contains(StandardWatchEventKind.ENTRY_MODIFY))
+            {
+                key.signalEvent(StandardWatchEventKind.ENTRY_MODIFY, node.name());
+            }
+
+            // entry removed
+            if (((mask & (FILE_REMOVED)) != 0) &&
+                events.contains(StandardWatchEventKind.ENTRY_DELETE))
+            {
+                // Due to 6636438/6636412 we may get a remove event for cases
+                // where a rmdir/unlink/rename is attempted but fails. Until
+                // this issue is resolved we re-lstat the file to check if it
+                // exists. If it exists then we ignore the event. To keep the
+                // workaround simple we don't check the st_ino so it isn't
+                // effective when the file is replaced.
+                boolean removed = true;
+                try {
+                    UnixFileAttributes
+                        .get(key.getFileRef().resolve(node.name()), false);
+                    removed = false;
+                } catch (UnixException x) { }
+
+                if (removed)
+                    key.signalEvent(StandardWatchEventKind.ENTRY_DELETE, node.name());
+            }
+            return false;
+        }
+
+        /**
+         * Registers all entries in the given directory
+         *
+         * The {@code sendEvents} parameter indicates if ENTRY_CREATE events
+         * should be queued when new entries are found. When initially
+         * registering a directory then will always be false. When re-scanning
+         * a directory then it depends on if the event is enabled or not.
+         */
+        void registerChildren(UnixPath dir,
+                              SolarisWatchKey parent,
+                              boolean sendEvents)
+        {
+            // if the ENTRY_MODIFY event is not enabled then we don't need
+            // modification events for entries in the directory
+            int events = FILE_NOFOLLOW;
+            if (parent.events().contains(StandardWatchEventKind.ENTRY_MODIFY))
+                events |= (FILE_MODIFIED | FILE_ATTRIB);
+
+            DirectoryStream<Path> stream = null;
+            try {
+                stream = dir.newDirectoryStream();
+            } catch (IOException x) {
+                // nothing we can do
+                return;
+            }
+            try {
+                for (Path entry: stream) {
+                    Path name = entry.getName();
+
+                    // skip entry if already registered
+                    if (parent.getChild(name) != null)
+                        continue;
+
+                    // send ENTRY_CREATE if enabled
+                    if (sendEvents) {
+                        parent.signalEvent(StandardWatchEventKind.ENTRY_CREATE, name);
+                    }
+
+                    // register it
+                    long object = 0L;
+                    try {
+                        object = registerImpl((UnixPath)entry, events);
+                    } catch (UnixException x) {
+                        // can't register so ignore for now.
+                        continue;
+                    }
+
+                    // create node
+                    EntryNode node = new EntryNode(object, entry.getName(), parent);
+                    // tell the parent about it
+                    parent.addChild(entry.getName(), node);
+                    object2Node.put(object, node);
+                }
+            } catch (ConcurrentModificationException x) {
+                // error during iteration which we ignore for now
+            } finally {
+                try {
+                    stream.close();
+                } catch (IOException x) { }
+            }
+        }
+
+        /**
+         * Update watch key's events. Where the ENTRY_MODIFY changes then we
+         * need to update the events of registered children.
+         */
+        void updateEvents(SolarisWatchKey key, Set<? extends WatchEvent.Kind<?>> events) {
+            // update events, rembering if ENTRY_MODIFY was previously
+            // enabled or disabled.
+            boolean wasModifyEnabled = key.events()
+                .contains(StandardWatchEventKind.ENTRY_MODIFY);
+            key.setEvents(events);
+
+            // check if ENTRY_MODIFY has changed
+            boolean isModifyEnabled = events
+                .contains(StandardWatchEventKind.ENTRY_MODIFY);
+            if (wasModifyEnabled == isModifyEnabled) {
+                return;
+            }
+
+            // if changed then update events of children
+            if (key.children != null) {
+                int ev = FILE_NOFOLLOW;
+                if (isModifyEnabled)
+                    ev |= (FILE_MODIFIED | FILE_ATTRIB);
+
+                for (Map.Entry<Path,EntryNode> entry: key.children.entrySet()) {
+                    long object = entry.getValue().object();
+                    try {
+                        portAssociate(port,
+                                      PORT_SOURCE_FILE,
+                                      object,
+                                      ev);
+                    } catch (UnixException x) {
+                        // nothing we can do.
+                    }
+                }
+            }
+        }
+
+        /**
+         * Calls port_associate to register the given path.
+         * Returns pointer to fileobj structure that is allocated for
+         * the registration.
+         */
+        long registerImpl(UnixPath dir, int events)
+            throws UnixException
+        {
+            // allocate memory for the path (file_obj->fo_name field)
+            byte[] path = dir.getByteArrayForSysCalls();
+            int len = path.length;
+            long name = unsafe.allocateMemory(len+1);
+            unsafe.copyMemory(path, Unsafe.ARRAY_BYTE_BASE_OFFSET, null,
+                name, (long)len);
+            unsafe.putByte(name + len, (byte)0);
+
+            // allocate memory for filedatanode structure - this is the object
+            // to port_associate
+            long object = unsafe.allocateMemory(SIZEOF_FILEOBJ);
+            unsafe.setMemory(null, object, SIZEOF_FILEOBJ, (byte)0);
+            unsafe.putAddress(object + OFFSET_FO_NAME, name);
+
+            // associate the object with the port
+            try {
+                portAssociate(port,
+                              PORT_SOURCE_FILE,
+                              object,
+                              events);
+            } catch (UnixException x) {
+                // debugging
+                if (x.errno() == EAGAIN) {
+                    System.err.println("The maximum number of objects associated "+
+                        "with the port has been reached");
+                }
+
+                unsafe.freeMemory(name);
+                unsafe.freeMemory(object);
+                throw x;
+            }
+            return object;
+        }
+
+        /**
+         * Frees all resources for an file_obj object; optionally remove
+         * association from port
+         */
+        void releaseObject(long object, boolean dissociate) {
+            // remove association
+            if (dissociate) {
+                try {
+                    portDissociate(port, PORT_SOURCE_FILE, object);
+                } catch (UnixException x) {
+                    // ignore
+                }
+            }
+
+            // free native memory
+            long name = unsafe.getAddress(object + OFFSET_FO_NAME);
+            unsafe.freeMemory(name);
+            unsafe.freeMemory(object);
+        }
+    }
+
+    /**
+     * A node with native (file_obj) resources
+     */
+    private static interface Node {
+        long object();
+    }
+
+    /**
+     * A directory node with a map of the entries in the directory
+     */
+    private static interface DirectoryNode extends Node {
+        void addChild(Path name, EntryNode node);
+        void removeChild(Path name);
+        EntryNode getChild(Path name);
+    }
+
+    /**
+     * An implementation of a node that is an entry in a directory.
+     */
+    private static class EntryNode implements Node {
+        private final long object;
+        private final Path name;
+        private final DirectoryNode parent;
+
+        EntryNode(long object, Path name, DirectoryNode parent) {
+            this.object = object;
+            this.name = name;
+            this.parent = parent;
+        }
+
+        @Override
+        public long object() {
+            return object;
+        }
+
+        Path name() {
+            return name;
+        }
+
+        DirectoryNode parent() {
+            return parent;
+        }
+    }
+
+    // -- native methods --
+
+    private static native void init();
+
+    private static native int portCreate() throws UnixException;
+
+    private static native void portAssociate(int port, int source, long object, int events)
+        throws UnixException;
+
+    private static native void portDissociate(int port, int source, long object)
+        throws UnixException;
+
+    private static native void portSend(int port, int events)
+        throws UnixException;
+
+    private static native int portGetn(int port, long address, int max)
+        throws UnixException;
+
+    static {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                System.loadLibrary("nio");
+                return null;
+        }});
+        init();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixChannelFactory.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.channels.*;
+import java.io.FileDescriptor;
+import java.util.Set;
+
+import sun.nio.ch.FileChannelImpl;
+import sun.nio.ch.ThreadPool;
+import sun.nio.ch.SimpleAsynchronousFileChannelImpl;
+import sun.misc.SharedSecrets;
+import sun.misc.JavaIOFileDescriptorAccess;
+
+import com.sun.nio.file.ExtendedOpenOption;
+
+import static sun.nio.fs.UnixNativeDispatcher.*;
+import static sun.nio.fs.UnixConstants.*;
+
+/**
+ * Factory for FileChannels and AsynchronousFileChannels
+ */
+
+class UnixChannelFactory {
+    private static final JavaIOFileDescriptorAccess fdAccess =
+        SharedSecrets.getJavaIOFileDescriptorAccess();
+
+    private UnixChannelFactory() {
+    }
+
+    /**
+     * Represents the flags from a user-supplied set of open options.
+     */
+    private static class Flags {
+        boolean read;
+        boolean write;
+        boolean append;
+        boolean truncateExisting;
+        boolean noFollowLinks;
+        boolean create;
+        boolean createNew;
+        boolean deleteOnClose;
+        boolean sync;
+        boolean dsync;
+
+        static Flags toFlags(Set<? extends OpenOption> options) {
+            Flags flags = new Flags();
+            for (OpenOption option: options) {
+                if (option instanceof StandardOpenOption) {
+                    switch ((StandardOpenOption)option) {
+                        case READ : flags.read = true; break;
+                        case WRITE : flags.write = true; break;
+                        case APPEND : flags.append = true; break;
+                        case TRUNCATE_EXISTING : flags.truncateExisting = true; break;
+                        case CREATE : flags.create = true; break;
+                        case CREATE_NEW : flags.createNew = true; break;
+                        case DELETE_ON_CLOSE : flags.deleteOnClose = true; break;
+                        case SPARSE : /* ignore */ break;
+                        case SYNC : flags.sync = true; break;
+                        case DSYNC : flags.dsync = true; break;
+                        default: throw new UnsupportedOperationException();
+                    }
+                    continue;
+                }
+                if (option == LinkOption.NOFOLLOW_LINKS) {
+                    flags.noFollowLinks = true;
+                    continue;
+                }
+                if (option == null)
+                    throw new NullPointerException();
+               throw new UnsupportedOperationException();
+            }
+            return flags;
+        }
+    }
+
+
+    /**
+     * Constructs a file channel from an existing (open) file descriptor
+     */
+    static FileChannel newFileChannel(int fd, boolean reading, boolean writing) {
+        FileDescriptor fdObj = new FileDescriptor();
+        fdAccess.set(fdObj, fd);
+        return FileChannelImpl.open(fdObj, reading, writing, null);
+    }
+
+    /**
+     * Constructs a file channel by opening a file using a dfd/path pair
+     */
+    static FileChannel newFileChannel(int dfd,
+                                      UnixPath path,
+                                      String pathForPermissionCheck,
+                                      Set<? extends OpenOption> options,
+                                      int mode)
+        throws UnixException
+    {
+        Flags flags = Flags.toFlags(options);
+
+        // default is reading; append => writing
+        if (!flags.read && !flags.write) {
+            if (flags.append) {
+                flags.write = true;
+            } else {
+                flags.read = true;
+            }
+        }
+
+        // validation
+        if (flags.read && flags.append)
+            throw new IllegalArgumentException("READ + APPEND not allowed");
+        if (flags.append && flags.truncateExisting)
+            throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
+
+        FileDescriptor fdObj = open(dfd, path, pathForPermissionCheck, flags, mode);
+        return FileChannelImpl.open(fdObj, flags.read, flags.write, null);
+    }
+
+    /**
+     * Constructs a file channel by opening the given file.
+     */
+    static FileChannel newFileChannel(UnixPath path,
+                                      Set<? extends OpenOption> options,
+                                      int mode)
+        throws UnixException
+    {
+        return newFileChannel(-1, path, null, options, mode);
+    }
+
+    /**
+     * Constructs an asynchronous file channel by opening the given file.
+     */
+    static AsynchronousFileChannel newAsynchronousFileChannel(UnixPath path,
+                                                              Set<? extends OpenOption> options,
+                                                              int mode,
+                                                              ThreadPool pool)
+        throws UnixException
+    {
+        Flags flags = Flags.toFlags(options);
+
+        // default is reading
+        if (!flags.read && !flags.write) {
+            flags.read = true;
+        }
+
+        // validation
+        if (flags.append)
+            throw new UnsupportedOperationException("APPEND not allowed");
+
+        // for now use simple implementation
+        FileDescriptor fdObj = open(-1, path, null, flags, mode);
+        return SimpleAsynchronousFileChannelImpl.open(fdObj, flags.read, flags.write, pool);
+    }
+
+    /**
+     * Opens file based on parameters and options, returning a FileDescriptor
+     * encapsulating the handle to the open file.
+     */
+    static FileDescriptor open(int dfd,
+                               UnixPath path,
+                               String pathForPermissionCheck,
+                               Flags flags,
+                               int mode)
+        throws UnixException
+    {
+        // map to oflags
+        int oflags;
+        if (flags.read && flags.write) {
+            oflags = O_RDWR;
+        } else {
+            oflags = (flags.write) ? O_WRONLY : O_RDONLY;
+        }
+        if (flags.write) {
+            if (flags.truncateExisting)
+                oflags |= O_TRUNC;
+            if (flags.append)
+                oflags |= O_APPEND;
+
+            // create flags
+            if (flags.createNew) {
+                byte[] pathForSysCall = path.asByteArray();
+
+                // throw exception if file name is "." to avoid confusing error
+                if ((pathForSysCall[pathForSysCall.length-1] == '.') &&
+                    (pathForSysCall.length == 1 ||
+                    (pathForSysCall[pathForSysCall.length-2] == '/')))
+                {
+                    throw new UnixException(EEXIST);
+                }
+                oflags |= (O_CREAT | O_EXCL);
+            } else {
+                if (flags.create)
+                    oflags |= O_CREAT;
+            }
+        }
+
+        // follow links by default
+        boolean followLinks = true;
+        if (!flags.createNew && (flags.noFollowLinks || flags.deleteOnClose)) {
+            followLinks = false;
+            oflags |= O_NOFOLLOW;
+        }
+
+        if (flags.dsync)
+            oflags |= O_DSYNC;
+        if (flags.sync)
+            oflags |= O_SYNC;
+
+        // permission check before we open the file
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            if (pathForPermissionCheck == null)
+                pathForPermissionCheck = path.getPathForPermissionCheck();
+            if (flags.read)
+                sm.checkRead(pathForPermissionCheck);
+            if (flags.write)
+                sm.checkWrite(pathForPermissionCheck);
+            if (flags.deleteOnClose)
+                sm.checkDelete(pathForPermissionCheck);
+        }
+
+        int fd;
+        try {
+            if (dfd >= 0) {
+                fd = openat(dfd, path.asByteArray(), oflags, mode);
+            } else {
+                fd = UnixNativeDispatcher.open(path, oflags, mode);
+            }
+        } catch (UnixException x) {
+            // Linux error can be EISDIR or EEXIST when file exists
+            if (flags.createNew && (x.errno() == EISDIR)) {
+                x.setError(EEXIST);
+            }
+
+            // handle ELOOP to avoid confusing message
+            if (!followLinks && (x.errno() == ELOOP)) {
+                x = new UnixException(x.getMessage() + " (NOFOLLOW_LINKS specified)");
+            }
+
+            throw x;
+        }
+
+        // unlink file immediately if delete on close. The spec is clear that
+        // an implementation cannot guarantee to unlink the correct file when
+        // replaced by an attacker after it is opened.
+        if (flags.deleteOnClose) {
+            try {
+                if (dfd >= 0) {
+                    unlinkat(dfd, path.asByteArray(), 0);
+                } else {
+                    unlink(path);
+                }
+            } catch (UnixException ignore) {
+                // best-effort
+            }
+        }
+
+        // create java.io.FileDescriptor
+        FileDescriptor fdObj = new FileDescriptor();
+        fdAccess.set(fdObj, fd);
+        return fdObj;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixCopyFile.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,608 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.concurrent.ExecutionException;
+import com.sun.nio.file.ExtendedCopyOption;
+
+import static sun.nio.fs.UnixNativeDispatcher.*;
+import static sun.nio.fs.UnixConstants.*;
+
+
+/**
+ * Unix implementation of Path#copyTo and Path#moveTo methods.
+ */
+
+class UnixCopyFile {
+    private UnixCopyFile() {  }
+
+    // The flags that control how a file is copied or moved
+    private static class Flags {
+        boolean replaceExisting;
+        boolean atomicMove;
+        boolean followLinks;
+        boolean interruptible;
+
+        // the attributes to copy
+        boolean copyBasicAttributes;
+        boolean copyPosixAttributes;
+        boolean copyNonPosixAttributes;
+
+        // flags that indicate if we should fail if attributes cannot be copied
+        boolean failIfUnableToCopyBasic;
+        boolean failIfUnableToCopyPosix;
+        boolean failIfUnableToCopyNonPosix;
+
+        static Flags fromCopyOptions(CopyOption... options) {
+            Flags flags = new Flags();
+            flags.followLinks = true;
+            for (CopyOption option: options) {
+                if (option == StandardCopyOption.REPLACE_EXISTING) {
+                    flags.replaceExisting = true;
+                    continue;
+                }
+                if (option == LinkOption.NOFOLLOW_LINKS) {
+                    flags.followLinks = false;
+                    continue;
+                }
+                if (option == StandardCopyOption.COPY_ATTRIBUTES) {
+                    // copy all attributes but only fail if basic attributes
+                    // cannot be copied
+                    flags.copyBasicAttributes = true;
+                    flags.copyPosixAttributes = true;
+                    flags.copyNonPosixAttributes = true;
+                    flags.failIfUnableToCopyBasic = true;
+                    continue;
+                }
+                if (option == ExtendedCopyOption.INTERRUPTIBLE) {
+                    flags.interruptible = true;
+                    continue;
+                }
+                if (option == null)
+                    throw new NullPointerException();
+                throw new UnsupportedOperationException("Unsupported copy option");
+            }
+            return flags;
+        }
+
+        static Flags fromMoveOptions(CopyOption... options) {
+            Flags flags = new Flags();
+            for (CopyOption option: options) {
+                if (option == StandardCopyOption.ATOMIC_MOVE) {
+                    flags.atomicMove = true;
+                    continue;
+                }
+                if (option == StandardCopyOption.REPLACE_EXISTING) {
+                    flags.replaceExisting = true;
+                    continue;
+                }
+                if (option == LinkOption.NOFOLLOW_LINKS) {
+                    // ignore
+                    continue;
+                }
+                if (option == null)
+                    throw new NullPointerException();
+                throw new UnsupportedOperationException("Unsupported copy option");
+            }
+
+            // a move requires that all attributes be copied but only fail if
+            // the basic attributes cannot be copied
+            flags.copyBasicAttributes = true;
+            flags.copyPosixAttributes = true;
+            flags.copyNonPosixAttributes = true;
+            flags.failIfUnableToCopyBasic = true;
+            return flags;
+        }
+    }
+
+    // copy directory from source to target
+    private static void copyDirectory(UnixPath source,
+                                      UnixFileAttributes attrs,
+                                      UnixPath target,
+                                      Flags flags)
+        throws IOException
+    {
+        try {
+            mkdir(target, attrs.mode());
+        } catch (UnixException x) {
+            x.rethrowAsIOException(target);
+        }
+
+        // no attributes to copy
+        if (!flags.copyBasicAttributes &&
+            !flags.copyPosixAttributes &&
+            !flags.copyNonPosixAttributes) return;
+
+        // open target directory if possible (this can fail when copying a
+        // directory for which we don't have read access).
+        int dfd = -1;
+        try {
+            dfd = open(target, O_RDONLY, 0);
+        } catch (UnixException x) {
+            // access to target directory required to copy named attributes
+            if (flags.copyNonPosixAttributes && flags.failIfUnableToCopyNonPosix) {
+                try { rmdir(target); } catch (UnixException ignore) { }
+                x.rethrowAsIOException(target);
+            }
+        }
+
+        boolean done = false;
+        try {
+            // copy owner/group/permissions
+            if (flags.copyPosixAttributes){
+                try {
+                    if (dfd >= 0) {
+                        fchown(dfd, attrs.uid(), attrs.gid());
+                        fchmod(dfd, attrs.mode());
+                    } else {
+                        chown(target, attrs.uid(), attrs.gid());
+                        chmod(target, attrs.mode());
+                    }
+                } catch (UnixException x) {
+                    // unable to set owner/group
+                    if (flags.failIfUnableToCopyPosix)
+                        x.rethrowAsIOException(target);
+                }
+            }
+            // copy other attributes
+            if (flags.copyNonPosixAttributes && (dfd >= 0)) {
+                int sfd = -1;
+                try {
+                    sfd = open(source, O_RDONLY, 0);
+                } catch (UnixException x) {
+                    if (flags.failIfUnableToCopyNonPosix)
+                        x.rethrowAsIOException(source);
+                }
+                if (sfd >= 0) {
+                    source.getFileSystem().copyNonPosixAttributes(sfd, dfd);
+                    close(sfd);
+                }
+            }
+            // copy time stamps last
+            if (flags.copyBasicAttributes) {
+                try {
+                    if (dfd >= 0) {
+                        futimes(dfd, attrs.lastAccessTime(),
+                            attrs.lastModifiedTime());
+                    } else {
+                        utimes(target, attrs.lastAccessTime(),
+                            attrs.lastModifiedTime());
+                    }
+                } catch (UnixException x) {
+                    // unable to set times
+                    if (flags.failIfUnableToCopyBasic)
+                        x.rethrowAsIOException(target);
+                }
+            }
+            done = true;
+        } finally {
+            if (dfd >= 0)
+                close(dfd);
+            if (!done) {
+                // rollback
+                try { rmdir(target); } catch (UnixException ignore) { }
+            }
+        }
+    }
+
+    // copy regular file from source to target
+    private static void copyFile(UnixPath source,
+                                 UnixFileAttributes attrs,
+                                 UnixPath  target,
+                                 Flags flags,
+                                 long addressToPollForCancel)
+        throws IOException
+    {
+        int fi = -1;
+        try {
+            fi = open(source, O_RDONLY, 0);
+        } catch (UnixException x) {
+            x.rethrowAsIOException(source);
+        }
+
+        try {
+            // open new file
+            int fo = -1;
+            try {
+                fo = open(target,
+                           (O_WRONLY |
+                            O_CREAT |
+                            O_TRUNC),
+                           attrs.mode());
+            } catch (UnixException x) {
+                x.rethrowAsIOException(target);
+            }
+
+            // set to true when file and attributes copied
+            boolean complete = false;
+            try {
+                // transfer bytes to target file
+                try {
+                    transfer(fo, fi, addressToPollForCancel);
+                } catch (UnixException x) {
+                    x.rethrowAsIOException(source, target);
+                }
+                // copy owner/permissions
+                if (flags.copyPosixAttributes) {
+                    try {
+                        fchown(fo, attrs.uid(), attrs.gid());
+                        fchmod(fo, attrs.mode());
+                    } catch (UnixException x) {
+                        if (flags.failIfUnableToCopyPosix)
+                            x.rethrowAsIOException(target);
+                    }
+                }
+                // copy non POSIX attributes (depends on file system)
+                if (flags.copyNonPosixAttributes) {
+                    source.getFileSystem().copyNonPosixAttributes(fi, fo);
+                }
+                // copy time attributes
+                if (flags.copyBasicAttributes) {
+                    try {
+                        futimes(fo, attrs.lastAccessTime(), attrs.lastModifiedTime());
+                    } catch (UnixException x) {
+                        if (flags.failIfUnableToCopyBasic)
+                            x.rethrowAsIOException(target);
+                    }
+                }
+                complete = true;
+            } finally {
+                close(fo);
+
+                // copy of file or attributes failed so rollback
+                if (!complete) {
+                    try {
+                        unlink(target);
+                    } catch (UnixException ignore) { }
+                }
+            }
+        } finally {
+            close(fi);
+        }
+    }
+
+    // copy symbolic link from source to target
+    private static void copyLink(UnixPath source,
+                                 UnixFileAttributes attrs,
+                                 UnixPath  target,
+                                 Flags flags)
+        throws IOException
+    {
+        byte[] linktarget = null;
+        try {
+            linktarget = readlink(source);
+        } catch (UnixException x) {
+            x.rethrowAsIOException(source);
+        }
+        try {
+            symlink(linktarget, target);
+
+            if (flags.copyPosixAttributes) {
+                try {
+                    lchown(target, attrs.uid(), attrs.gid());
+                } catch (UnixException x) {
+                    // ignore since link attributes not required to be copied
+                }
+            }
+        } catch (UnixException x) {
+            x.rethrowAsIOException(target);
+        }
+    }
+
+    // copy special file from source to target
+    private static void copySpecial(UnixPath source,
+                                    UnixFileAttributes attrs,
+                                    UnixPath  target,
+                                    Flags flags)
+        throws IOException
+    {
+        try {
+            mknod(target, attrs.mode(), attrs.rdev());
+        } catch (UnixException x) {
+            x.rethrowAsIOException(target);
+        }
+        boolean done = false;
+        try {
+            if (flags.copyPosixAttributes) {
+                try {
+                    chown(target, attrs.uid(), attrs.gid());
+                    chmod(target, attrs.mode());
+                } catch (UnixException x) {
+                    if (flags.failIfUnableToCopyPosix)
+                        x.rethrowAsIOException(target);
+                }
+            }
+            if (flags.copyBasicAttributes) {
+                try {
+                    utimes(target, attrs.lastAccessTime(), attrs.lastModifiedTime());
+                } catch (UnixException x) {
+                    if (flags.failIfUnableToCopyBasic)
+                        x.rethrowAsIOException(target);
+                }
+            }
+            done = true;
+        } finally {
+            if (!done) {
+                try { unlink(target); } catch (UnixException ignore) { }
+            }
+        }
+    }
+
+    // move file from source to target
+    static void move(UnixPath source, UnixPath target, CopyOption... options)
+        throws IOException
+    {
+        // permission check
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            source.checkWrite();
+            target.checkWrite();
+        }
+
+        // translate options into flags
+        Flags flags = Flags.fromMoveOptions(options);
+
+        // handle atomic rename case
+        if (flags.atomicMove) {
+            try {
+                rename(source, target);
+            } catch (UnixException x) {
+                if (x.errno() == EXDEV) {
+                    throw new AtomicMoveNotSupportedException(
+                        source.getPathForExecptionMessage(),
+                        target.getPathForExecptionMessage(),
+                        x.errorString());
+                }
+                x.rethrowAsIOException(source, target);
+            }
+            return;
+        }
+
+        // move using rename or copy+delete
+        UnixFileAttributes sourceAttrs = null;
+        UnixFileAttributes targetAttrs = null;
+
+        // get attributes of source file (don't follow links)
+        try {
+            sourceAttrs = UnixFileAttributes.get(source, false);
+        } catch (UnixException x) {
+            x.rethrowAsIOException(source);
+        }
+
+        // get attributes of target file (don't follow links)
+        try {
+            targetAttrs = UnixFileAttributes.get(target, false);
+        } catch (UnixException x) {
+            // ignore
+        }
+        boolean targetExists = (targetAttrs != null);
+
+        // if the target exists:
+        // 1. check if source and target are the same file
+        // 2. throw exception if REPLACE_EXISTING option is not set
+        // 3. delete target if REPLACE_EXISTING option set
+        if (targetExists) {
+            if (sourceAttrs.isSameFile(targetAttrs))
+                return;  // nothing to do as files are identical
+            if (!flags.replaceExisting) {
+                throw new FileAlreadyExistsException(
+                    target.getPathForExecptionMessage());
+            }
+
+            // attempt to delete target
+            try {
+                if (targetAttrs.isDirectory()) {
+                    rmdir(target);
+                } else {
+                    unlink(target);
+                }
+            } catch (UnixException x) {
+                // target is non-empty directory that can't be replaced.
+                if (targetAttrs.isDirectory() &&
+                   (x.errno() == EEXIST || x.errno() == ENOTEMPTY))
+                {
+                    throw new FileAlreadyExistsException(
+                        source.getPathForExecptionMessage(),
+                        target.getPathForExecptionMessage(),
+                        x.getMessage());
+                }
+                x.rethrowAsIOException(target);
+            }
+        }
+
+        // first try rename
+        try {
+            rename(source, target);
+            return;
+        } catch (UnixException x) {
+            if (x.errno() != EXDEV && x.errno() != EISDIR) {
+                x.rethrowAsIOException(source, target);
+            }
+        }
+
+        // copy source to target
+        if (sourceAttrs.isDirectory()) {
+            copyDirectory(source, sourceAttrs, target, flags);
+        } else {
+            if (sourceAttrs.isSymbolicLink()) {
+                copyLink(source, sourceAttrs, target, flags);
+            } else {
+                if (sourceAttrs.isDevice()) {
+                    copySpecial(source, sourceAttrs, target, flags);
+                } else {
+                    copyFile(source, sourceAttrs, target, flags, 0L);
+                }
+            }
+        }
+
+        // delete source
+        try {
+            if (sourceAttrs.isDirectory()) {
+                rmdir(source);
+            } else {
+                unlink(source);
+            }
+        } catch (UnixException x) {
+            // file was copied but unable to unlink the source file so attempt
+            // to remove the target and throw a reasonable exception
+            try {
+                if (sourceAttrs.isDirectory()) {
+                    rmdir(target);
+                } else {
+                    unlink(target);
+                }
+            } catch (UnixException ignore) { }
+
+            if (sourceAttrs.isDirectory() &&
+                (x.errno() == EEXIST || x.errno() == ENOTEMPTY))
+            {
+                throw new DirectoryNotEmptyException(
+                    source.getPathForExecptionMessage());
+            }
+            x.rethrowAsIOException(source);
+        }
+    }
+
+    // copy file from source to target
+    static void copy(final UnixPath source,
+                     final UnixPath target,
+                     CopyOption... options) throws IOException
+    {
+        // permission checks
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            source.checkRead();
+            target.checkWrite();
+        }
+
+        // translate options into flags
+        final Flags flags = Flags.fromCopyOptions(options);
+
+        UnixFileAttributes sourceAttrs = null;
+        UnixFileAttributes targetAttrs = null;
+
+        // get attributes of source file
+        try {
+            sourceAttrs = UnixFileAttributes.get(source, flags.followLinks);
+        } catch (UnixException x) {
+            x.rethrowAsIOException(source);
+        }
+
+        // if source file is symbolic link then we must check LinkPermission
+        if (sm != null && sourceAttrs.isSymbolicLink()) {
+            sm.checkPermission(new LinkPermission("symbolic"));
+        }
+
+        // get attributes of target file (don't follow links)
+        try {
+            targetAttrs = UnixFileAttributes.get(target, false);
+        } catch (UnixException x) {
+            // ignore
+        }
+        boolean targetExists = (targetAttrs != null);
+
+        // if the target exists:
+        // 1. check if source and target are the same file
+        // 2. throw exception if REPLACE_EXISTING option is not set
+        // 3. try to unlink the target
+        if (targetExists) {
+            if (sourceAttrs.isSameFile(targetAttrs))
+                return;  // nothing to do as files are identical
+            if (!flags.replaceExisting)
+                throw new FileAlreadyExistsException(
+                    target.getPathForExecptionMessage());
+            try {
+                if (targetAttrs.isDirectory()) {
+                    rmdir(target);
+                } else {
+                    unlink(target);
+                }
+            } catch (UnixException x) {
+                // target is non-empty directory that can't be replaced.
+                if (targetAttrs.isDirectory() &&
+                   (x.errno() == EEXIST || x.errno() == ENOTEMPTY))
+                {
+                    throw new FileAlreadyExistsException(
+                        source.getPathForExecptionMessage(),
+                        target.getPathForExecptionMessage(),
+                        x.getMessage());
+                }
+                x.rethrowAsIOException(target);
+            }
+        }
+
+        // do the copy
+        if (sourceAttrs.isDirectory()) {
+            copyDirectory(source, sourceAttrs, target, flags);
+            return;
+        }
+        if (sourceAttrs.isSymbolicLink()) {
+            copyLink(source, sourceAttrs, target, flags);
+            return;
+        }
+        if (!flags.interruptible) {
+            // non-interruptible file copy
+            copyFile(source, sourceAttrs, target, flags, 0L);
+            return;
+        }
+
+        // interruptible file copy
+        final UnixFileAttributes attrsToCopy = sourceAttrs;
+        Cancellable copyTask = new Cancellable() {
+            @Override public void implRun() throws IOException {
+                copyFile(source, attrsToCopy, target, flags,
+                    addressToPollForCancel());
+            }
+        };
+        try {
+            Cancellable.runInterruptibly(copyTask);
+        } catch (ExecutionException e) {
+            Throwable t = e.getCause();
+            if (t instanceof IOException)
+                throw (IOException)t;
+            throw new IOException(t);
+        }
+    }
+
+    // -- native methods --
+
+    static native void transfer(int dst, int src, long addressToPollForCancel)
+        throws UnixException;
+
+    static {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run() {
+                System.loadLibrary("nio");
+                return null;
+            }});
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.util.Iterator;
+import java.util.ConcurrentModificationException;
+import java.util.NoSuchElementException;
+import java.util.concurrent.locks.*;
+import java.io.IOException;
+import static sun.nio.fs.UnixNativeDispatcher.*;
+
+/**
+ * Unix implementation of java.nio.file.DirectoryStream
+ */
+
+class UnixDirectoryStream
+    implements DirectoryStream<Path>
+{
+    // path to directory when originally opened
+    private final UnixPath dir;
+
+    // directory pointer (returned by opendir)
+    private final long dp;
+
+    // filter (may be null)
+    private final DirectoryStream.Filter<? super Path> filter;
+
+    // used to coorindate closing of directory stream
+    private final ReentrantReadWriteLock streamLock =
+        new ReentrantReadWriteLock(true);
+
+    // indicates if directory stream is open (synchronize on closeLock)
+    private volatile boolean isClosed;
+
+    // directory iterator
+    private Iterator<Path> iterator;
+
+    /**
+     * Initializes a new instance
+     */
+    UnixDirectoryStream(UnixPath dir, long dp, DirectoryStream.Filter<? super Path> filter) {
+        this.dir = dir;
+        this.dp = dp;
+        this.filter = filter;
+    }
+
+    protected final UnixPath directory() {
+        return dir;
+    }
+
+    protected final Lock readLock() {
+        return streamLock.readLock();
+    }
+
+    protected final Lock writeLock() {
+        return streamLock.writeLock();
+    }
+
+    protected final boolean isOpen() {
+        return !isClosed;
+    }
+
+    protected final boolean closeImpl() throws IOException {
+        if (!isClosed) {
+            isClosed = true;
+            try {
+                closedir(dp);
+            } catch (UnixException x) {
+                throw new IOException(x.errorString());
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public void close()
+        throws IOException
+    {
+        writeLock().lock();
+        try {
+            closeImpl();
+        } finally {
+            writeLock().unlock();
+        }
+    }
+
+    protected final Iterator<Path> iterator(DirectoryStream<Path> ds) {
+        if (isClosed) {
+            throw new IllegalStateException("Directory stream is closed");
+        }
+        synchronized (this) {
+            if (iterator != null)
+                throw new IllegalStateException("Iterator already obtained");
+            iterator = new UnixDirectoryIterator(ds);
+            return iterator;
+        }
+    }
+
+    @Override
+    public Iterator<Path> iterator() {
+        return iterator(this);
+    }
+
+    /**
+     * Iterator implementation
+     */
+    private class UnixDirectoryIterator implements Iterator<Path> {
+        private final DirectoryStream<Path> stream;
+
+        // true when at EOF
+        private boolean atEof;
+
+        // next entry to return
+        private Path nextEntry;
+
+        // previous entry returned by next method (needed by remove method)
+        private Path prevEntry;
+
+        UnixDirectoryIterator(DirectoryStream<Path> stream) {
+            atEof = false;
+            this.stream = stream;
+        }
+
+        // Return true if file name is "." or ".."
+        private boolean isSelfOrParent(byte[] nameAsBytes) {
+            if (nameAsBytes[0] == '.') {
+                if ((nameAsBytes.length == 1) ||
+                    (nameAsBytes.length == 2 && nameAsBytes[1] == '.')) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        // Returns next entry (or null)
+        private Path readNextEntry() {
+            assert Thread.holdsLock(this);
+
+            for (;;) {
+                byte[] nameAsBytes = null;
+
+                // prevent close while reading
+                readLock().lock();
+                try {
+                    if (isClosed)
+                        throwAsConcurrentModificationException(new
+                            ClosedDirectoryStreamException());
+                    try {
+                        nameAsBytes = readdir(dp);
+                    } catch (UnixException x) {
+                        try {
+                            x.rethrowAsIOException(dir);
+                        } catch (IOException ioe) {
+                            throwAsConcurrentModificationException(ioe);
+                        }
+                    }
+                } finally {
+                    readLock().unlock();
+                }
+
+                // EOF
+                if (nameAsBytes == null) {
+                    return null;
+                }
+
+                // ignore "." and ".."
+                if (!isSelfOrParent(nameAsBytes)) {
+                    Path entry = dir.resolve(nameAsBytes);
+
+                    // return entry if no filter or filter accepts it
+                    if (filter.accept(entry)) {
+                        return entry;
+                    }
+                }
+            }
+        }
+
+        @Override
+        public synchronized boolean hasNext() {
+            if (nextEntry == null && !atEof) {
+                nextEntry = readNextEntry();
+
+                // at EOF?
+                if (nextEntry == null)
+                    atEof = true;
+            }
+            return nextEntry != null;
+        }
+
+        @Override
+        public synchronized Path next() {
+            if (nextEntry == null) {
+                if (!atEof) {
+                    nextEntry = readNextEntry();
+                }
+                if (nextEntry == null) {
+                    atEof = true;
+                    throw new NoSuchElementException();
+                }
+            }
+            prevEntry = nextEntry;
+            nextEntry = null;
+            return prevEntry;
+        }
+
+        @Override
+        public void remove() {
+            if (isClosed) {
+                throw new ClosedDirectoryStreamException();
+            }
+            Path entry;
+            synchronized (this) {
+                if (prevEntry == null)
+                    throw new IllegalStateException("No previous entry to remove");
+                entry = prevEntry;
+                prevEntry = null;
+            }
+
+            // use (race-free) unlinkat if available
+            try {
+                if (stream instanceof UnixSecureDirectoryStream) {
+                    ((UnixSecureDirectoryStream)stream)
+                        .implDelete(entry.getName(), false, 0);
+                } else {
+                    entry.delete(true);
+                }
+            } catch (IOException ioe) {
+                throwAsConcurrentModificationException(ioe);
+            } catch (SecurityException se) {
+                throwAsConcurrentModificationException(se);
+            }
+        }
+    }
+
+    private static void throwAsConcurrentModificationException(Throwable t) {
+        ConcurrentModificationException cme = new ConcurrentModificationException();
+        cme.initCause(t);
+        throw cme;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.io.IOException;
+
+/**
+ * Internal exception thrown by native methods when error detected.
+ */
+
+class UnixException extends Exception {
+    static final long serialVersionUID = 7227016794320723218L;
+
+    private int errno;
+    private String msg;
+
+    UnixException(int errno) {
+        this.errno = errno;
+        this.msg = null;
+    }
+
+    UnixException(String msg) {
+        this.errno = 0;
+        this.msg = msg;
+    }
+
+    int errno() {
+        return errno;
+    }
+
+    void setError(int errno) {
+        this.errno = errno;
+        this.msg = null;
+    }
+
+    String errorString() {
+        if (msg != null) {
+            return msg;
+        } else {
+            return new String(UnixNativeDispatcher.strerror(errno()));
+        }
+    }
+
+    @Override
+    public String getMessage() {
+        return errorString();
+    }
+
+    /**
+     * Map well known errors to specific exceptions where possible; otherwise
+     * return more general FileSystemException.
+     */
+    private IOException translateToIOException(String file, String other) {
+        // created with message rather than errno
+        if (msg != null)
+            return new IOException(msg);
+
+        // handle specific cases
+        if (errno() == UnixConstants.EACCES)
+            return new AccessDeniedException(file, other, null);
+        if (errno() == UnixConstants.ENOENT)
+            return new NoSuchFileException(file, other, null);
+        if (errno() == UnixConstants.EEXIST)
+            return new FileAlreadyExistsException(file, other, null);
+
+        // fallback to the more general exception
+        return new FileSystemException(file, other, errorString());
+    }
+
+    void rethrowAsIOException(String file) throws IOException {
+        IOException x = translateToIOException(file, null);
+        throw x;
+    }
+
+    void rethrowAsIOException(UnixPath file, UnixPath other) throws IOException {
+        String a = (file == null) ? null : file.getPathForExecptionMessage();
+        String b = (other == null) ? null : other.getPathForExecptionMessage();
+        IOException x = translateToIOException(a, b);
+        throw x;
+    }
+
+    void rethrowAsIOException(UnixPath file) throws IOException {
+        rethrowAsIOException(file, null);
+    }
+
+    IOException asIOException(UnixPath file) {
+        return translateToIOException(file.getPathForExecptionMessage(), null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.io.IOException;
+
+import static sun.nio.fs.UnixNativeDispatcher.*;
+
+class UnixFileAttributeViews {
+
+    static class Basic extends AbstractBasicFileAttributeView {
+        protected final UnixPath file;
+        protected final boolean followLinks;
+
+        Basic(UnixPath file, boolean followLinks) {
+            this.file = file;
+            this.followLinks = followLinks;
+        }
+
+        @Override
+        public BasicFileAttributes readAttributes() throws IOException {
+            file.checkRead();
+            try {
+                 UnixFileAttributes attrs =
+                     UnixFileAttributes.get(file, followLinks);
+                 return attrs.asBasicFileAttributes();
+            } catch (UnixException x) {
+                x.rethrowAsIOException(file);
+                return null;    // keep compiler happy
+            }
+        }
+        @Override
+        public void setTimes(Long lastModifiedTime,
+                             Long lastAccessTime,
+                             Long createTime,
+                             TimeUnit unit) throws IOException
+        {
+            // null => don't change
+            if (lastModifiedTime == null && lastAccessTime == null) {
+                // no effect
+                return;
+            }
+
+            file.checkWrite();
+
+            int fd = file.openForAttributeAccess(followLinks);
+            try {
+                UnixFileAttributes attrs = null;
+
+                // if not changing both attributes then need existing attributes
+                if (lastModifiedTime == null || lastAccessTime == null) {
+                    try {
+                        attrs = UnixFileAttributes.get(fd);
+                    } catch (UnixException x) {
+                        x.rethrowAsIOException(file);
+                    }
+                }
+
+                // modified time = existing, now, or new value
+                long modTime;
+                if (lastModifiedTime == null) {
+                    modTime = attrs.lastModifiedTime();
+                } else {
+                    if (lastModifiedTime >= 0L) {
+                        modTime = TimeUnit.MILLISECONDS.convert(lastModifiedTime, unit);
+                    } else {
+                        if (lastModifiedTime != -1L)
+                            throw new IllegalArgumentException();
+                        modTime = System.currentTimeMillis();
+                    }
+                }
+
+                // access time = existing, now, or new value
+                long accTime;
+                if (lastAccessTime == null) {
+                    accTime = attrs.lastAccessTime();
+                } else {
+                    if (lastAccessTime >= 0L) {
+                        accTime = TimeUnit.MILLISECONDS.convert(lastAccessTime, unit);
+                    } else {
+                        if (lastAccessTime != -1L)
+                            throw new IllegalArgumentException();
+                        accTime = System.currentTimeMillis();
+                    }
+                }
+
+                try {
+                    futimes(fd, accTime, modTime);
+                } catch (UnixException x) {
+                    x.rethrowAsIOException(file);
+                }
+            } finally {
+                close(fd);
+            }
+        }
+    }
+
+    private static class Posix extends Basic implements PosixFileAttributeView {
+        private static final String PERMISSIONS_NAME = "permissions";
+        private static final String OWNER_NAME = "owner";
+        private static final String GROUP_NAME = "group";
+
+        Posix(UnixPath file, boolean followLinks) {
+            super(file, followLinks);
+        }
+
+        final void checkReadExtended() {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                file.checkRead();
+                sm.checkPermission(new RuntimePermission("accessUserInformation"));
+            }
+        }
+
+        final void checkWriteExtended() {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                file.checkWrite();
+                sm.checkPermission(new RuntimePermission("accessUserInformation"));
+            }
+        }
+
+        @Override
+        public String name() {
+            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)
+            throws IOException
+        {
+            if (attribute.equals(PERMISSIONS_NAME)) {
+                setPermissions((Set<PosixFilePermission>)value);
+                return;
+            }
+            if (attribute.equals(OWNER_NAME)) {
+                setOwner((UserPrincipal)value);
+                return;
+            }
+            if (attribute.equals(GROUP_NAME)) {
+                setGroup((GroupPrincipal)value);
+                return;
+            }
+            super.setAttribute(attribute, value);
+        }
+
+        /**
+         * Invoked by readAttributes or sub-classes to add all matching posix
+         * attributes to the builder
+         */
+        final void addPosixAttributesToBuilder(PosixFileAttributes attrs,
+                                               AttributesBuilder builder)
+        {
+            if (builder.match(PERMISSIONS_NAME))
+                builder.add(PERMISSIONS_NAME, attrs.permissions());
+            if (builder.match(OWNER_NAME))
+                 builder.add(OWNER_NAME, attrs.owner());
+            if (builder.match(GROUP_NAME))
+                builder.add(GROUP_NAME, attrs.group());
+        }
+
+        @Override
+        public Map<String,?> readAttributes(String first, String[] rest)
+            throws IOException
+        {
+            AttributesBuilder builder = AttributesBuilder.create(first, rest);
+            PosixFileAttributes attrs = readAttributes();
+            addBasicAttributesToBuilder(attrs, builder);
+            addPosixAttributesToBuilder(attrs, builder);
+            return builder.unmodifiableMap();
+        }
+
+        @Override
+        public UnixFileAttributes readAttributes() throws IOException {
+            checkReadExtended();
+            try {
+                 return UnixFileAttributes.get(file, followLinks);
+            } catch (UnixException x) {
+                x.rethrowAsIOException(file);
+                return null;    // keep compiler happy
+            }
+        }
+
+        // chmod
+        final void setMode(int mode) throws IOException {
+            checkWriteExtended();
+            try {
+                if (followLinks) {
+                    chmod(file, mode);
+                } else {
+                    int fd = file.openForAttributeAccess(false);
+                    try {
+                        fchmod(fd, mode);
+                    } finally {
+                        close(fd);
+                    }
+                }
+            } catch (UnixException x) {
+                x.rethrowAsIOException(file);
+            }
+        }
+
+        // chown
+        final void setOwners(int uid, int gid) throws IOException {
+            checkWriteExtended();
+            try {
+                if (followLinks) {
+                    chown(file, uid, gid);
+                } else {
+                    lchown(file, uid, gid);
+                }
+            } catch (UnixException x) {
+                x.rethrowAsIOException(file);
+            }
+        }
+
+        @Override
+        public void setPermissions(Set<PosixFilePermission> perms)
+            throws IOException
+        {
+            setMode(UnixFileModeAttribute.toUnixMode(perms));
+        }
+
+        @Override
+        public void setOwner(UserPrincipal owner)
+            throws IOException
+        {
+            if (owner == null)
+                throw new NullPointerException("'owner' is null");
+            if (!(owner instanceof UnixUserPrincipals.User))
+                throw new ProviderMismatchException();
+            if (owner instanceof UnixUserPrincipals.Group)
+                throw new IOException("'owner' parameter can't be a group");
+            int uid = ((UnixUserPrincipals.User)owner).uid();
+            setOwners(uid, -1);
+        }
+
+        @Override
+        public UserPrincipal getOwner() throws IOException {
+            return readAttributes().owner();
+        }
+
+        @Override
+        public void setGroup(GroupPrincipal group)
+            throws IOException
+        {
+            if (group == null)
+                throw new NullPointerException("'owner' is null");
+            if (!(group instanceof UnixUserPrincipals.Group))
+                throw new ProviderMismatchException();
+            int gid = ((UnixUserPrincipals.Group)group).gid();
+            setOwners(-1, gid);
+        }
+    }
+
+    private static class Unix extends Posix {
+        private static final String MODE_NAME = "mode";
+        private static final String INO_NAME = "ino";
+        private static final String DEV_NAME = "dev";
+        private static final String RDEV_NAME = "rdev";
+        private static final String UID_NAME = "uid";
+        private static final String GID_NAME = "gid";
+        private static final String CTIME_NAME = "ctime";
+
+        Unix(UnixPath file, boolean followLinks) {
+            super(file, followLinks);
+        }
+
+        @Override
+        public String name() {
+            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(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
+        {
+            if (attribute.equals(MODE_NAME)) {
+                setMode((Integer)value);
+                return;
+            }
+            if (attribute.equals(UID_NAME)) {
+                setOwners((Integer)value, -1);
+                return;
+            }
+            if (attribute.equals(GID_NAME)) {
+                setOwners(-1, (Integer)value);
+                return;
+            }
+            super.setAttribute(attribute, value);
+        }
+
+        @Override
+        public Map<String,?> readAttributes(String first, String[] rest)
+            throws IOException
+        {
+            AttributesBuilder builder = AttributesBuilder.create(first, rest);
+            UnixFileAttributes attrs = readAttributes();
+            addBasicAttributesToBuilder(attrs, builder);
+            addPosixAttributesToBuilder(attrs, builder);
+            if (builder.match(MODE_NAME))
+                builder.add(MODE_NAME, attrs.mode());
+            if (builder.match(INO_NAME))
+                builder.add(INO_NAME, attrs.ino());
+            if (builder.match(DEV_NAME))
+                builder.add(DEV_NAME, attrs.dev());
+            if (builder.match(RDEV_NAME))
+                builder.add(RDEV_NAME, attrs.rdev());
+            if (builder.match(UID_NAME))
+                builder.add(UID_NAME, attrs.uid());
+            if (builder.match(GID_NAME))
+                builder.add(GID_NAME, attrs.gid());
+            if (builder.match(CTIME_NAME))
+                builder.add(CTIME_NAME, attrs.ctime());
+            return builder.unmodifiableMap();
+        }
+    }
+
+    static BasicFileAttributeView createBasicView(UnixPath file, boolean followLinks) {
+        return new Basic(file, followLinks);
+    }
+
+    static PosixFileAttributeView createPosixView(UnixPath file, boolean followLinks) {
+        return new Posix(file, followLinks);
+    }
+
+    static PosixFileAttributeView createUnixView(UnixPath file, boolean followLinks) {
+        return new Unix(file, followLinks);
+    }
+
+    static FileOwnerAttributeView createOwnerView(UnixPath file, boolean followLinks) {
+        return new FileOwnerAttributeViewImpl(createPosixView(file, followLinks));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,307 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.attribute.*;
+import java.util.concurrent.TimeUnit;
+import java.util.Set;
+import java.util.HashSet;
+
+/**
+ * Unix implementation of PosixFileAttributes.
+ */
+
+class UnixFileAttributes
+    implements PosixFileAttributes
+{
+    private int     st_mode;
+    private long    st_ino;
+    private long    st_dev;
+    private long    st_rdev;
+    private int     st_nlink;
+    private int     st_uid;
+    private int     st_gid;
+    private long    st_size;
+    private long    st_atime;
+    private long    st_mtime;
+    private long    st_ctime;
+
+    // created lazily
+    private volatile UserPrincipal owner;
+    private volatile GroupPrincipal group;
+    private volatile UnixFileKey key;
+
+    private UnixFileAttributes() {
+    }
+
+    // get the UnixFileAttributes for a given file
+    static UnixFileAttributes get(UnixPath path, boolean followLinks)
+        throws UnixException
+    {
+        UnixFileAttributes attrs = new UnixFileAttributes();
+        if (followLinks) {
+            UnixNativeDispatcher.stat(path, attrs);
+        } else {
+            UnixNativeDispatcher.lstat(path, attrs);
+        }
+        return attrs;
+    }
+
+    // get the UnixFileAttributes for an open file
+    static UnixFileAttributes get(int fd) throws UnixException {
+        UnixFileAttributes attrs = new UnixFileAttributes();
+        UnixNativeDispatcher.fstat(fd, attrs);
+        return attrs;
+    }
+
+    // get the UnixFileAttributes for a given file, relative to open directory
+    static UnixFileAttributes get(int dfd, UnixPath path, boolean followLinks)
+        throws UnixException
+    {
+        UnixFileAttributes attrs = new UnixFileAttributes();
+        int flag = (followLinks) ? 0 : UnixConstants.AT_SYMLINK_NOFOLLOW;
+        UnixNativeDispatcher.fstatat(dfd, path.asByteArray(), flag, attrs);
+        return attrs;
+    }
+
+    // package-private
+    boolean isSameFile(UnixFileAttributes attrs) {
+        return ((st_ino == attrs.st_ino) && (st_dev == attrs.st_dev));
+    }
+
+    // package-private
+    int mode()  { return st_mode; }
+    long ino()  { return st_ino; }
+    long dev()  { return st_dev; }
+    long rdev() { return st_rdev; }
+    int uid()   { return st_uid; }
+    int gid()   { return st_gid; }
+    long ctime() { return st_ctime; }
+
+    boolean isDevice() {
+        int type = st_mode & UnixConstants.S_IFMT;
+        return (type == UnixConstants.S_IFCHR ||
+                type == UnixConstants.S_IFBLK  ||
+                type == UnixConstants.S_IFIFO);
+    }
+
+    @Override
+    public long lastModifiedTime() {
+        return st_mtime;
+    }
+
+    @Override
+    public long lastAccessTime() {
+        return st_atime;
+    }
+
+    @Override
+    public long creationTime() {
+        return -1L;
+    }
+
+    @Override
+    public TimeUnit resolution() {
+        return TimeUnit.MILLISECONDS;
+    }
+
+    @Override
+    public boolean isRegularFile() {
+       return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFREG);
+    }
+
+    @Override
+    public boolean isDirectory() {
+        return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR);
+    }
+
+    @Override
+    public boolean isSymbolicLink() {
+        return ((st_mode & UnixConstants.S_IFMT) == UnixConstants.S_IFLNK);
+    }
+
+    @Override
+    public boolean isOther() {
+        int type = st_mode & UnixConstants.S_IFMT;
+        return (type != UnixConstants.S_IFREG &&
+                type != UnixConstants.S_IFDIR &&
+                type != UnixConstants.S_IFLNK);
+    }
+
+    @Override
+    public long size() {
+        return st_size;
+    }
+
+    @Override
+    public int linkCount() {
+        return st_nlink;
+    }
+
+    @Override
+    public UnixFileKey fileKey() {
+        if (key == null) {
+            synchronized (this) {
+                if (key == null) {
+                    key = new UnixFileKey(st_dev, st_ino);
+                }
+            }
+        }
+        return key;
+    }
+
+    @Override
+    public UserPrincipal owner() {
+        if (owner == null) {
+            synchronized (this) {
+                if (owner == null) {
+                    owner = UnixUserPrincipals.fromUid(st_uid);
+                }
+            }
+        }
+        return owner;
+    }
+
+    @Override
+    public GroupPrincipal group() {
+        if (group == null) {
+            synchronized (this) {
+                if (group == null) {
+                    group = UnixUserPrincipals.fromGid(st_gid);
+                }
+            }
+        }
+        return group;
+    }
+
+    @Override
+    public Set<PosixFilePermission> permissions() {
+        int bits = (st_mode & UnixConstants.S_IAMB);
+        HashSet<PosixFilePermission> perms = new HashSet<PosixFilePermission>();
+
+        if ((bits & UnixConstants.S_IRUSR) > 0)
+            perms.add(PosixFilePermission.OWNER_READ);
+        if ((bits & UnixConstants.S_IWUSR) > 0)
+            perms.add(PosixFilePermission.OWNER_WRITE);
+        if ((bits & UnixConstants.S_IXUSR) > 0)
+            perms.add(PosixFilePermission.OWNER_EXECUTE);
+
+        if ((bits & UnixConstants.S_IRGRP) > 0)
+            perms.add(PosixFilePermission.GROUP_READ);
+        if ((bits & UnixConstants.S_IWGRP) > 0)
+            perms.add(PosixFilePermission.GROUP_WRITE);
+        if ((bits & UnixConstants.S_IXGRP) > 0)
+            perms.add(PosixFilePermission.GROUP_EXECUTE);
+
+        if ((bits & UnixConstants.S_IROTH) > 0)
+            perms.add(PosixFilePermission.OTHERS_READ);
+        if ((bits & UnixConstants.S_IWOTH) > 0)
+            perms.add(PosixFilePermission.OTHERS_WRITE);
+        if ((bits & UnixConstants.S_IXOTH) > 0)
+            perms.add(PosixFilePermission.OTHERS_EXECUTE);
+
+        return perms;
+    }
+
+    // wrap this object with BasicFileAttributes object to prevent leaking of
+    // user information
+    BasicFileAttributes asBasicFileAttributes() {
+        return UnixAsBasicFileAttributes.wrap(this);
+    }
+
+    // unwrap BasicFileAttributes to get the underlying UnixFileAttributes
+    // object. Returns null is not wrapped.
+    static UnixFileAttributes toUnixFileAttributes(BasicFileAttributes attrs) {
+        if (attrs instanceof UnixFileAttributes)
+            return (UnixFileAttributes)attrs;
+        if (attrs instanceof UnixAsBasicFileAttributes) {
+            return ((UnixAsBasicFileAttributes)attrs).unwrap();
+        }
+        return null;
+    }
+
+    // wrap a UnixFileAttributes object as a BasicFileAttributes
+    private static class UnixAsBasicFileAttributes implements BasicFileAttributes {
+        private final UnixFileAttributes attrs;
+
+        private UnixAsBasicFileAttributes(UnixFileAttributes attrs) {
+            this.attrs = attrs;
+        }
+
+        static UnixAsBasicFileAttributes wrap(UnixFileAttributes attrs) {
+            return new UnixAsBasicFileAttributes(attrs);
+        }
+
+        UnixFileAttributes unwrap() {
+            return attrs;
+        }
+
+        @Override
+        public long lastModifiedTime() {
+            return attrs.lastModifiedTime();
+        }
+        @Override
+        public long lastAccessTime() {
+            return attrs.lastAccessTime();
+        }
+        @Override
+        public long creationTime() {
+            return attrs.creationTime();
+        }
+        @Override
+        public TimeUnit resolution() {
+            return attrs.resolution();
+        }
+        @Override
+        public boolean isRegularFile() {
+            return attrs.isRegularFile();
+        }
+        @Override
+        public boolean isDirectory() {
+            return attrs.isDirectory();
+        }
+        @Override
+        public boolean isSymbolicLink() {
+            return attrs.isSymbolicLink();
+        }
+        @Override
+        public boolean isOther() {
+            return attrs.isOther();
+        }
+        @Override
+        public long size() {
+            return attrs.size();
+        }
+        @Override
+        public int linkCount() {
+            return attrs.linkCount();
+        }
+        @Override
+        public Object fileKey() {
+            return attrs.fileKey();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileKey.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+/**
+ * Container for device/inode to uniquely identify file.
+ */
+
+class UnixFileKey {
+    private final long st_dev;
+    private final long st_ino;
+
+    UnixFileKey(long st_dev, long st_ino) {
+        this.st_dev = st_dev;
+        this.st_ino = st_ino;
+    }
+
+    @Override
+    public int hashCode() {
+        return (int)(st_dev ^ (st_dev >>> 32)) +
+               (int)(st_ino ^ (st_ino >>> 32));
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this)
+            return true;
+        if (!(obj instanceof UnixFileKey))
+            return false;
+        UnixFileKey other = (UnixFileKey)obj;
+        return (this.st_dev == other.st_dev) && (this.st_ino == other.st_ino);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileModeAttribute.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.attribute.*;
+import java.util.*;
+
+class UnixFileModeAttribute {
+    static final int ALL_PERMISSIONS =
+        UnixConstants.S_IRUSR | UnixConstants.S_IWUSR | UnixConstants.S_IXUSR |
+        UnixConstants.S_IRGRP | UnixConstants.S_IWGRP | UnixConstants.S_IXGRP |
+        UnixConstants.S_IROTH | UnixConstants.S_IWOTH | UnixConstants. S_IXOTH;
+
+    static final int ALL_READWRITE =
+        UnixConstants.S_IRUSR | UnixConstants.S_IWUSR |
+        UnixConstants.S_IRGRP | UnixConstants.S_IWGRP |
+        UnixConstants.S_IROTH | UnixConstants.S_IWOTH;
+
+    static final int TEMPFILE_PERMISSIONS =
+        UnixConstants.S_IRUSR | UnixConstants.S_IWUSR | UnixConstants.S_IXUSR;
+
+    private Set<PosixFilePermission> perms;
+
+    UnixFileModeAttribute() {
+        perms = Collections.emptySet();
+    }
+
+    static int toUnixMode(Set<PosixFilePermission> perms) {
+        int mode = 0;
+        for (PosixFilePermission perm: perms) {
+            if (perm == null)
+                throw new NullPointerException();
+            switch (perm) {
+                case OWNER_READ :     mode |= UnixConstants.S_IRUSR; break;
+                case OWNER_WRITE :    mode |= UnixConstants.S_IWUSR; break;
+                case OWNER_EXECUTE :  mode |= UnixConstants.S_IXUSR; break;
+                case GROUP_READ :     mode |= UnixConstants.S_IRGRP; break;
+                case GROUP_WRITE :    mode |= UnixConstants.S_IWGRP; break;
+                case GROUP_EXECUTE :  mode |= UnixConstants.S_IXGRP; break;
+                case OTHERS_READ :    mode |= UnixConstants.S_IROTH; break;
+                case OTHERS_WRITE :   mode |= UnixConstants.S_IWOTH; break;
+                case OTHERS_EXECUTE : mode |= UnixConstants.S_IXOTH; break;
+            }
+        }
+        return mode;
+    }
+
+    @SuppressWarnings("unchecked")
+    static int toUnixMode(int defaultMode, FileAttribute<?>... attrs) {
+        int mode = defaultMode;
+        for (FileAttribute<?> attr: attrs) {
+            String name = attr.name();
+            if (!name.equals("posix:permissions") && !name.equals("unix:permissions")) {
+                throw new UnsupportedOperationException("'" + attr.name() +
+                   "' not supported as initial attribute");
+            }
+            mode = toUnixMode((Set<PosixFilePermission>)attr.value());
+        }
+        return mode;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileStore.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.nio.channels.*;
+import java.util.*;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Base implementation of FileStore for Unix/like implementations.
+ */
+
+abstract class UnixFileStore
+    extends FileStore
+{
+    // original path of file that identified file system
+    private final UnixPath file;
+
+    // device ID
+    private final long dev;
+
+    // entry in the mount tab
+    private final UnixMountEntry entry;
+
+    // return the device ID where the given file resides
+    private static long devFor(UnixPath file) throws IOException {
+        try {
+            return UnixFileAttributes.get(file, true).dev();
+        } catch (UnixException x) {
+            x.rethrowAsIOException(file);
+            return 0L;  // keep compiler happy
+        }
+    }
+
+    UnixFileStore(UnixPath file) throws IOException {
+        this.file = file;
+        this.dev = devFor(file);
+        this.entry = findMountEntry();
+    }
+
+    UnixFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException {
+        this.file = new UnixPath(fs, entry.dir());
+        this.dev = (entry.dev() == 0L) ? devFor(this.file) : entry.dev();
+        this.entry = entry;
+    }
+
+    /**
+     * Find the mount entry for the file store
+     */
+    abstract UnixMountEntry findMountEntry() throws IOException;
+
+    /**
+     * Returns true if this file store represents a loopback file system that
+     * will have the same device ID as undelrying file system.
+     */
+    abstract boolean isLoopback();
+
+    UnixPath file() {
+        return file;
+    }
+
+    long dev() {
+        return dev;
+    }
+
+    UnixMountEntry entry() {
+        return entry;
+    }
+
+    @Override
+    public String name() {
+        return entry.name();
+    }
+
+    @Override
+    public String type() {
+        return entry.fstype();
+    }
+
+    @Override
+    public boolean isReadOnly() {
+        return entry.isReadOnly();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> viewType)
+    {
+        if (viewType == FileStoreSpaceAttributeView.class)
+            return (V) new UnixFileStoreSpaceAttributeView(this);
+        return (V) null;
+    }
+
+    @Override
+    public FileStoreAttributeView getFileStoreAttributeView(String name) {
+        if (name.equals("space"))
+            return new UnixFileStoreSpaceAttributeView(this);
+        return  null;
+    }
+
+    @Override
+    public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
+        if (type == BasicFileAttributeView.class)
+            return true;
+        if (type == PosixFileAttributeView.class ||
+            type == FileOwnerAttributeView.class)
+        {
+            // lookup fstypes.properties
+            FeatureStatus status = checkIfFeaturePresent("posix");
+            if (status == FeatureStatus.NOT_PRESENT)
+                return false;
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean supportsFileAttributeView(String name) {
+        if (name.equals("basic") || name.equals("unix"))
+            return true;
+        if (name.equals("posix"))
+            return supportsFileAttributeView(PosixFileAttributeView.class);
+        if (name.equals("owner"))
+            return supportsFileAttributeView(FileOwnerAttributeView.class);
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object ob) {
+        if (ob == this)
+            return true;
+        if (!(ob instanceof UnixFileStore))
+            return false;
+        UnixFileStore other = (UnixFileStore)ob;
+        if (dev != other.dev)
+            return false;
+        // deviceIDs are equal but they may not be equal if one or both of
+        // them is a loopback file system
+        boolean thisIsLoopback = isLoopback();
+        if (thisIsLoopback != other.isLoopback())
+            return false;  // one, but not both, are lofs
+        if (!thisIsLoopback)
+            return true;    // neither is lofs
+        // both are lofs so compare mount points
+        return Arrays.equals(this.entry.dir(), other.entry.dir());
+    }
+
+    @Override
+    public int hashCode() {
+        return (int)(dev ^ (dev >>> 32));
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(new String(entry.dir()));
+        sb.append(" (");
+        sb.append(entry.name());
+        sb.append(")");
+        return sb.toString();
+    }
+
+    private static class UnixFileStoreSpaceAttributeView
+        extends AbstractFileStoreSpaceAttributeView
+    {
+        private final UnixFileStore fs;
+
+        UnixFileStoreSpaceAttributeView(UnixFileStore fs) {
+            this.fs = fs;
+        }
+
+        @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();
+    private static volatile Properties props;
+
+    enum FeatureStatus {
+        PRESENT,
+        NOT_PRESENT,
+        UNKNOWN;
+    }
+
+    /**
+     * Returns status to indicate if file system supports a given feature
+     */
+    FeatureStatus checkIfFeaturePresent(String feature) {
+        if (props == null) {
+            synchronized (loadLock) {
+                if (props == null) {
+                    props = AccessController.doPrivileged(
+                        new PrivilegedAction<Properties>() {
+                            @Override
+                            public Properties run() {
+                                return loadProperties();
+                            }});
+                }
+            }
+        }
+
+        String value = props.getProperty(type());
+        if (value != null) {
+            String[] values = value.split("\\s");
+            for (String s: values) {
+                s = s.trim().toLowerCase();
+                if (s.equals(feature)) {
+                    return FeatureStatus.PRESENT;
+                }
+                if (s.startsWith("no")) {
+                    s = s.substring(2);
+                    if (s.equals(feature)) {
+                        return FeatureStatus.NOT_PRESENT;
+                    }
+                }
+            }
+        }
+        return FeatureStatus.UNKNOWN;
+    }
+
+    private static Properties loadProperties() {
+        Properties result = new Properties();
+        String fstypes = System.getProperty("java.home") + "/lib/fstypes.properties";
+        FileRef file = Paths.get(fstypes);
+        try {
+            ReadableByteChannel rbc = file.newByteChannel();
+            try {
+                result.load(Channels.newReader(rbc, "UTF-8"));
+            } finally {
+                rbc.close();
+            }
+        } catch (IOException x) {
+        }
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileStoreAttributes.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+class UnixFileStoreAttributes {
+    private long f_frsize;          // block size
+    private long f_blocks;          // total
+    private long f_bfree;           // free
+    private long f_bavail;          // usable
+
+    private UnixFileStoreAttributes() {
+    }
+
+    static UnixFileStoreAttributes get(UnixPath path) throws UnixException {
+        UnixFileStoreAttributes attrs = new UnixFileStoreAttributes();
+        UnixNativeDispatcher.statvfs(path, attrs);
+        return attrs;
+    }
+
+    long blockSize() {
+        return f_frsize;
+    }
+
+    long totalBlocks() {
+        return f_blocks;
+    }
+
+    long freeBlocks() {
+        return f_bfree;
+    }
+
+    long availableBlocks() {
+        return f_bavail;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystem.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.nio.file.spi.*;
+import java.io.IOException;
+import java.util.*;
+import java.util.regex.Pattern;
+import java.security.AccessController;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * Base implementation of FileSystem for Unix-like implementations.
+ */
+
+abstract class UnixFileSystem
+    extends FileSystem
+{
+    private final UnixFileSystemProvider provider;
+    private final byte[] defaultDirectory;
+    private final boolean needToResolveAgainstDefaultDirectory;
+    private final UnixPath rootDirectory;
+
+    // package-private
+    UnixFileSystem(UnixFileSystemProvider provider, String dir) {
+        this.provider = provider;
+        this.defaultDirectory = UnixPath.normalizeAndCheck(dir).getBytes();
+        if (this.defaultDirectory[0] != '/') {
+            throw new RuntimeException("default directory must be absolute");
+        }
+
+        // if process-wide chdir is allowed or default directory is not the
+        // process working directory then paths must be resolved against the
+        // default directory.
+        String propValue = AccessController.doPrivileged(
+            new GetPropertyAction("sun.nio.fs.chdirAllowed", "false"));
+        boolean chdirAllowed = (propValue.length() == 0) ?
+            true : Boolean.valueOf(propValue);
+        if (chdirAllowed) {
+            this.needToResolveAgainstDefaultDirectory = true;
+        } else {
+            byte[] cwd = UnixNativeDispatcher.getcwd();
+            boolean defaultIsCwd = (cwd.length == defaultDirectory.length);
+            if (defaultIsCwd) {
+                for (int i=0; i<cwd.length; i++) {
+                    if (cwd[i] != defaultDirectory[i]) {
+                        defaultIsCwd = false;
+                        break;
+                    }
+                }
+            }
+            this.needToResolveAgainstDefaultDirectory = !defaultIsCwd;
+        }
+
+        // the root directory
+        this.rootDirectory = new UnixPath(this, "/");
+    }
+
+    // package-private
+    byte[] defaultDirectory() {
+        return defaultDirectory;
+    }
+
+    boolean needToResolveAgainstDefaultDirectory() {
+        return needToResolveAgainstDefaultDirectory;
+    }
+
+    UnixPath rootDirectory() {
+        return rootDirectory;
+    }
+
+    boolean isSolaris() {
+        return false;
+    }
+
+    @Override
+    public final FileSystemProvider provider() {
+        return provider;
+    }
+
+    @Override
+    public final String getSeparator() {
+        return "/";
+    }
+
+    @Override
+    public final boolean isOpen() {
+        return true;
+    }
+
+    @Override
+    public final boolean isReadOnly() {
+        return false;
+    }
+
+    @Override
+    public final void close() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Copies non-POSIX attributes from the source to target file.
+     *
+     * Copying a file preserving attributes, or moving a file, will preserve
+     * the file owner/group/permissions/timestamps but it does not preserve
+     * other non-POSIX attributes. This method is invoked by the
+     * copy or move operation to preserve these attributes. It should copy
+     * extended attributes, ACLs, or other attributes.
+     *
+     * @param   sfd
+     *          Open file descriptor to source file
+     * @param   tfd
+     *          Open file descriptor to target file
+     */
+    abstract void copyNonPosixAttributes(int sfd, int tfd);
+
+    /**
+     * Tells if directory relative system calls (openat, etc.) are available
+     * on this operating system.
+     */
+    abstract boolean supportsSecureDirectoryStreams();
+
+    /**
+     * Unix systems only have a single root directory (/)
+     */
+    @Override
+    public final Iterable<Path> getRootDirectories() {
+        final List<Path> allowedList =
+           Collections.unmodifiableList(Arrays.asList((Path)rootDirectory));
+        return new Iterable<Path>() {
+            public Iterator<Path> iterator() {
+                try {
+                    SecurityManager sm = System.getSecurityManager();
+                    if (sm != null)
+                        sm.checkRead(rootDirectory.toString());
+                    return allowedList.iterator();
+                } catch (SecurityException x) {
+                    List<Path> disallowed = Collections.emptyList();
+                    return disallowed.iterator();
+                }
+            }
+        };
+    }
+
+    /**
+     * Returns object to iterate over entries in mounttab or equivalent
+     */
+    abstract Iterable<UnixMountEntry> 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.
+     */
+    abstract FileStore getFileStore(UnixMountEntry entry) throws IOException;
+
+    /**
+     * Iterator returned by getFileStores method.
+     */
+    private class FileStoreIterator implements Iterator<FileStore> {
+        private final Iterator<UnixMountEntry> entries;
+        private FileStore next;
+
+        FileStoreIterator() {
+            this.entries = getMountEntries().iterator();
+        }
+
+        private FileStore readNext() {
+            assert Thread.holdsLock(this);
+            for (;;) {
+                if (!entries.hasNext())
+                    return null;
+                UnixMountEntry entry = entries.next();
+
+                // skip entries with the "ignore" option
+                if (entry.isIgnored())
+                    continue;
+
+                // check permission to read mount point
+                SecurityManager sm = System.getSecurityManager();
+                if (sm != null) {
+                    try {
+                        sm.checkRead(new String(entry.dir()));
+                    } catch (SecurityException x) {
+                        continue;
+                    }
+                }
+                try {
+                    return getFileStore(entry);
+                } catch (IOException ignore) {
+                    // ignore as per spec
+                }
+            }
+        }
+
+        @Override
+        public synchronized boolean hasNext() {
+            if (next != null)
+                return true;
+            next = readNext();
+            return next != null;
+        }
+
+        @Override
+        public synchronized FileStore next() {
+            if (next == null)
+                next = readNext();
+            if (next == null) {
+                throw new NoSuchElementException();
+            } else {
+                FileStore result = next;
+                next = null;
+                return result;
+            }
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    @Override
+    public final Iterable<FileStore> getFileStores() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            try {
+                sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));
+            } catch (SecurityException se) {
+                return Collections.emptyList();
+            }
+        }
+        return new Iterable<FileStore>() {
+            public Iterator<FileStore> iterator() {
+                return new FileStoreIterator();
+            }
+        };
+    }
+
+    @Override
+    public final UnixPath getPath(String path) {
+        return new UnixPath(this, path);
+    }
+
+    @Override
+    public PathMatcher getPathMatcher(String syntaxAndInput) {
+        int pos = syntaxAndInput.indexOf(':');
+        if (pos <= 0 || pos == syntaxAndInput.length())
+            throw new IllegalArgumentException();
+        String syntax = syntaxAndInput.substring(0, pos);
+        String input = syntaxAndInput.substring(pos+1);
+
+        String expr;
+        if (syntax.equals(GLOB_SYNTAX)) {
+            expr = Globs.toUnixRegexPattern(input);
+        } else {
+            if (syntax.equals(REGEX_SYNTAX)) {
+                expr = input;
+            } else {
+                throw new UnsupportedOperationException("Syntax '" + syntax +
+                    "' not recognized");
+            }
+        }
+
+        // return matcher
+        final Pattern pattern = Pattern.compile(expr);
+        return new PathMatcher() {
+            @Override
+            public boolean matches(Path path) {
+                return pattern.matcher(path.toString()).matches();
+            }
+        };
+    }
+    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 extends FileAttributeView> V newFileAttributeView(Class<V> 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<String> standardFileAttributeViews() {
+        return Arrays.asList("basic", "posix", "unix", "owner");
+    }
+
+    protected FileAttributeView 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;
+    }
+
+    private static final UserPrincipalLookupService theLookupService =
+        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);
+            }
+        };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+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.util.*;
+
+import sun.nio.ch.ThreadPool;
+
+/**
+ * Base implementation of FileSystemProvider
+ */
+
+public abstract class UnixFileSystemProvider
+    extends FileSystemProvider
+{
+    private static final String USER_DIR = "user.dir";
+    private final UnixFileSystem theFileSystem;
+
+    public UnixFileSystemProvider() {
+        String userDir = System.getProperty(USER_DIR);
+        theFileSystem = newFileSystem(userDir);
+    }
+
+    /**
+     * Constructs a new file system using the given default directory.
+     */
+    abstract UnixFileSystem newFileSystem(String dir);
+
+    @Override
+    public final String getScheme() {
+        return "file";
+    }
+
+    private void checkUri(URI uri) {
+        if (!uri.getScheme().equalsIgnoreCase(getScheme()))
+            throw new IllegalArgumentException("URI does not match this provider");
+        if (uri.getAuthority() != null)
+            throw new IllegalArgumentException("Authority component present");
+        if (uri.getPath() == null)
+            throw new IllegalArgumentException("Path component is undefined");
+        if (!uri.getPath().equals("/"))
+            throw new IllegalArgumentException("Path component should be '/'");
+        if (uri.getQuery() != null)
+            throw new IllegalArgumentException("Query component present");
+        if (uri.getFragment() != null)
+            throw new IllegalArgumentException("Fragment component present");
+    }
+
+    @Override
+    public final FileSystem newFileSystem(URI uri, Map<String,?> env) {
+        checkUri(uri);
+        throw new FileSystemAlreadyExistsException();
+    }
+
+    @Override
+    public final FileSystem getFileSystem(URI uri) {
+        checkUri(uri);
+        return theFileSystem;
+    }
+
+    @Override
+    public Path getPath(URI uri) {
+        return UnixUriUtils.fromUri(theFileSystem, uri);
+    }
+
+    private UnixPath checkPath(Path obj) {
+        if (obj == null)
+            throw new NullPointerException();
+        if (!(obj instanceof UnixPath))
+            throw new ProviderMismatchException();
+        return (UnixPath)obj;
+    }
+
+    @Override
+    public final FileChannel newFileChannel(Path obj,
+                                            Set<? extends OpenOption> options,
+                                            FileAttribute<?>... attrs)
+        throws IOException
+    {
+        UnixPath file = checkPath(obj);
+        int mode = UnixFileModeAttribute
+            .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
+        try {
+            return UnixChannelFactory.newFileChannel(file, options, mode);
+        } catch (UnixException x) {
+            x.rethrowAsIOException(file);
+            return null;
+        }
+    }
+
+    @Override
+    public final AsynchronousFileChannel newAsynchronousFileChannel(Path obj,
+                                                                    Set<? extends OpenOption> options,
+                                                                    ExecutorService executor,
+                                                                    FileAttribute<?>... attrs) throws IOException
+    {
+        UnixPath file = checkPath(obj);
+        int mode = UnixFileModeAttribute
+            .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
+        ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0);
+        try {
+            return UnixChannelFactory
+                .newAsynchronousFileChannel(file, options, mode, pool);
+        } catch (UnixException x) {
+            x.rethrowAsIOException(file);
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixMountEntry.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+/**
+ * Represents an entry in the mount table.
+ */
+
+class UnixMountEntry {
+    private byte[] name;        // file system name
+    private byte[] dir;         // directory (mount point)
+    private byte[] fstype;      // ufs, nfs, ...
+    private byte[] opts;        // mount options
+    private long dev;           // device ID
+
+    private volatile String fstypeAsString;
+    private volatile String optionsAsString;
+
+    UnixMountEntry() {
+    }
+
+    String name() {
+        return new String(name);
+    }
+
+    String fstype() {
+        if (fstypeAsString == null)
+            fstypeAsString = new String(fstype);
+        return fstypeAsString;
+    }
+
+    byte[] dir() {
+        return dir;
+    }
+
+    long dev() {
+        return dev;
+    }
+
+    /**
+     * Tells whether the mount entry has the given option.
+     */
+    boolean hasOption(String requested) {
+        if (optionsAsString == null)
+            optionsAsString = new String(opts);
+        for (String opt: optionsAsString.split("\\,", 0)) {
+            if (opt.equals(requested))
+                return true;
+        }
+        return false;
+    }
+
+    // generic option
+    boolean isIgnored() {
+        return hasOption("ignore");
+    }
+
+    // generic option
+    boolean isReadOnly() {
+        return hasOption("ro");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,556 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Unix system and library calls.
+ */
+
+class UnixNativeDispatcher {
+    protected UnixNativeDispatcher() { }
+
+    // returns a NativeBuffer containing the given path
+    private static NativeBuffer copyToNativeBuffer(UnixPath path) {
+        byte[] cstr = path.getByteArrayForSysCalls();
+        int size = cstr.length + 1;
+        NativeBuffer buffer = NativeBuffers.getNativeBufferFromCache(size);
+        if (buffer == null) {
+            buffer = NativeBuffers.allocNativeBuffer(size);
+        } else {
+            // buffer already contains the path
+            if (buffer.owner() == path)
+                return buffer;
+        }
+        NativeBuffers.copyCStringToNativeBuffer(cstr, buffer);
+        buffer.setOwner(path);
+        return buffer;
+    }
+
+    /**
+     * char *getcwd(char *buf, size_t size);
+     */
+    static native byte[] getcwd();
+
+    /**
+     * int dup(int filedes)
+     */
+    static native int dup(int filedes) throws UnixException;
+
+    /**
+     * int open(const char* path, int oflag, mode_t mode)
+     */
+    static int open(UnixPath path, int flags, int mode) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            return open0(buffer.address(), flags, mode);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native int open0(long pathAddress, int flags, int mode)
+        throws UnixException;
+
+    /**
+     * int openat(int dfd, const char* path, int oflag, mode_t mode)
+     */
+    static int openat(int dfd, byte[] path, int flags, int mode) throws UnixException {
+        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+        try {
+            return openat0(dfd, buffer.address(), flags, mode);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native int openat0(int dfd, long pathAddress, int flags, int mode)
+        throws UnixException;
+
+    /**
+     * close(int filedes)
+     */
+    static native void close(int fd);
+
+    /**
+     * FILE* fopen(const char *filename, const char* mode);
+     */
+    static long fopen(UnixPath filename, String mode) throws UnixException {
+        NativeBuffer pathBuffer = copyToNativeBuffer(filename);
+        NativeBuffer modeBuffer = NativeBuffers.asNativeBuffer(mode.getBytes());
+        try {
+            return fopen0(pathBuffer.address(), modeBuffer.address());
+        } finally {
+            modeBuffer.release();
+            pathBuffer.release();
+        }
+    }
+    private static native long fopen0(long pathAddress, long modeAddress)
+        throws UnixException;
+
+    /**
+     * fclose(FILE* stream)
+     */
+    static native void fclose(long stream) throws UnixException;
+
+    /**
+     * link(const char* existing, const char* new)
+     */
+    static void link(UnixPath existing, UnixPath newfile) throws UnixException {
+        NativeBuffer existingBuffer = copyToNativeBuffer(existing);
+        NativeBuffer newBuffer = copyToNativeBuffer(newfile);
+        try {
+            link0(existingBuffer.address(), newBuffer.address());
+        } finally {
+            newBuffer.release();
+            existingBuffer.release();
+        }
+    }
+    private static native void link0(long existingAddress, long newAddress)
+        throws UnixException;
+
+    /**
+     * unlink(const char* path)
+     */
+    static void unlink(UnixPath path) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            unlink0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void unlink0(long pathAddress) throws UnixException;
+
+    /**
+     * unlinkat(int dfd, const char* path, int flag)
+     */
+    static void unlinkat(int dfd, byte[] path, int flag) throws UnixException {
+        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+        try {
+            unlinkat0(dfd, buffer.address(), flag);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void unlinkat0(int dfd, long pathAddress, int flag)
+        throws UnixException;
+
+    /**
+     * mknod(const char* path, mode_t mode, dev_t dev)
+     */
+    static void mknod(UnixPath path, int mode, long dev) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            mknod0(buffer.address(), mode, dev);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void mknod0(long pathAddress, int mode, long dev)
+        throws UnixException;
+
+    /**
+     *  rename(const char* old, const char* new)
+     */
+    static void rename(UnixPath from, UnixPath to) throws UnixException {
+        NativeBuffer fromBuffer = copyToNativeBuffer(from);
+        NativeBuffer toBuffer = copyToNativeBuffer(to);
+        try {
+            rename0(fromBuffer.address(), toBuffer.address());
+        } finally {
+            toBuffer.release();
+            fromBuffer.release();
+        }
+    }
+    private static native void rename0(long fromAddress, long toAddress)
+        throws UnixException;
+
+    /**
+     *  renameat(int fromfd, const char* old, int tofd, const char* new)
+     */
+    static void renameat(int fromfd, byte[] from, int tofd, byte[] to) throws UnixException {
+        NativeBuffer fromBuffer = NativeBuffers.asNativeBuffer(from);
+        NativeBuffer toBuffer = NativeBuffers.asNativeBuffer(to);
+        try {
+            renameat0(fromfd, fromBuffer.address(), tofd, toBuffer.address());
+        } finally {
+            toBuffer.release();
+            fromBuffer.release();
+        }
+    }
+    private static native void renameat0(int fromfd, long fromAddress, int tofd, long toAddress)
+        throws UnixException;
+
+    /**
+     * mkdir(const char* path, mode_t mode)
+     */
+    static void mkdir(UnixPath path, int mode) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            mkdir0(buffer.address(), mode);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void mkdir0(long pathAddress, int mode) throws UnixException;
+
+    /**
+     * rmdir(const char* path)
+     */
+    static void rmdir(UnixPath path) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            rmdir0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void rmdir0(long pathAddress) throws UnixException;
+
+    /**
+     * readlink(const char* path, char* buf, size_t bufsize)
+     *
+     * @return  link target
+     */
+    static byte[] readlink(UnixPath path) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            return readlink0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native byte[] readlink0(long pathAddress) throws UnixException;
+
+    /**
+     * realpath(const char* path, char* resolved_name)
+     *
+     * @return  resolved path
+     */
+    static byte[] realpath(UnixPath path) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            return realpath0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native byte[] realpath0(long pathAddress) throws UnixException;
+
+    /**
+     * symlink(const char* name1, const char* name2)
+     */
+    static void symlink(byte[] name1, UnixPath name2) throws UnixException {
+        NativeBuffer targetBuffer = NativeBuffers.asNativeBuffer(name1);
+        NativeBuffer linkBuffer = copyToNativeBuffer(name2);
+        try {
+            symlink0(targetBuffer.address(), linkBuffer.address());
+        } finally {
+            linkBuffer.release();
+            targetBuffer.release();
+        }
+    }
+    private static native void symlink0(long name1, long name2)
+        throws UnixException;
+
+    /**
+     * stat(const char* path, struct stat* buf)
+     */
+    static void stat(UnixPath path, UnixFileAttributes attrs) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            stat0(buffer.address(), attrs);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void stat0(long pathAddress, UnixFileAttributes attrs)
+        throws UnixException;
+
+    /**
+     * lstat(const char* path, struct stat* buf)
+     */
+    static void lstat(UnixPath path, UnixFileAttributes attrs) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            lstat0(buffer.address(), attrs);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void lstat0(long pathAddress, UnixFileAttributes attrs)
+        throws UnixException;
+
+    /**
+     * fstat(int filedes, struct stat* buf)
+     */
+    static native void fstat(int fd, UnixFileAttributes attrs) throws UnixException;
+
+    /**
+     * fstatat(int filedes,const char* path,  struct stat* buf, int flag)
+     */
+    static void fstatat(int dfd, byte[] path, int flag, UnixFileAttributes attrs)
+        throws UnixException
+    {
+        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+        try {
+            fstatat0(dfd, buffer.address(), flag, attrs);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void fstatat0(int dfd, long pathAddress, int flag,
+        UnixFileAttributes attrs) throws UnixException;
+
+    /**
+     * chown(const char* path, uid_t owner, gid_t group)
+     */
+    static void chown(UnixPath path, int uid, int gid) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            chown0(buffer.address(), uid, gid);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void chown0(long pathAddress, int uid, int gid)
+        throws UnixException;
+
+    /**
+     * lchown(const char* path, uid_t owner, gid_t group)
+     */
+    static void lchown(UnixPath path, int uid, int gid) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            lchown0(buffer.address(), uid, gid);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void lchown0(long pathAddress, int uid, int gid)
+        throws UnixException;
+
+    /**
+     * fchown(int filedes, uid_t owner, gid_t group)
+     */
+    static native void fchown(int fd, int uid, int gid) throws UnixException;
+
+    /**
+     * chmod(const char* path, mode_t mode)
+     */
+    static void chmod(UnixPath path, int mode) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            chmod0(buffer.address(), mode);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void chmod0(long pathAddress, int mode)
+        throws UnixException;
+
+    /**
+     * fchmod(int fildes, mode_t mode)
+     */
+    static native void fchmod(int fd, int mode) throws UnixException;
+
+    /**
+     * utimes(conar char* path, const struct timeval times[2])
+     */
+    static void utimes(UnixPath path, long times0, long times1)
+        throws UnixException
+    {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            utimes0(buffer.address(), times0, times1);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void utimes0(long pathAddress, long times0, long times1)
+        throws UnixException;
+
+    /**
+     * futimes(int fildes,, const struct timeval times[2])
+     */
+    static native void futimes(int fd, long times0, long times1) throws UnixException;
+
+    /**
+     * DIR *opendir(const char* dirname)
+     */
+    static long opendir(UnixPath path) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            return opendir0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native long opendir0(long pathAddress) throws UnixException;
+
+    /**
+     * DIR* fdopendir(int filedes)
+     */
+    static native long fdopendir(int dfd) throws UnixException;
+
+
+    /**
+     * closedir(DIR* dirp)
+     */
+    static native void closedir(long dir) throws UnixException;
+
+    /**
+     * struct dirent* readdir(DIR *dirp)
+     *
+     * @return  dirent->d_name
+     */
+    static native byte[] readdir(long dir) throws UnixException;
+
+    /**
+     * size_t read(int fildes, void* buf, size_t nbyte)
+     */
+    static native int read(int fildes, long buf, int nbyte) throws UnixException;
+
+    /**
+     * size_t writeint fildes, void* buf, size_t nbyte)
+     */
+    static native int write(int fildes, long buf, int nbyte) throws UnixException;
+
+    /**
+     * access(const char* path, int amode);
+     */
+    static void access(UnixPath path, int amode) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            access0(buffer.address(), amode);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void access0(long pathAddress, int amode) throws UnixException;
+
+    /**
+     * struct passwd *getpwuid(uid_t uid);
+     *
+     * @return  passwd->pw_name
+     */
+    static native byte[] getpwuid(int uid) throws UnixException;
+
+    /**
+     * struct group *getgrgid(gid_t gid);
+     *
+     * @return  group->gr_name
+     */
+    static native byte[] getgrgid(int gid) throws UnixException;
+
+    /**
+     * struct passwd *getpwnam(const char *name);
+     *
+     * @return  passwd->pw_uid
+     */
+    static int getpwnam(String name) throws UnixException {
+        NativeBuffer buffer = NativeBuffers.asNativeBuffer(name.getBytes());
+        try {
+            return getpwnam0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native int getpwnam0(long nameAddress) throws UnixException;
+
+    /**
+     * struct group *getgrnam(const char *name);
+     *
+     * @return  group->gr_name
+     */
+    static int getgrnam(String name) throws UnixException {
+        NativeBuffer buffer = NativeBuffers.asNativeBuffer(name.getBytes());
+        try {
+            return getgrnam0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native int getgrnam0(long nameAddress) throws UnixException;
+
+    /**
+     * int getextmntent(FILE *fp, struct extmnttab *mp, int len);
+     */
+    static native int getextmntent(long fp, UnixMountEntry entry) throws UnixException;
+
+    /**
+     * statvfs(const char* path, struct statvfs *buf)
+     */
+    static void statvfs(UnixPath path, UnixFileStoreAttributes attrs)
+        throws UnixException
+    {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            statvfs0(buffer.address(), attrs);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void statvfs0(long pathAddress, UnixFileStoreAttributes attrs)
+        throws UnixException;
+
+    /**
+     * long int pathconf(const char *path, int name);
+     */
+    static long pathconf(UnixPath path, int name) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
+        try {
+            return pathconf0(buffer.address(), name);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native long pathconf0(long pathAddress, int name)
+        throws UnixException;
+
+    /**
+     * long fpathconf(int fildes, int name);
+     */
+    static native long fpathconf(int filedes, int name) throws UnixException;
+
+    /**
+     * char* strerror(int errnum)
+     */
+    static native byte[] strerror(int errnum);
+
+    // initialize field IDs
+    private static native void initIDs();
+
+    static {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                System.loadLibrary("nio");
+                return null;
+        }});
+        initIDs();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,1228 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.nio.file.spi.AbstractPath;
+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.*;
+
+/**
+ * Solaris/Linux implementation of java.nio.file.Path
+ */
+
+class UnixPath
+    extends AbstractPath
+{
+    private static ThreadLocal<SoftReference<CharsetEncoder>> encoder =
+        new ThreadLocal<SoftReference<CharsetEncoder>>();
+
+    // FIXME - eliminate this reference to reduce space
+    private final UnixFileSystem fs;
+
+    // internal representation
+    private final byte[] path;
+
+    // String representation (created lazily)
+    private volatile String stringValue;
+
+    // cached hashcode (created lazily, no need to be volatile)
+    private int hash;
+
+    // array of offsets of elements in path (created lazily)
+    private volatile int[] offsets;
+
+    // file permissions (created lazily)
+    private volatile FilePermission[] perms;
+
+    UnixPath(UnixFileSystem fs, byte[] path) {
+        this.fs = fs;
+        this.path = path;
+    }
+
+    UnixPath(UnixFileSystem fs, String input) {
+        // removes redundant slashes and checks for invalid characters
+        this(fs, encode(normalizeAndCheck(input)));
+    }
+
+    // package-private
+    // 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);
+            if (c == '\u0000')
+                throw new InvalidPathException(input, "Nul character not allowed");
+            if ((c == '/') && (prevChar == '/'))
+                return normalize(input, n, i - 1);
+            prevChar = c;
+        }
+        if (prevChar == '/')
+            return normalize(input, n, n - 1);
+        return input;
+    }
+
+    private static String normalize(String input, int len, int off) {
+        if (len == 0)
+            return input;
+        int n = len;
+        while ((n > 0) && (input.charAt(n - 1) == '/')) n--;
+        if (n == 0)
+            return "/";
+        StringBuilder sb = new StringBuilder(input.length());
+        if (off > 0)
+            sb.append(input.substring(0, off));
+        char prevChar = 0;
+        for (int i=off; i < n; i++) {
+            char c = input.charAt(i);
+            if ((c == '/') && (prevChar == '/'))
+                continue;
+            sb.append(c);
+            prevChar = c;
+        }
+        return sb.toString();
+    }
+
+    // encodes the given path-string into a sequence of bytes
+    private static byte[] encode(String input) {
+        SoftReference<CharsetEncoder> ref = encoder.get();
+        CharsetEncoder ce = (ref != null) ? ref.get() : null;
+        if (ce == null) {
+            ce = Charset.defaultCharset().newEncoder()
+                .onMalformedInput(CodingErrorAction.REPORT)
+                .onUnmappableCharacter(CodingErrorAction.REPORT);
+            encoder.set(new SoftReference<CharsetEncoder>(ce));
+        }
+
+        char[] ca = input.toCharArray();
+
+        // size output buffer for worse-case size
+        byte[] ba = new byte[(int)(ca.length * (double)ce.maxBytesPerChar())];
+
+        // encode
+        ByteBuffer bb = ByteBuffer.wrap(ba);
+        CharBuffer cb = CharBuffer.wrap(ca);
+        ce.reset();
+        CoderResult cr = ce.encode(cb, bb, true);
+        boolean error;
+        if (!cr.isUnderflow()) {
+            error = true;
+        } else {
+            cr = ce.flush(bb);
+            error = !cr.isUnderflow();
+        }
+        if (error) {
+            throw new InvalidPathException(input,
+                "Malformed input or input contains unmappable chacraters");
+        }
+
+        // trim result to actual length if required
+        int len = bb.position();
+        if (len != ba.length)
+            ba = Arrays.copyOf(ba, len);
+
+        return ba;
+    }
+
+    // package-private
+    byte[] asByteArray() {
+        return path;
+    }
+
+    // use this path when making system/library calls
+    byte[] getByteArrayForSysCalls() {
+        // resolve against default directory if required (chdir allowed or
+        // file system default directory is not working directory)
+        if (getFileSystem().needToResolveAgainstDefaultDirectory()) {
+            return resolve(getFileSystem().defaultDirectory(), path);
+        } else {
+            return path;
+        }
+    }
+
+    // use this message when throwing exceptions
+    String getPathForExecptionMessage() {
+        return toString();
+    }
+
+    // use this path for permission checks
+    String getPathForPermissionCheck() {
+        if (getFileSystem().needToResolveAgainstDefaultDirectory()) {
+            return new String(getByteArrayForSysCalls());
+        } else {
+            return toString();
+        }
+    }
+
+    // Checks that the given file is a UnixPath
+    private UnixPath checkPath(FileRef obj) {
+        if (obj == null)
+            throw new NullPointerException();
+        if (!(obj instanceof UnixPath))
+            throw new ProviderMismatchException();
+        return (UnixPath)obj;
+    }
+
+    // create offset list if not already created
+    private void initOffsets() {
+        if (offsets == null) {
+            int count, index;
+
+            // count names
+            count = 0;
+            index = 0;
+            while (index < path.length) {
+                byte c = path[index++];
+                if (c != '/') {
+                    count++;
+                    while (index < path.length && path[index] != '/')
+                        index++;
+                }
+            }
+
+            // populate offsets
+            int[] result = new int[count];
+            count = 0;
+            index = 0;
+            while (index < path.length) {
+                byte c = path[index];
+                if (c == '/') {
+                    index++;
+                } else {
+                    result[count++] = index++;
+                    while (index < path.length && path[index] != '/')
+                        index++;
+                }
+            }
+            synchronized (this) {
+                if (offsets == null)
+                    offsets = result;
+            }
+        }
+    }
+
+    @Override
+    public UnixFileSystem getFileSystem() {
+        return fs;
+    }
+
+    @Override
+    public UnixPath getRoot() {
+        if (path[0] == '/') {
+            return getFileSystem().rootDirectory();
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public UnixPath getName() {
+        initOffsets();
+
+        int count = offsets.length;
+        if (count == 0)
+            return null;  // no elements so no name
+
+        if (count == 1 && path[0] != '/')
+            return this;
+
+        int lastOffset = offsets[count-1];
+        int len = path.length - lastOffset;
+        byte[] result = new byte[len];
+        System.arraycopy(path, lastOffset, result, 0, len);
+        return new UnixPath(getFileSystem(), result);
+    }
+
+    @Override
+    public UnixPath getParent() {
+        initOffsets();
+
+        int count = offsets.length;
+        if (count == 0) {
+            // no elements so no parent
+            return null;
+        }
+        int len = offsets[count-1] - 1;
+        if (len <= 0) {
+            // parent is root only (may be null)
+            return getRoot();
+        }
+        byte[] result = new byte[len];
+        System.arraycopy(path, 0, result, 0, len);
+        return new UnixPath(getFileSystem(), result);
+    }
+
+    @Override
+    public int getNameCount() {
+        initOffsets();
+        return offsets.length;
+    }
+
+    @Override
+    public UnixPath getName(int index) {
+        initOffsets();
+        if (index < 0)
+            throw new IllegalArgumentException();
+        if (index >= offsets.length)
+            throw new IllegalArgumentException();
+
+        int begin = offsets[index];
+        int len;
+        if (index == (offsets.length-1)) {
+            len = path.length - begin;
+        } else {
+            len = offsets[index+1] - begin - 1;
+        }
+
+        // construct result
+        byte[] result = new byte[len];
+        System.arraycopy(path, begin, result, 0, len);
+        return new UnixPath(getFileSystem(), result);
+    }
+
+    @Override
+    public UnixPath subpath(int beginIndex, int endIndex) {
+        initOffsets();
+
+        if (beginIndex < 0)
+            throw new IllegalArgumentException();
+        if (beginIndex >= offsets.length)
+            throw new IllegalArgumentException();
+        if (endIndex > offsets.length)
+            throw new IllegalArgumentException();
+        if (beginIndex >= endIndex) {
+            throw new IllegalArgumentException();
+        }
+
+        // starting offset and length
+        int begin = offsets[beginIndex];
+        int len;
+        if (endIndex == offsets.length) {
+            len = path.length - begin;
+        } else {
+            len = offsets[endIndex] - begin - 1;
+        }
+
+        // construct result
+        byte[] result = new byte[len];
+        System.arraycopy(path, begin, result, 0, len);
+        return new UnixPath(getFileSystem(), result);
+    }
+
+    @Override
+    public boolean isAbsolute() {
+        return (path[0] == '/');
+    }
+
+    // Resolve child against given base
+    private static byte[] resolve(byte[] base, byte[] child) {
+        if (child[0] == '/')
+            return child;
+        byte[] result;
+        if (base.length == 1 && base[0] == '/') {
+            result = new byte[child.length + 1];
+            result[0] = '/';
+            System.arraycopy(child, 0, result, 1, child.length);
+        } else {
+            result = new byte[base.length + 1 + child.length];
+            System.arraycopy(base, 0, result, 0, base.length);
+            result[base.length] = '/';
+            System.arraycopy(child, 0, result,  base.length+1, child.length);
+        }
+        return result;
+    }
+
+    @Override
+    public UnixPath resolve(Path obj) {
+        if (obj == null)
+            return this;
+        byte[] other = checkPath(obj).path;
+        if (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);
+        if (other.equals(this))
+            return null;
+
+        // can only relativize paths of the same type
+        if (this.isAbsolute() != other.isAbsolute())
+            throw new IllegalArgumentException("'other' is different type of Path");
+
+        int bn = this.getNameCount();
+        int cn = other.getNameCount();
+
+        // skip matching names
+        int n = (bn > cn) ? cn : bn;
+        int i = 0;
+        while (i < n) {
+            if (!this.getName(i).equals(other.getName(i)))
+                break;
+            i++;
+        }
+
+        int dotdots = bn - i;
+        if (i < cn) {
+            // remaining name components in other
+            UnixPath remainder = other.subpath(i, cn);
+            if (dotdots == 0)
+                return remainder;
+
+            // 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];
+            int pos = 0;
+            while (dotdots > 0) {
+                result[pos++] = (byte)'.';
+                result[pos++] = (byte)'.';
+                result[pos++] = (byte)'/';
+                dotdots--;
+            }
+            System.arraycopy(remainder.path, 0, result, pos, remainder.path.length);
+            return new UnixPath(getFileSystem(), result);
+        } else {
+            // no remaining names in other so result is simply a sequence of ".."
+            byte[] result = new byte[dotdots*3 - 1];
+            int pos = 0;
+            while (dotdots > 0) {
+                result[pos++] = (byte)'.';
+                result[pos++] = (byte)'.';
+                // no tailing slash at the end
+                if (dotdots > 1)
+                    result[pos++] = (byte)'/';
+                dotdots--;
+            }
+            return new UnixPath(getFileSystem(), result);
+        }
+    }
+
+    @Override
+    public Path normalize() {
+        final int count = getNameCount();
+        if (count == 0)
+            return this;
+
+        boolean[] ignore = new boolean[count];      // true => ignore name
+        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] == '/';
+
+        // first pass:
+        //   1. compute length of names
+        //   2. mark all occurences of "." to ignore
+        //   3. and look for any occurences of ".."
+        for (int i=0; i<count; i++) {
+            int begin = offsets[i];
+            int len;
+            if (i == (offsets.length-1)) {
+                len = path.length - begin;
+            } else {
+                len = offsets[i+1] - begin - 1;
+            }
+            size[i] = len;
+
+            if (path[begin] == '.') {
+                if (len == 1) {
+                    ignore[i] = true;  // ignore  "."
+                    remaining--;
+                }
+                else {
+                    if (path[begin+1] == '.')   // ".." found
+                        hasDotDot = true;
+                }
+            }
+        }
+
+        // multiple passes to eliminate all occurences of name/..
+        if (hasDotDot) {
+            int prevRemaining;
+            do {
+                prevRemaining = remaining;
+                int prevName = -1;
+                for (int i=0; i<count; i++) {
+                    if (ignore[i])
+                        continue;
+
+                    // not a ".."
+                    if (size[i] != 2) {
+                        prevName = i;
+                        continue;
+                    }
+
+                    int begin = offsets[i];
+                    if (path[begin] != '.' || path[begin+1] != '.') {
+                        prevName = i;
+                        continue;
+                    }
+
+                    // ".." found
+                    if (prevName >= 0) {
+                        // name/<ignored>/.. found so mark name and ".." to be
+                        // ignored
+                        ignore[prevName] = true;
+                        ignore[i] = true;
+                        remaining = remaining - 2;
+                        prevName = -1;
+                    } else {
+                        // Case: /<ignored>/.. so mark ".." as ignored
+                        if (isAbsolute) {
+                            boolean hasPrevious = false;
+                            for (int j=0; j<i; j++) {
+                                if (!ignore[j]) {
+                                    hasPrevious = true;
+                                    break;
+                                }
+                            }
+                            if (!hasPrevious) {
+                                // all proceeding names are ignored
+                                ignore[i] = true;
+                                remaining--;
+                            }
+                        }
+                    }
+                }
+            } while (prevRemaining > remaining);
+        }
+
+        // no redundant names
+        if (remaining == count)
+            return this;
+
+        // corner case - all names removed
+        if (remaining == 0) {
+            return isAbsolute ? getFileSystem().rootDirectory() : null;
+        }
+
+        // compute length of result
+        int len = remaining - 1;
+        if (isAbsolute)
+            len++;
+
+        for (int i=0; i<count; i++) {
+            if (!ignore[i])
+                len += size[i];
+        }
+        byte[] result = new byte[len];
+
+        // copy names into result
+        int pos = 0;
+        if (isAbsolute)
+            result[pos++] = '/';
+        for (int i=0; i<count; i++) {
+            if (!ignore[i]) {
+                System.arraycopy(path, offsets[i], result, pos, size[i]);
+                pos += size[i];
+                if (--remaining > 0) {
+                    result[pos++] = '/';
+                }
+            }
+        }
+        return new UnixPath(getFileSystem(), result);
+    }
+
+    @Override
+    public boolean startsWith(Path other) {
+        UnixPath that = checkPath(other);
+
+        // other path is longer
+        if (that.path.length > path.length)
+            return false;
+
+        int thisOffsetCount = getNameCount();
+        int thatOffsetCount = that.getNameCount();
+
+        // other path has no name elements
+        if (thatOffsetCount == 0 && this.isAbsolute())
+            return true;
+
+        // given path has more elements that this path
+        if (thatOffsetCount > thisOffsetCount)
+            return false;
+
+        // same number of elements so must be exact match
+        if ((thatOffsetCount == thisOffsetCount) &&
+            (path.length != that.path.length)) {
+            return false;
+        }
+
+        // check offsets of elements match
+        for (int i=0; i<thatOffsetCount; i++) {
+            Integer o1 = offsets[i];
+            Integer o2 = that.offsets[i];
+            if (!o1.equals(o2))
+                return false;
+        }
+
+        // offsets match so need to compare bytes
+        int i=0;
+        while (i < that.path.length) {
+            if (this.path[i] != that.path[i])
+                return false;
+            i++;
+        }
+
+        // final check that match is on name boundary
+        if (i < path.length && this.path[i] != '/')
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public boolean endsWith(Path other) {
+        UnixPath that = checkPath(other);
+
+        // other path is longer
+        if (that.path.length > path.length)
+            return false;
+
+        // other path is absolute so this path must be absolute
+        if (that.isAbsolute() && !this.isAbsolute())
+            return false;
+
+        int thisOffsetCount = getNameCount();
+        int thatOffsetCount = that.getNameCount();
+
+        // given path has more elements that this path
+        if (thatOffsetCount > thisOffsetCount) {
+            return false;
+        } else {
+            // same number of elements
+            if (thatOffsetCount == thisOffsetCount) {
+                if (thisOffsetCount == 0)
+                    return true;
+                int expectedLen = path.length;
+                if (this.isAbsolute() && !that.isAbsolute())
+                    expectedLen--;
+                if (that.path.length != expectedLen)
+                    return false;
+            } else {
+                // this path has more elements so given path must be relative
+                if (that.isAbsolute())
+                    return false;
+            }
+        }
+
+        // compare bytes
+        int thisPos = offsets[thisOffsetCount - thatOffsetCount];
+        int thatPos = that.offsets[0];
+        while (thatPos < that.path.length) {
+            if (this.path[thisPos++] != that.path[thatPos++])
+                return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int compareTo(Path other) {
+        int len1 = path.length;
+        int len2 = ((UnixPath) other).path.length;
+
+        int n = Math.min(len1, len2);
+        byte v1[] = path;
+        byte v2[] = ((UnixPath) other).path;
+
+        int k = 0;
+        while (k < n) {
+            int c1 = v1[k] & 0xff;
+            int c2 = v2[k] & 0xff;
+            if (c1 != c2) {
+                return c1 - c2;
+            }
+            k++;
+        }
+        return len1 - len2;
+    }
+
+    @Override
+    public boolean equals(Object ob) {
+        if ((ob != null) && (ob instanceof UnixPath)) {
+            return compareTo((Path)ob) == 0;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        // OK if two or more threads compute hash
+        int h = hash;
+        if (h == 0) {
+            for (int i = 0; i< path.length; i++) {
+                h = 31*h + (path[i] & 0xff);
+            }
+            hash = h;
+        }
+        return h;
+    }
+
+    @Override
+    public String toString() {
+        // OK if two or more threads create a String
+        if (stringValue == null)
+            stringValue = new String(path);     // platform encoding
+        return stringValue;
+    }
+
+    @Override
+    public Iterator<Path> iterator() {
+        initOffsets();
+        return new Iterator<Path>() {
+            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
+    int openForAttributeAccess(boolean followLinks) throws IOException {
+        int flags = O_RDONLY;
+        if (!followLinks)
+            flags |= O_NOFOLLOW;
+        try {
+            return open(this, flags, 0);
+        } catch (UnixException x) {
+            // HACK: EINVAL instead of ELOOP on Solaris 10 prior to u4 (see 6460380)
+            if (getFileSystem().isSolaris() && x.errno() == EINVAL)
+                x.setError(ELOOP);
+
+            if (x.errno() == ELOOP)
+                throw new FileSystemException(getPathForExecptionMessage(), null,
+                    x.getMessage() + " or unable to access attributes of symbolic link");
+
+            x.rethrowAsIOException(this);
+            return -1; // keep compile happy
+        }
+    }
+
+    // create file permissions used for read and write checks
+    private void checkReadOrWrite(boolean checkRead) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null)
+            return;
+        if (perms == null) {
+            synchronized (this) {
+                if (perms == null) {
+                    FilePermission[] p = new FilePermission[2];
+                    String pathForPermCheck = getPathForPermissionCheck();
+                    p[0] = new FilePermission(pathForPermCheck,
+                        SecurityConstants.FILE_READ_ACTION);
+                    p[1] = new FilePermission(pathForPermCheck,
+                        SecurityConstants.FILE_WRITE_ACTION);
+                    perms = p;
+                }
+            }
+        }
+        if (checkRead) {
+            sm.checkPermission(perms[0]);
+        } else {
+            sm.checkPermission(perms[1]);
+        }
+    }
+
+    void checkRead() {
+        checkReadOrWrite(true);
+    }
+
+    void checkWrite() {
+        checkReadOrWrite(false);
+    }
+
+    void checkDelete() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            // permission not cached
+            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
+    public void delete(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<Path> newDirectoryStream(DirectoryStream.Filter<? super Path> filter)
+        throws IOException
+    {
+        if (filter == null)
+            throw new NullPointerException();
+        checkRead();
+
+        // can't return SecureDirectoryStream on older kernels.
+        if (!getFileSystem().supportsSecureDirectoryStreams()) {
+            try {
+                long ptr = opendir(this);
+                return new UnixDirectoryStream(this, ptr, filter);
+            } catch (UnixException x) {
+                if (x.errno() == UnixConstants.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 extends FileAttributeView> V
+        getFileAttributeView(Class<V> type, LinkOption... options)
+    {
+        FileAttributeView view = getFileSystem()
+            .newFileAttributeView(type, this, options);
+        if (view == null)
+            return null;
+        return (V) view;
+    }
+
+    @Override
+    public FileAttributeView 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 InputStream newInputStream()throws IOException {
+        try {
+            Set<OpenOption> options = Collections.emptySet();
+            FileChannel fc = UnixChannelFactory.newFileChannel(this, options, 0);
+            return Channels.newInputStream(fc);
+        } catch (UnixException x) {
+            x.rethrowAsIOException(this);
+            return null;  // keep compiler happy
+        }
+    }
+
+    @Override
+    public SeekableByteChannel newByteChannel(Set<? extends OpenOption> 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 OutputStream newOutputStream(Set<? extends OpenOption> options,
+                                        FileAttribute<?>... attrs)
+        throws IOException
+    {
+        // need to copy options to add WRITE
+        Set<OpenOption> opts = new HashSet<OpenOption>(options);
+        if (opts.contains(StandardOpenOption.READ))
+            throw new IllegalArgumentException("READ not allowed");
+        opts.add(StandardOpenOption.WRITE);
+
+        int mode = UnixFileModeAttribute
+            .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
+        try {
+            FileChannel fc = UnixChannelFactory.newFileChannel(this, opts, mode);
+            return Channels.newOutputStream(fc);
+        } catch (UnixException x) {
+            x.rethrowAsIOException(this);
+            return null;  // keep compiler happy
+        }
+    }
+
+    @Override
+    public boolean isSameFile(FileRef 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()) {
+            return this;
+        }
+        // The path is relative so need to resolve against default directory,
+        // taking care not to reveal the user.dir
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPropertyAccess("user.dir");
+        }
+        return new UnixPath(getFileSystem(),
+            resolve(getFileSystem().defaultDirectory(), path));
+    }
+
+    @Override
+    public UnixPath toRealPath(boolean resolveLinks) throws IOException {
+        checkRead();
+
+        UnixPath absolute = toAbsolutePath();
+
+        // if resolveLinks is true then use realpath
+        if (resolveLinks) {
+            try {
+                byte[] rp = realpath(absolute);
+                return new UnixPath(getFileSystem(), rp);
+            } catch (UnixException x) {
+                x.rethrowAsIOException(this);
+            }
+        }
+
+        // if resolveLinks is false then eliminate "." and also ".."
+        // where the previous element is not a link.
+        UnixPath root = getFileSystem().rootDirectory();
+        UnixPath result = root;
+        for (int i=0; i<absolute.getNameCount(); i++) {
+            UnixPath element = absolute.getName(i);
+
+            // eliminate "."
+            if ((element.asByteArray().length == 1) && (element.asByteArray()[0] == '.'))
+                continue;
+
+            // cannot eliminate ".." if previous element is a link
+            if ((element.asByteArray().length == 2) && (element.asByteArray()[0] == '.') &&
+                (element.asByteArray()[1] == '.'))
+            {
+                UnixFileAttributes attrs = null;
+                try {
+                    attrs = UnixFileAttributes.get(result, false);
+                } catch (UnixException x) {
+                    x.rethrowAsIOException(result);
+                }
+                if (!attrs.isSymbolicLink()) {
+                    result = result.getParent();
+                    if (result == null) {
+                        result = root;
+                    }
+                    continue;
+                }
+            }
+            result = result.resolve(element);
+        }
+
+        // finally check that file exists
+        try {
+            UnixFileAttributes.get(result, true);
+        } catch (UnixException x) {
+            x.rethrowAsIOException(result);
+        }
+        return result;
+    }
+
+    @Override
+    public boolean isHidden() {
+        checkRead();
+        UnixPath name = getName();
+        if (name == null)
+            return false;
+        return (name.asByteArray()[0] == '.');
+    }
+
+    @Override
+    public URI toUri() {
+        return UnixUriUtils.toUri(this);
+    }
+
+    @Override
+    public WatchKey register(WatchService watcher,
+                             WatchEvent.Kind<?>[] events,
+                             WatchEvent.Modifier... modifiers)
+        throws IOException
+    {
+        if (watcher == null)
+            throw new NullPointerException();
+        if (!(watcher instanceof AbstractWatchService))
+            throw new ProviderMismatchException();
+        checkRead();
+        return ((AbstractWatchService)watcher).register(this, events, modifiers);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixSecureDirectoryStream.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,643 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.nio.channels.SeekableByteChannel;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.io.IOException;
+
+import static sun.nio.fs.UnixNativeDispatcher.*;
+import static sun.nio.fs.UnixConstants.*;
+
+/**
+ * Unix implementation of SecureDirectoryStream.
+ */
+
+class UnixSecureDirectoryStream
+    extends SecureDirectoryStream
+{
+    private final UnixDirectoryStream ds;
+    private final int dfd;
+
+    UnixSecureDirectoryStream(UnixPath dir,
+                              long dp,
+                              int dfd,
+                              DirectoryStream.Filter<? super Path> filter)
+    {
+        this.ds = new UnixDirectoryStream(dir, dp, filter);
+        this.dfd = dfd;
+    }
+
+    @Override
+    public void close()
+        throws IOException
+    {
+        ds.writeLock().lock();
+        try {
+            if (ds.closeImpl()) {
+                UnixNativeDispatcher.close(dfd);
+            }
+        } finally {
+            ds.writeLock().unlock();
+        }
+    }
+
+    @Override
+    public Iterator<Path> iterator() {
+        return ds.iterator(this);
+    }
+
+    private UnixPath getName(Path obj) {
+        if (obj == null)
+            throw new NullPointerException();
+        if (!(obj instanceof UnixPath))
+            throw new ProviderMismatchException();
+        return (UnixPath)obj;
+    }
+
+    /**
+     * Opens sub-directory in this directory
+     */
+    @Override
+    public SecureDirectoryStream newDirectoryStream(Path obj,
+                                                    boolean followLinks,
+                                                    DirectoryStream.Filter<? super Path> filter)
+        throws IOException
+    {
+        UnixPath file = getName(obj);
+        UnixPath child = ds.directory().resolve(file);
+
+        // permission check using name resolved against original path of directory
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            child.checkRead();
+        }
+
+        ds.readLock().lock();
+        try {
+            if (!ds.isOpen())
+                throw new ClosedDirectoryStreamException();
+
+            // open directory and create new secure directory stream
+            int newdfd1 = -1;
+            int newdfd2 = -1;
+            long ptr = 0L;
+            try {
+                int flags = O_RDONLY;
+                if (!followLinks)
+                    flags |= O_NOFOLLOW;
+                newdfd1 = openat(dfd, file.asByteArray(), flags , 0);
+                newdfd2 = dup(newdfd1);
+                ptr = fdopendir(newdfd1);
+            } catch (UnixException x) {
+                if (newdfd1 != -1)
+                    UnixNativeDispatcher.close(newdfd1);
+                if (newdfd2 != -1)
+                    UnixNativeDispatcher.close(newdfd2);
+                if (x.errno() == UnixConstants.ENOTDIR)
+                    throw new NotDirectoryException(file.toString());
+                x.rethrowAsIOException(file);
+            }
+            return new UnixSecureDirectoryStream(child, ptr, newdfd2, filter);
+        } finally {
+            ds.readLock().unlock();
+        }
+    }
+
+    /**
+     * Opens file in this directory
+     */
+    @Override
+    public SeekableByteChannel newByteChannel(Path obj,
+                                              Set<? extends OpenOption> options,
+                                              FileAttribute<?>... attrs)
+        throws IOException
+    {
+        UnixPath file = getName(obj);
+
+        int mode = UnixFileModeAttribute
+            .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
+
+        // path for permission check
+        String pathToCheck = ds.directory().resolve(file).getPathForPermissionCheck();
+
+        ds.readLock().lock();
+        try {
+            if (!ds.isOpen())
+                throw new ClosedDirectoryStreamException();
+            try {
+                return UnixChannelFactory.newFileChannel(dfd, file, pathToCheck, options, mode);
+            } catch (UnixException x) {
+                x.rethrowAsIOException(file);
+                return null; // keep compiler happy
+            }
+        } finally {
+            ds.readLock().unlock();
+        }
+    }
+
+    /**
+     * Deletes file/directory in this directory. Works in a race-free manner
+     * when invoked with flags.
+     */
+    void implDelete(Path obj, boolean haveFlags, int flags)
+        throws IOException
+    {
+        UnixPath file = getName(obj);
+
+        // permission check using name resolved against original path of directory
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            ds.directory().resolve(file).checkDelete();
+        }
+
+        ds.readLock().lock();
+        try {
+            if (!ds.isOpen())
+                throw new ClosedDirectoryStreamException();
+
+            if (!haveFlags) {
+                // need file attribute to know if file is directory. This creates
+                // a race in that the file may be replaced by a directory or a
+                // directory replaced by a file between the time we query the
+                // file type and unlink it.
+                UnixFileAttributes attrs = null;
+                try {
+                    attrs = UnixFileAttributes.get(dfd, file, false);
+                } catch (UnixException x) {
+                    x.rethrowAsIOException(file);
+                }
+                flags = (attrs.isDirectory()) ? AT_REMOVEDIR : 0;
+            }
+
+            try {
+                unlinkat(dfd, file.asByteArray(), flags);
+            } catch (UnixException x) {
+                if ((flags & AT_REMOVEDIR) != 0) {
+                    if (x.errno() == EEXIST || x.errno() == ENOTEMPTY) {
+                        throw new DirectoryNotEmptyException(null);
+                    }
+                }
+                x.rethrowAsIOException(file);
+            }
+        } finally {
+            ds.readLock().unlock();
+        }
+    }
+
+    @Override
+    public void deleteFile(Path file) throws IOException {
+        implDelete(file, true, 0);
+    }
+
+    @Override
+    public void deleteDirectory(Path dir) throws IOException {
+        implDelete(dir, true, AT_REMOVEDIR);
+    }
+
+    /**
+     * Rename/move file in this directory to another (open) directory
+     */
+    @Override
+    public void move(Path fromObj, SecureDirectoryStream dir, Path toObj)
+        throws IOException
+    {
+        UnixPath from = getName(fromObj);
+        UnixPath to = getName(toObj);
+        if (dir == null)
+            throw new NullPointerException();
+        if (!(dir instanceof UnixSecureDirectoryStream))
+            throw new ProviderMismatchException();
+        UnixSecureDirectoryStream that = (UnixSecureDirectoryStream)dir;
+
+        // permission check
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            this.ds.directory().resolve(from).checkWrite();
+            that.ds.directory().resolve(to).checkWrite();
+        }
+
+        // lock ordering doesn't matter
+        this.ds.readLock().lock();
+        try {
+            that.ds.readLock().lock();
+            try {
+                if (!this.ds.isOpen() || !that.ds.isOpen())
+                    throw new ClosedDirectoryStreamException();
+                try {
+                    renameat(this.dfd, from.asByteArray(), that.dfd, to.asByteArray());
+                } catch (UnixException x) {
+                    if (x.errno() == EXDEV) {
+                        throw new AtomicMoveNotSupportedException(
+                            from.toString(), to.toString(), x.errorString());
+                    }
+                    x.rethrowAsIOException(from, to);
+                }
+            } finally {
+                that.ds.readLock().unlock();
+            }
+        } finally {
+            this.ds.readLock().unlock();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private <V extends FileAttributeView> V getFileAttributeViewImpl(UnixPath file,
+                                                                     Class<V> type,
+                                                                     boolean followLinks)
+    {
+        if (type == null)
+            throw new NullPointerException();
+        Class<?> c = type;
+        if (c == BasicFileAttributeView.class) {
+            return (V) new BasicFileAttributeViewImpl(file, followLinks);
+        }
+        if (c == PosixFileAttributeView.class || c == FileOwnerAttributeView.class) {
+            return (V) new PosixFileAttributeViewImpl(file, followLinks);
+        }
+        // TBD - should also support AclFileAttributeView
+        return (V) null;
+    }
+
+    /**
+     * Returns file attribute view bound to this directory
+     */
+    @Override
+    public <V extends FileAttributeView> V getFileAttributeView(Class<V> type) {
+        return getFileAttributeViewImpl(null, type, false);
+    }
+
+    /**
+     * Returns file attribute view bound to dfd/filename.
+     */
+    @Override
+    public <V extends FileAttributeView> V getFileAttributeView(Path obj,
+                                                                Class<V> type,
+                                                                LinkOption... options)
+    {
+        UnixPath file = getName(obj);
+        boolean followLinks = file.getFileSystem().followLinks(options);
+        return getFileAttributeViewImpl(file, type, followLinks);
+    }
+
+    /**
+     * A BasicFileAttributeView implementation that using a dfd/name pair.
+     */
+    private class BasicFileAttributeViewImpl
+        extends AbstractBasicFileAttributeView
+    {
+        final UnixPath file;
+        final boolean followLinks;
+
+        // set to true when binding to another object
+        volatile boolean forwarding;
+
+        BasicFileAttributeViewImpl(UnixPath file, boolean followLinks)
+        {
+            this.file = file;
+            this.followLinks = followLinks;
+        }
+
+        int open() throws IOException {
+            int oflags = O_RDONLY;
+            if (!followLinks)
+                oflags |= O_NOFOLLOW;
+            try {
+                return openat(dfd, file.asByteArray(), oflags, 0);
+            } catch (UnixException x) {
+                x.rethrowAsIOException(file);
+                return -1; // keep compiler happy
+            }
+        }
+
+        private void checkWriteAccess() {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                ds.directory().resolve(file).checkWrite();
+            }
+        }
+
+        @Override
+        public String name() {
+            return "basic";
+        }
+
+        @Override
+        public BasicFileAttributes readAttributes() throws IOException {
+            ds.readLock().lock();
+            try {
+                if (!ds.isOpen())
+                    throw new ClosedDirectoryStreamException();
+
+                SecurityManager sm = System.getSecurityManager();
+                if (sm != null) {
+                    if (file == null) {
+                        ds.directory().checkRead();
+                    } else {
+                        ds.directory().resolve(file).checkRead();
+                    }
+                }
+                try {
+                     UnixFileAttributes attrs = (file == null) ?
+                         UnixFileAttributes.get(dfd) :
+                         UnixFileAttributes.get(dfd, file, followLinks);
+
+                     // SECURITY: must return as BasicFileAttribute
+                     return attrs.asBasicFileAttributes();
+                } catch (UnixException x) {
+                    x.rethrowAsIOException(file);
+                    return null;    // keep compiler happy
+                }
+            } finally {
+                ds.readLock().unlock();
+            }
+        }
+
+        @Override
+        public void setTimes(Long lastModifiedTime,
+                             Long lastAccessTime,
+                             Long createTime, // ignore
+                             TimeUnit unit)
+            throws IOException
+        {
+            // no effect
+            if (lastModifiedTime == null && lastAccessTime == null) {
+                return;
+            }
+
+            checkWriteAccess();
+
+            ds.readLock().lock();
+            try {
+                if (!ds.isOpen())
+                    throw new ClosedDirectoryStreamException();
+
+                int fd = (file == null) ? dfd : open();
+                try {
+                    UnixFileAttributes attrs = null;
+
+                    // if not changing both attributes then need existing attributes
+                    if (lastModifiedTime == null || lastAccessTime == null) {
+                        try {
+                            attrs = UnixFileAttributes.get(fd);
+                        } catch (UnixException x) {
+                            x.rethrowAsIOException(file);
+                        }
+                    }
+
+                    // modified time = existing, now, or new value
+                    long modTime;
+                    if (lastModifiedTime == null) {
+                        modTime = attrs.lastModifiedTime();
+                    } else {
+                        if (lastModifiedTime >= 0L) {
+                            modTime = TimeUnit.MILLISECONDS.convert(lastModifiedTime, unit);
+                        } else {
+                            if (lastModifiedTime != -1L)
+                                throw new IllegalArgumentException();
+                            modTime = System.currentTimeMillis();
+                        }
+                    }
+
+                    // access time = existing, now, or new value
+                    long accTime;
+                    if (lastAccessTime == null) {
+                        accTime = attrs.lastAccessTime();
+                    } else {
+                        if (lastAccessTime >= 0L) {
+                            accTime = TimeUnit.MILLISECONDS.convert(lastAccessTime, unit);
+                        } else {
+                            if (lastAccessTime != -1L)
+                                throw new IllegalArgumentException();
+                            accTime = System.currentTimeMillis();
+                        }
+                    }
+
+                    try {
+                        futimes(fd, accTime, modTime);
+                    } catch (UnixException x) {
+                        x.rethrowAsIOException(file);
+                    }
+                } finally {
+                    if (file != null)
+                        UnixNativeDispatcher.close(fd);
+                }
+            } finally {
+                ds.readLock().unlock();
+            }
+        }
+    }
+
+    /**
+     * A PosixFileAttributeView implementation that using a dfd/name pair.
+     */
+    private class PosixFileAttributeViewImpl
+        extends BasicFileAttributeViewImpl implements PosixFileAttributeView
+    {
+        private static final String PERMISSIONS_NAME = "permissions";
+        private static final String OWNER_NAME = "owner";
+        private static final String GROUP_NAME = "group";
+
+        PosixFileAttributeViewImpl(UnixPath file, boolean followLinks) {
+            super(file, followLinks);
+        }
+
+        private void checkWriteAndUserAccess() {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                super.checkWriteAccess();
+                sm.checkPermission(new RuntimePermission("accessUserInformation"));
+            }
+        }
+
+        @Override
+        public String name() {
+            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)
+            throws IOException
+        {
+            if (attribute.equals(PERMISSIONS_NAME)) {
+                setPermissions((Set<PosixFilePermission>)value);
+                return;
+            }
+            if (attribute.equals(OWNER_NAME)) {
+                setOwner((UserPrincipal)value);
+                return;
+            }
+            if (attribute.equals(GROUP_NAME)) {
+                setGroup((GroupPrincipal)value);
+                return;
+            }
+            super.setAttribute(attribute, value);
+        }
+
+        final void addPosixAttributesToBuilder(PosixFileAttributes attrs,
+                                               AttributesBuilder builder)
+        {
+            if (builder.match(PERMISSIONS_NAME))
+                builder.add(PERMISSIONS_NAME, attrs.permissions());
+            if (builder.match(OWNER_NAME))
+                builder.add(OWNER_NAME, attrs.owner());
+            if (builder.match(GROUP_NAME))
+                builder.add(GROUP_NAME, attrs.group());
+        }
+
+        @Override
+        public Map<String,?> readAttributes(String first, String[] rest)
+            throws IOException
+        {
+            AttributesBuilder builder = AttributesBuilder.create(first, rest);
+            PosixFileAttributes attrs = readAttributes();
+            addBasicAttributesToBuilder(attrs, builder);
+            addPosixAttributesToBuilder(attrs, builder);
+            return builder.unmodifiableMap();
+        }
+
+        @Override
+        public PosixFileAttributes readAttributes() throws IOException {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                if (file == null)
+                    ds.directory().checkRead();
+                else
+                    ds.directory().resolve(file).checkRead();
+                sm.checkPermission(new RuntimePermission("accessUserInformation"));
+            }
+
+            ds.readLock().lock();
+            try {
+                if (!ds.isOpen())
+                    throw new ClosedDirectoryStreamException();
+
+                try {
+                     UnixFileAttributes attrs = (file == null) ?
+                         UnixFileAttributes.get(dfd) :
+                         UnixFileAttributes.get(dfd, file, followLinks);
+                     return attrs;
+                } catch (UnixException x) {
+                    x.rethrowAsIOException(file);
+                    return null;    // keep compiler happy
+                }
+            } finally {
+                ds.readLock().unlock();
+            }
+        }
+
+        @Override
+        public void setPermissions(Set<PosixFilePermission> perms)
+            throws IOException
+        {
+            // permission check
+            checkWriteAndUserAccess();
+
+            ds.readLock().lock();
+            try {
+                if (!ds.isOpen())
+                    throw new ClosedDirectoryStreamException();
+
+                int fd = (file == null) ? dfd : open();
+                try {
+                    fchmod(fd, UnixFileModeAttribute.toUnixMode(perms));
+                } catch (UnixException x) {
+                    x.rethrowAsIOException(file);
+                } finally {
+                    if (file != null && fd >= 0)
+                        UnixNativeDispatcher.close(fd);
+                }
+            } finally {
+                ds.readLock().unlock();
+            }
+        }
+
+        private void setOwners(int uid, int gid) throws IOException {
+            // permission check
+            checkWriteAndUserAccess();
+
+            ds.readLock().lock();
+            try {
+                if (!ds.isOpen())
+                    throw new ClosedDirectoryStreamException();
+
+                int fd = (file == null) ? dfd : open();
+                try {
+                    fchown(fd, uid, gid);
+                } catch (UnixException x) {
+                    x.rethrowAsIOException(file);
+                } finally {
+                    if (file != null && fd >= 0)
+                        UnixNativeDispatcher.close(fd);
+                }
+            } finally {
+                ds.readLock().unlock();
+            }
+        }
+
+        @Override
+        public UserPrincipal getOwner() throws IOException {
+            return readAttributes().owner();
+        }
+
+        @Override
+        public void setOwner(UserPrincipal owner)
+            throws IOException
+        {
+            if (!(owner instanceof UnixUserPrincipals.User))
+                throw new ProviderMismatchException();
+            if (owner instanceof UnixUserPrincipals.Group)
+                throw new IOException("'owner' parameter can't be a group");
+            int uid = ((UnixUserPrincipals.User)owner).uid();
+            setOwners(uid, -1);
+        }
+
+        @Override
+        public void setGroup(GroupPrincipal group)
+            throws IOException
+        {
+            if (!(group instanceof UnixUserPrincipals.Group))
+                throw new ProviderMismatchException();
+            int gid = ((UnixUserPrincipals.Group)group).gid();
+            setOwners(-1, gid);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixUriUtils.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * Unix specific Path <--> URI conversion
+ */
+
+class UnixUriUtils {
+    private UnixUriUtils() { }
+
+    /**
+     * Converts URI to Path
+     */
+    static UnixPath fromUri(UnixFileSystem fs, URI uri) {
+        if (!uri.isAbsolute())
+            throw new IllegalArgumentException("URI is not absolute");
+        if (uri.isOpaque())
+            throw new IllegalArgumentException("URI is not hierarchical");
+        String scheme = uri.getScheme();
+        if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
+            throw new IllegalArgumentException("URI scheme is not \"file\"");
+        if (uri.getAuthority() != null)
+            throw new IllegalArgumentException("URI has an authority component");
+        if (uri.getFragment() != null)
+            throw new IllegalArgumentException("URI has a fragment component");
+        if (uri.getQuery() != null)
+            throw new IllegalArgumentException("URI has a query component");
+
+        String path = uri.getPath();
+        if (path.equals(""))
+            throw new IllegalArgumentException("URI path component is empty");
+        if (path.endsWith("/") && (path.length() > 1)) {
+            // "/foo/" --> "/foo", but "/" --> "/"
+            path = path.substring(0, path.length() - 1);
+        }
+
+        // preserve bytes
+        byte[] result = new byte[path.length()];
+        for (int i=0; i<path.length(); i++) {
+            byte v = (byte)(path.charAt(i));
+            if (v == 0)
+                throw new IllegalArgumentException("Nul character not allowed");
+            result[i] = v;
+        }
+        return new UnixPath(fs, result);
+    }
+
+    /**
+     * Converts Path to URI
+     */
+    static URI toUri(UnixPath up) {
+        byte[] path = up.toAbsolutePath().asByteArray();
+        StringBuilder sb = new StringBuilder("file:///");
+        assert path[0] == '/';
+        for (int i=1; i<path.length; i++) {
+            char c = (char)(path[i] & 0xff);
+            if (match(c, L_PATH, H_PATH)) {
+                sb.append(c);
+            } else {
+               sb.append('%');
+               sb.append(hexDigits[(c >> 4) & 0x0f]);
+               sb.append(hexDigits[(c >> 0) & 0x0f]);
+            }
+        }
+
+        // trailing slash if directory
+        if (sb.charAt(sb.length()-1) != '/') {
+            try {
+                 if (UnixFileAttributes.get(up, true).isDirectory())
+                     sb.append('/');
+            } catch (UnixException x) {
+                // ignore
+            }
+        }
+
+        try {
+            return new URI(sb.toString());
+        } catch (URISyntaxException x) {
+            throw new AssertionError(x);  // should not happen
+        }
+    }
+
+    // The following is copied from java.net.URI
+
+    // Compute the low-order mask for the characters in the given string
+    private static long lowMask(String chars) {
+        int n = chars.length();
+        long m = 0;
+        for (int i = 0; i < n; i++) {
+            char c = chars.charAt(i);
+            if (c < 64)
+                m |= (1L << c);
+        }
+        return m;
+    }
+
+    // Compute the high-order mask for the characters in the given string
+    private static long highMask(String chars) {
+        int n = chars.length();
+        long m = 0;
+        for (int i = 0; i < n; i++) {
+            char c = chars.charAt(i);
+            if ((c >= 64) && (c < 128))
+                m |= (1L << (c - 64));
+        }
+        return m;
+    }
+
+    // Compute a low-order mask for the characters
+    // between first and last, inclusive
+    private static long lowMask(char first, char last) {
+        long m = 0;
+        int f = Math.max(Math.min(first, 63), 0);
+        int l = Math.max(Math.min(last, 63), 0);
+        for (int i = f; i <= l; i++)
+            m |= 1L << i;
+        return m;
+    }
+
+    // Compute a high-order mask for the characters
+    // between first and last, inclusive
+    private static long highMask(char first, char last) {
+        long m = 0;
+        int f = Math.max(Math.min(first, 127), 64) - 64;
+        int l = Math.max(Math.min(last, 127), 64) - 64;
+        for (int i = f; i <= l; i++)
+            m |= 1L << i;
+        return m;
+    }
+
+    // Tell whether the given character is permitted by the given mask pair
+    private static boolean match(char c, long lowMask, long highMask) {
+        if (c < 64)
+            return ((1L << c) & lowMask) != 0;
+        if (c < 128)
+            return ((1L << (c - 64)) & highMask) != 0;
+        return false;
+    }
+
+    // digit    = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
+    //            "8" | "9"
+    private static final long L_DIGIT = lowMask('0', '9');
+    private static final long H_DIGIT = 0L;
+
+    // upalpha  = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
+    //            "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
+    //            "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
+    private static final long L_UPALPHA = 0L;
+    private static final long H_UPALPHA = highMask('A', 'Z');
+
+    // lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
+    //            "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
+    //            "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
+    private static final long L_LOWALPHA = 0L;
+    private static final long H_LOWALPHA = highMask('a', 'z');
+
+    // alpha         = lowalpha | upalpha
+    private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA;
+    private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA;
+
+    // alphanum      = alpha | digit
+    private static final long L_ALPHANUM = L_DIGIT | L_ALPHA;
+    private static final long H_ALPHANUM = H_DIGIT | H_ALPHA;
+
+    // mark          = "-" | "_" | "." | "!" | "~" | "*" | "'" |
+    //                 "(" | ")"
+    private static final long L_MARK = lowMask("-_.!~*'()");
+    private static final long H_MARK = highMask("-_.!~*'()");
+
+    // unreserved    = alphanum | mark
+    private static final long L_UNRESERVED = L_ALPHANUM | L_MARK;
+    private static final long H_UNRESERVED = H_ALPHANUM | H_MARK;
+
+    // pchar         = unreserved | escaped |
+    //                 ":" | "@" | "&" | "=" | "+" | "$" | ","
+    private static final long L_PCHAR
+        = L_UNRESERVED | lowMask(":@&=+$,");
+    private static final long H_PCHAR
+        = H_UNRESERVED | highMask(":@&=+$,");
+
+   // All valid path characters
+   private static final long L_PATH = L_PCHAR | lowMask(";/");
+   private static final long H_PATH = H_PCHAR | highMask(";/");
+
+   private final static char[] hexDigits = {
+        '0', '1', '2', '3', '4', '5', '6', '7',
+        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixUserPrincipals.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import static sun.nio.fs.UnixNativeDispatcher.*;
+
+/**
+ * Unix implementation of java.nio.file.attribute.UserPrincipal
+ */
+
+class UnixUserPrincipals {
+    private static User createSpecial(String name) { return new User(-1, name); }
+
+    static final User SPECIAL_OWNER = createSpecial("OWNER@");
+    static final User SPECIAL_GROUP = createSpecial("GROUP@");
+    static final User SPECIAL_EVERYONE = createSpecial("EVERYONE@");
+
+    static class User implements UserPrincipal {
+        private final int id;             // uid or gid
+        private final boolean isGroup;
+        private final String name;
+
+        private User(int id, boolean isGroup, String name) {
+            this.id = id;
+            this.isGroup = isGroup;
+            this.name = name;
+        }
+
+        User(int id, String name) {
+            this(id, false, name);
+        }
+
+        int uid() {
+            if (isGroup)
+                throw new AssertionError();
+            return id;
+        }
+
+        int gid() {
+            if (isGroup)
+                return id;
+            throw new AssertionError();
+        }
+
+        boolean isSpecial() {
+            return id == -1;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this)
+                return true;
+            if (!(obj instanceof User))
+                return false;
+            User other = (User)obj;
+            if ((this.id != other.id) ||
+                (this.isGroup != other.isGroup)) {
+                return false;
+            }
+            // specials
+            if (this.id == -1 && other.id == -1)
+                return this.name.equals(other.name);
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return (id != -1) ? id : name.hashCode();
+        }
+    }
+
+    static class Group extends User implements GroupPrincipal {
+        Group(int id, String name) {
+            super(id, true, name);
+        }
+    }
+
+    // return UserPrincipal representing given uid
+    static User fromUid(int uid) {
+        String name = null;
+        try {
+            name = new String(getpwuid(uid));
+        } catch (UnixException x) {
+            name = Integer.toString(uid);
+        }
+        return new User(uid, name);
+    }
+
+    // return GroupPrincipal representing given gid
+    static Group fromGid(int gid) {
+        String name = null;
+        try {
+            name = new String(getgrgid(gid));
+        } catch (UnixException x) {
+            name = Integer.toString(gid);
+        }
+        return new Group(gid, name);
+    }
+
+    // lookup user or group name
+    private static int lookupName(String name, boolean isGroup)
+        throws IOException
+    {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("lookupUserInformation"));
+        }
+        int id = -1;
+        try {
+            id = (isGroup) ? getgrnam(name) : getpwnam(name);
+        } catch (UnixException x) {
+            throw new IOException(name + ": " + x.errorString());
+        }
+        if (id == -1)
+            throw new UserPrincipalNotFoundException(name);
+        return id;
+
+    }
+
+    // lookup user name
+    static UserPrincipal lookupUser(String name) throws IOException {
+        if (name.equals(SPECIAL_OWNER.getName()))
+            return SPECIAL_OWNER;
+        if (name.equals(SPECIAL_GROUP.getName()))
+            return SPECIAL_GROUP;
+        if (name.equals(SPECIAL_EVERYONE.getName()))
+            return SPECIAL_EVERYONE;
+        int uid = lookupName(name, false);
+        return new User(uid, name);
+    }
+
+    // lookup group name
+    static GroupPrincipal lookupGroup(String group)
+        throws IOException
+    {
+        int gid = lookupName(group, true);
+        return new Group(gid, group);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/ch/EPoll.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+#include "nio_util.h"
+
+#include "sun_nio_ch_EPoll.h"
+
+#include <dlfcn.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* epoll_wait(2) man page */
+
+typedef union epoll_data {
+    void *ptr;
+    int fd;
+    __uint32_t u32;
+    __uint64_t u64;
+} epoll_data_t;
+
+struct epoll_event {
+    __uint32_t events;  /* Epoll events */
+    epoll_data_t data;  /* User data variable */
+} __attribute__ ((__packed__));
+
+#ifdef  __cplusplus
+}
+#endif
+
+/*
+ * epoll event notification is new in 2.6 kernel. As the offical build
+ * platform for the JDK is on a 2.4-based distribution then we must
+ * obtain the addresses of the epoll functions dynamically.
+ */
+typedef int (*epoll_create_t)(int size);
+typedef int (*epoll_ctl_t)   (int epfd, int op, int fd, struct epoll_event *event);
+typedef int (*epoll_wait_t)  (int epfd, struct epoll_event *events, int maxevents, int timeout);
+
+static epoll_create_t epoll_create_func;
+static epoll_ctl_t    epoll_ctl_func;
+static epoll_wait_t   epoll_wait_func;
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_EPoll_init(JNIEnv *env, jclass this)
+{
+    epoll_create_func = (epoll_create_t) dlsym(RTLD_DEFAULT, "epoll_create");
+    epoll_ctl_func    = (epoll_ctl_t)    dlsym(RTLD_DEFAULT, "epoll_ctl");
+    epoll_wait_func   = (epoll_wait_t)   dlsym(RTLD_DEFAULT, "epoll_wait");
+
+    if ((epoll_create_func == NULL) || (epoll_ctl_func == NULL) ||
+        (epoll_wait_func == NULL)) {
+        JNU_ThrowInternalError(env, "unable to get address of epoll functions, pre-2.6 kernel?");
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_EPoll_eventSize(JNIEnv* env, jclass this)
+{
+    return sizeof(struct epoll_event);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_EPoll_eventsOffset(JNIEnv* env, jclass this)
+{
+    return offsetof(struct epoll_event, events);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_EPoll_dataOffset(JNIEnv* env, jclass this)
+{
+    return offsetof(struct epoll_event, data);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_EPoll_epollCreate(JNIEnv *env, jclass c) {
+    /*
+     * epoll_create expects a size as a hint to the kernel about how to
+     * dimension internal structures. We can't predict the size in advance.
+     */
+    int epfd = (*epoll_create_func)(256);
+    if (epfd < 0) {
+       JNU_ThrowIOExceptionWithLastError(env, "epoll_create failed");
+    }
+    return epfd;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_EPoll_epollCtl(JNIEnv *env, jclass c, jint epfd,
+                                   jint opcode, jint fd, jint events)
+{
+    struct epoll_event event;
+    int res;
+
+    event.events = events;
+    event.data.fd = fd;
+
+    RESTARTABLE((*epoll_ctl_func)(epfd, (int)opcode, (int)fd, &event), res);
+
+    return (res == 0) ? 0 : errno;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_EPoll_epollWait(JNIEnv *env, jclass c,
+                                    jint epfd, jlong address, jint numfds)
+{
+    struct epoll_event *events = jlong_to_ptr(address);
+    int res;
+
+    RESTARTABLE((*epoll_wait_func)(epfd, events, numfds, -1), res);
+    if (res < 0) {
+        JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed");
+    }
+    return res;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_EPoll_close0(JNIEnv *env, jclass c, jint epfd) {
+    int res;
+    RESTARTABLE(close(epfd), res);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/ch/EPollPort.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+#include "nio_util.h"
+
+#include "sun_nio_ch_EPollPort.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_EPollPort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) {
+    int sp[2];
+    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
+    } else {
+        jint res[2];
+        res[0] = (jint)sp[0];
+        res[1] = (jint)sp[1];
+        (*env)->SetIntArrayRegion(env, sv, 0, 2, &res[0]);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_EPollPort_interrupt(JNIEnv *env, jclass c, jint fd) {
+    int res;
+    int buf[1];
+    buf[0] = 1;
+    RESTARTABLE(write(fd, buf, 1), res);
+    if (res < 0) {
+        JNU_ThrowIOExceptionWithLastError(env, "write failed");
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_EPollPort_drain1(JNIEnv *env, jclass cl, jint fd) {
+    int res;
+    char buf[1];
+    RESTARTABLE(read(fd, buf, 1), res);
+    if (res < 0) {
+        JNU_ThrowIOExceptionWithLastError(env, "drain1 failed");
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_EPollPort_close0(JNIEnv *env, jclass c, jint fd) {
+    int res;
+    RESTARTABLE(close(fd), res);
+}
--- a/jdk/src/solaris/native/sun/nio/ch/FileChannelImpl.c	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/solaris/native/sun/nio/ch/FileChannelImpl.c	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -31,7 +31,6 @@
 #include <sys/stat.h>
 #include "sun_nio_ch_FileChannelImpl.h"
 #include "java_lang_Integer.h"
-#include "java_lang_Long.h"
 #include "nio.h"
 #include "nio_util.h"
 #include <dlfcn.h>
@@ -145,32 +144,6 @@
 }
 
 
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_FileChannelImpl_truncate0(JNIEnv *env, jobject this,
-                                          jobject fdo, jlong size)
-{
-    return handle(env,
-                  ftruncate64(fdval(env, fdo), size),
-                  "Truncation failed");
-}
-
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_FileChannelImpl_force0(JNIEnv *env, jobject this,
-                                       jobject fdo, jboolean md)
-{
-    jint fd = fdval(env, fdo);
-    int result = 0;
-
-    if (md == JNI_FALSE) {
-        result = fdatasync(fd);
-    } else {
-        result = fsync(fd);
-    }
-    return handle(env, result, "Force failed");
-}
-
-
 JNIEXPORT jlong JNICALL
 Java_sun_nio_ch_FileChannelImpl_position0(JNIEnv *env, jobject this,
                                           jobject fdo, jlong offset)
@@ -187,17 +160,6 @@
 }
 
 
-JNIEXPORT jlong JNICALL
-Java_sun_nio_ch_FileChannelImpl_size0(JNIEnv *env, jobject this, jobject fdo)
-{
-    struct stat64 fbuf;
-
-    if (fstat64(fdval(env, fdo), &fbuf) < 0)
-        return handle(env, -1, "Size failed");
-    return fbuf.st_size;
-}
-
-
 JNIEXPORT void JNICALL
 Java_sun_nio_ch_FileChannelImpl_close0(JNIEnv *env, jobject this, jobject fdo)
 {
@@ -280,65 +242,3 @@
     }
 #endif
 }
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_FileChannelImpl_lock0(JNIEnv *env, jobject this, jobject fdo,
-                                      jboolean block, jlong pos, jlong size,
-                                      jboolean shared)
-{
-    jint fd = fdval(env, fdo);
-    jint lockResult = 0;
-    int cmd = 0;
-    struct flock64 fl;
-
-    fl.l_whence = SEEK_SET;
-    if (size == (jlong)java_lang_Long_MAX_VALUE) {
-        fl.l_len = (off64_t)0;
-    } else {
-        fl.l_len = (off64_t)size;
-    }
-    fl.l_start = (off64_t)pos;
-    if (shared == JNI_TRUE) {
-        fl.l_type = F_RDLCK;
-    } else {
-        fl.l_type = F_WRLCK;
-    }
-    if (block == JNI_TRUE) {
-        cmd = F_SETLKW64;
-    } else {
-        cmd = F_SETLK64;
-    }
-    lockResult = fcntl(fd, cmd, &fl);
-    if (lockResult < 0) {
-        if ((cmd == F_SETLK64) && (errno == EAGAIN))
-            return sun_nio_ch_FileChannelImpl_NO_LOCK;
-        if (errno == EINTR)
-            return sun_nio_ch_FileChannelImpl_INTERRUPTED;
-        JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
-    }
-    return 0;
-}
-
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_FileChannelImpl_release0(JNIEnv *env, jobject this,
-                                         jobject fdo, jlong pos, jlong size)
-{
-    jint fd = fdval(env, fdo);
-    jint lockResult = 0;
-    struct flock64 fl;
-    int cmd = F_SETLK64;
-
-    fl.l_whence = SEEK_SET;
-    if (size == (jlong)java_lang_Long_MAX_VALUE) {
-        fl.l_len = (off64_t)0;
-    } else {
-        fl.l_len = (off64_t)size;
-    }
-    fl.l_start = (off64_t)pos;
-    fl.l_type = F_UNLCK;
-    lockResult = fcntl(fd, cmd, &fl);
-    if (lockResult < 0) {
-        JNU_ThrowIOExceptionWithLastError(env, "Release failed");
-    }
-}
--- a/jdk/src/solaris/native/sun/nio/ch/FileDispatcher.c	Wed Feb 11 13:16:53 2009 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,147 +0,0 @@
-/*
- * Copyright 2000-2002 Sun Microsystems, Inc.  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.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-#include "jni.h"
-#include "jni_util.h"
-#include "jvm.h"
-#include "jlong.h"
-#include "sun_nio_ch_FileDispatcher.h"
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <fcntl.h>
-#include <sys/uio.h>
-#include "nio_util.h"
-
-
-static int preCloseFD = -1;     /* File descriptor to which we dup other fd's
-                                   before closing them for real */
-
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_FileDispatcher_init(JNIEnv *env, jclass cl)
-{
-    int sp[2];
-    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) {
-        JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
-        return;
-    }
-    preCloseFD = sp[0];
-    close(sp[1]);
-}
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_FileDispatcher_read0(JNIEnv *env, jclass clazz,
-                             jobject fdo, jlong address, jint len)
-{
-    jint fd = fdval(env, fdo);
-    void *buf = (void *)jlong_to_ptr(address);
-
-    return convertReturnVal(env, read(fd, buf, len), JNI_TRUE);
-}
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_FileDispatcher_pread0(JNIEnv *env, jclass clazz, jobject fdo,
-                            jlong address, jint len, jlong offset)
-{
-    jint fd = fdval(env, fdo);
-    void *buf = (void *)jlong_to_ptr(address);
-
-    return convertReturnVal(env, pread64(fd, buf, len, offset), JNI_TRUE);
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_nio_ch_FileDispatcher_readv0(JNIEnv *env, jclass clazz,
-                              jobject fdo, jlong address, jint len)
-{
-    jint fd = fdval(env, fdo);
-    struct iovec *iov = (struct iovec *)jlong_to_ptr(address);
-    if (len > 16) {
-        len = 16;
-    }
-    return convertLongReturnVal(env, readv(fd, iov, len), JNI_TRUE);
-}
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_FileDispatcher_write0(JNIEnv *env, jclass clazz,
-                              jobject fdo, jlong address, jint len)
-{
-    jint fd = fdval(env, fdo);
-    void *buf = (void *)jlong_to_ptr(address);
-
-    return convertReturnVal(env, write(fd, buf, len), JNI_FALSE);
-}
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_FileDispatcher_pwrite0(JNIEnv *env, jclass clazz, jobject fdo,
-                            jlong address, jint len, jlong offset)
-{
-    jint fd = fdval(env, fdo);
-    void *buf = (void *)jlong_to_ptr(address);
-
-    return convertReturnVal(env, pwrite64(fd, buf, len, offset), JNI_FALSE);
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_nio_ch_FileDispatcher_writev0(JNIEnv *env, jclass clazz,
-                                       jobject fdo, jlong address, jint len)
-{
-    jint fd = fdval(env, fdo);
-    struct iovec *iov = (struct iovec *)jlong_to_ptr(address);
-    if (len > 16) {
-        len = 16;
-    }
-    return convertLongReturnVal(env, writev(fd, iov, len), JNI_FALSE);
-}
-
-static void closeFileDescriptor(JNIEnv *env, int fd) {
-    if (fd != -1) {
-        int result = close(fd);
-        if (result < 0)
-            JNU_ThrowIOExceptionWithLastError(env, "Close failed");
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_FileDispatcher_close0(JNIEnv *env, jclass clazz, jobject fdo)
-{
-    jint fd = fdval(env, fdo);
-    closeFileDescriptor(env, fd);
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_FileDispatcher_preClose0(JNIEnv *env, jclass clazz, jobject fdo)
-{
-    jint fd = fdval(env, fdo);
-    if (preCloseFD >= 0) {
-        if (dup2(preCloseFD, fd) < 0)
-            JNU_ThrowIOExceptionWithLastError(env, "dup2 failed");
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_FileDispatcher_closeIntFD(JNIEnv *env, jclass clazz, jint fd)
-{
-    closeFileDescriptor(env, fd);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/ch/FileDispatcherImpl.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+#include "sun_nio_ch_FileDispatcherImpl.h"
+#include "java_lang_Long.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/uio.h>
+#include "nio.h"
+#include "nio_util.h"
+
+
+static int preCloseFD = -1;     /* File descriptor to which we dup other fd's
+                                   before closing them for real */
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_init(JNIEnv *env, jclass cl)
+{
+    int sp[2];
+    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) < 0) {
+        JNU_ThrowIOExceptionWithLastError(env, "socketpair failed");
+        return;
+    }
+    preCloseFD = sp[0];
+    close(sp[1]);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz,
+                             jobject fdo, jlong address, jint len)
+{
+    jint fd = fdval(env, fdo);
+    void *buf = (void *)jlong_to_ptr(address);
+
+    return convertReturnVal(env, read(fd, buf, len), JNI_TRUE);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo,
+                            jlong address, jint len, jlong offset)
+{
+    jint fd = fdval(env, fdo);
+    void *buf = (void *)jlong_to_ptr(address);
+
+    return convertReturnVal(env, pread64(fd, buf, len, offset), JNI_TRUE);
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz,
+                              jobject fdo, jlong address, jint len)
+{
+    jint fd = fdval(env, fdo);
+    struct iovec *iov = (struct iovec *)jlong_to_ptr(address);
+    if (len > 16) {
+        len = 16;
+    }
+    return convertLongReturnVal(env, readv(fd, iov, len), JNI_TRUE);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz,
+                              jobject fdo, jlong address, jint len)
+{
+    jint fd = fdval(env, fdo);
+    void *buf = (void *)jlong_to_ptr(address);
+
+    return convertReturnVal(env, write(fd, buf, len), JNI_FALSE);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo,
+                            jlong address, jint len, jlong offset)
+{
+    jint fd = fdval(env, fdo);
+    void *buf = (void *)jlong_to_ptr(address);
+
+    return convertReturnVal(env, pwrite64(fd, buf, len, offset), JNI_FALSE);
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz,
+                                       jobject fdo, jlong address, jint len)
+{
+    jint fd = fdval(env, fdo);
+    struct iovec *iov = (struct iovec *)jlong_to_ptr(address);
+    if (len > 16) {
+        len = 16;
+    }
+    return convertLongReturnVal(env, writev(fd, iov, len), JNI_FALSE);
+}
+
+static jlong
+handle(JNIEnv *env, jlong rv, char *msg)
+{
+    if (rv >= 0)
+        return rv;
+    if (errno == EINTR)
+        return IOS_INTERRUPTED;
+    JNU_ThrowIOExceptionWithLastError(env, msg);
+    return IOS_THROWN;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this,
+                                          jobject fdo, jboolean md)
+{
+    jint fd = fdval(env, fdo);
+    int result = 0;
+
+    if (md == JNI_FALSE) {
+        result = fdatasync(fd);
+    } else {
+        result = fsync(fd);
+    }
+    return handle(env, result, "Force failed");
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this,
+                                             jobject fdo, jlong size)
+{
+    return handle(env,
+                  ftruncate64(fdval(env, fdo), size),
+                  "Truncation failed");
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo)
+{
+    struct stat64 fbuf;
+
+    if (fstat64(fdval(env, fdo), &fbuf) < 0)
+        return handle(env, -1, "Size failed");
+    return fbuf.st_size;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo,
+                                      jboolean block, jlong pos, jlong size,
+                                      jboolean shared)
+{
+    jint fd = fdval(env, fdo);
+    jint lockResult = 0;
+    int cmd = 0;
+    struct flock64 fl;
+
+    fl.l_whence = SEEK_SET;
+    if (size == (jlong)java_lang_Long_MAX_VALUE) {
+        fl.l_len = (off64_t)0;
+    } else {
+        fl.l_len = (off64_t)size;
+    }
+    fl.l_start = (off64_t)pos;
+    if (shared == JNI_TRUE) {
+        fl.l_type = F_RDLCK;
+    } else {
+        fl.l_type = F_WRLCK;
+    }
+    if (block == JNI_TRUE) {
+        cmd = F_SETLKW64;
+    } else {
+        cmd = F_SETLK64;
+    }
+    lockResult = fcntl(fd, cmd, &fl);
+    if (lockResult < 0) {
+        if ((cmd == F_SETLK64) && (errno == EAGAIN))
+            return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
+        if (errno == EINTR)
+            return sun_nio_ch_FileDispatcherImpl_INTERRUPTED;
+        JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
+    }
+    return 0;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this,
+                                         jobject fdo, jlong pos, jlong size)
+{
+    jint fd = fdval(env, fdo);
+    jint lockResult = 0;
+    struct flock64 fl;
+    int cmd = F_SETLK64;
+
+    fl.l_whence = SEEK_SET;
+    if (size == (jlong)java_lang_Long_MAX_VALUE) {
+        fl.l_len = (off64_t)0;
+    } else {
+        fl.l_len = (off64_t)size;
+    }
+    fl.l_start = (off64_t)pos;
+    fl.l_type = F_UNLCK;
+    lockResult = fcntl(fd, cmd, &fl);
+    if (lockResult < 0) {
+        JNU_ThrowIOExceptionWithLastError(env, "Release failed");
+    }
+}
+
+
+static void closeFileDescriptor(JNIEnv *env, int fd) {
+    if (fd != -1) {
+        int result = close(fd);
+        if (result < 0)
+            JNU_ThrowIOExceptionWithLastError(env, "Close failed");
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo)
+{
+    jint fd = fdval(env, fdo);
+    closeFileDescriptor(env, fd);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_preClose0(JNIEnv *env, jclass clazz, jobject fdo)
+{
+    jint fd = fdval(env, fdo);
+    if (preCloseFD >= 0) {
+        if (dup2(preCloseFD, fd) < 0)
+            JNU_ThrowIOExceptionWithLastError(env, "dup2 failed");
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_closeIntFD(JNIEnv *env, jclass clazz, jint fd)
+{
+    closeFileDescriptor(env, fd);
+}
--- a/jdk/src/solaris/native/sun/nio/ch/SocketDispatcher.c	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/solaris/native/sun/nio/ch/SocketDispatcher.c	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2001 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -27,7 +27,6 @@
 #include "jni_util.h"
 #include "jvm.h"
 #include "jlong.h"
-#include "sun_nio_ch_FileDispatcher.h"
 
 /* this is a fake c file to make the build happy since there is no
    real SocketDispatcher.c file on Solaris but there is on windows. */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/ch/SolarisEventPort.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+#include "nio_util.h"
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <port.h>       // Solaris 10
+
+#include "sun_nio_ch_SolarisEventPort.h"
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_SolarisEventPort_init(JNIEnv *env, jclass clazz)
+{
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_SolarisEventPort_portCreate
+    (JNIEnv* env, jclass clazz)
+{
+    int port = port_create();
+    if (port == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "port_create");
+    }
+    return (jint)port;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_SolarisEventPort_portClose
+    (JNIEnv* env, jclass clazz, jint port)
+{
+    int res;
+    RESTARTABLE(close(port), res);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_SolarisEventPort_portAssociate
+    (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress, jint events)
+{
+    uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
+
+    if (port_associate((int)port, (int)source, object, (int)events, NULL) == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "port_associate");
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_SolarisEventPort_portDissociate
+    (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress)
+{
+    uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
+
+    if (port_dissociate((int)port, (int)source, object) == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "port_dissociate");
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_SolarisEventPort_portSend(JNIEnv* env, jclass clazz,
+    jint port, jint events)
+{
+    if (port_send((int)port, (int)events, NULL) == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "port_send");
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_SolarisEventPort_portGet(JNIEnv* env, jclass clazz,
+    jint port, jlong eventAddress)
+{
+    int res;
+    port_event_t* ev = (port_event_t*)jlong_to_ptr(eventAddress);
+
+    RESTARTABLE(port_get((int)port, ev, NULL), res);
+    if (res == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "port_get");
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_SolarisEventPort_portGetn(JNIEnv* env, jclass clazz,
+    jint port, jlong arrayAddress, jint max)
+{
+    int res;
+    uint_t n = 1;
+    port_event_t* list = (port_event_t*)jlong_to_ptr(arrayAddress);
+
+    RESTARTABLE(port_getn((int)port, list, (uint_t)max, &n, NULL), res);
+    if (res == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "port_getn");
+    }
+    return (jint)n;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include "sun_nio_ch_UnixAsynchronousServerSocketChannelImpl.h"
+
+extern void Java_sun_nio_ch_ServerSocketChannelImpl_initIDs(JNIEnv* env,
+    jclass c);
+
+extern jint Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv* env,
+    jobject this, jobject ssfdo, jobject newfdo, jobjectArray isaa);
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_initIDs(JNIEnv* env,
+    jclass c)
+{
+    Java_sun_nio_ch_ServerSocketChannelImpl_initIDs(env, c);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_UnixAsynchronousServerSocketChannelImpl_accept0(JNIEnv* env,
+    jobject this, jobject ssfdo, jobject newfdo, jobjectArray isaa)
+{
+    return Java_sun_nio_ch_ServerSocketChannelImpl_accept0(env, this,
+        ssfdo, newfdo, isaa);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/ch/UnixAsynchronousSocketChannelImpl.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "net_util.h"
+#include "jlong.h"
+#include "sun_nio_ch_UnixAsynchronousSocketChannelImpl.h"
+#include "nio_util.h"
+#include "nio.h"
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_UnixAsynchronousSocketChannelImpl_checkConnect(JNIEnv *env,
+    jobject this, int fd)
+{
+    int error = 0;
+    int n = sizeof(error);
+    int result;
+
+    result = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n);
+    if (result < 0) {
+        JNU_ThrowIOExceptionWithLastError(env, "getsockopt");
+    } else {
+        if (error)
+            handleSocketError(env, error);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/fs/GnomeFileTypeDetector.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <link.h>
+
+#ifdef __solaris__
+#include <strings.h>
+#endif
+
+#ifdef __linux__
+#include <string.h>
+#endif
+
+/* Definitions for GIO */
+
+#define G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "standard::content-type"
+
+typedef void* gpointer;
+typedef struct _GFile GFile;
+typedef struct _GFileInfo GFileInfo;
+typedef struct _GCancellable GCancellable;
+typedef struct _GError GError;
+
+typedef enum {
+  G_FILE_QUERY_INFO_NONE = 0
+} GFileQueryInfoFlags;
+
+typedef void (*g_type_init_func)(void);
+typedef void (*g_object_unref_func)(gpointer object);
+typedef GFile* (*g_file_new_for_path_func)(const char* path);
+typedef GFileInfo* (*g_file_query_info_func)(GFile *file,
+    const char *attributes, GFileQueryInfoFlags flags,
+    GCancellable *cancellable, GError **error);
+typedef char* (*g_file_info_get_content_type_func)(GFileInfo *info);
+
+static g_type_init_func g_type_init;
+static g_object_unref_func g_object_unref;
+static g_file_new_for_path_func g_file_new_for_path;
+static g_file_query_info_func g_file_query_info;
+static g_file_info_get_content_type_func g_file_info_get_content_type;
+
+
+/* Definitions for GNOME VFS */
+
+typedef int gboolean;
+
+typedef gboolean (*gnome_vfs_init_function)(void);
+typedef const char* (*gnome_vfs_mime_type_from_name_function)
+    (const char* filename);
+
+static gnome_vfs_init_function gnome_vfs_init;
+static gnome_vfs_mime_type_from_name_function gnome_vfs_mime_type_from_name;
+
+
+#include "sun_nio_fs_GnomeFileTypeDetector.h"
+
+
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_fs_GnomeFileTypeDetector_initializeGio
+    (JNIEnv* env, jclass this)
+{
+    void* gio_handle;
+
+    gio_handle = dlopen("libgio-2.0.so", RTLD_LAZY);
+    if (gio_handle == NULL) {
+        gio_handle = dlopen("libgio-2.0.so.0", RTLD_LAZY);
+        if (gio_handle == NULL) {
+            return JNI_FALSE;
+        }
+    }
+
+    g_type_init = (g_type_init_func)dlsym(gio_handle, "g_type_init");
+    (*g_type_init)();
+
+    g_object_unref = (g_object_unref_func)dlsym(gio_handle, "g_object_unref");
+
+    g_file_new_for_path =
+        (g_file_new_for_path_func)dlsym(gio_handle, "g_file_new_for_path");
+
+    g_file_query_info =
+        (g_file_query_info_func)dlsym(gio_handle, "g_file_query_info");
+
+    g_file_info_get_content_type = (g_file_info_get_content_type_func)
+        dlsym(gio_handle, "g_file_info_get_content_type");
+
+
+    if (g_type_init == NULL ||
+        g_object_unref == NULL ||
+        g_file_new_for_path == NULL ||
+        g_file_query_info == NULL ||
+        g_file_info_get_content_type == NULL)
+    {
+        dlclose(gio_handle);
+        return JNI_FALSE;
+    }
+
+    (*g_type_init)();
+    return JNI_TRUE;
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGio
+    (JNIEnv* env, jclass this, jlong pathAddress)
+{
+    char* path = (char*)jlong_to_ptr(pathAddress);
+    GFile* gfile;
+    GFileInfo* gfileinfo;
+    jbyteArray result = NULL;
+
+    gfile = (*g_file_new_for_path)(path);
+    gfileinfo = (*g_file_query_info)(gfile, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+        G_FILE_QUERY_INFO_NONE, NULL, NULL);
+    if (gfileinfo != NULL) {
+        const char* mime = (*g_file_info_get_content_type)(gfileinfo);
+        if (mime != NULL) {
+            jsize len = strlen(mime);
+            result = (*env)->NewByteArray(env, len);
+            if (result != NULL) {
+                (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)mime);
+            }
+        }
+        (*g_object_unref)(gfileinfo);
+    }
+    (*g_object_unref)(gfile);
+
+    return result;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_fs_GnomeFileTypeDetector_initializeGnomeVfs
+    (JNIEnv* env, jclass this)
+{
+    void* vfs_handle;
+
+    vfs_handle = dlopen("libgnomevfs-2.so", RTLD_LAZY);
+    if (vfs_handle == NULL) {
+        vfs_handle = dlopen("libgnomevfs-2.so.0", RTLD_LAZY);
+    }
+    if (vfs_handle == NULL) {
+        return JNI_FALSE;
+    }
+
+    gnome_vfs_init = (gnome_vfs_init_function)dlsym(vfs_handle, "gnome_vfs_init");
+    gnome_vfs_mime_type_from_name = (gnome_vfs_mime_type_from_name_function)
+        dlsym(vfs_handle, "gnome_vfs_mime_type_from_name");
+
+    if (gnome_vfs_init == NULL ||
+        gnome_vfs_mime_type_from_name == NULL)
+    {
+        dlclose(vfs_handle);
+        return JNI_FALSE;
+    }
+
+    (*gnome_vfs_init)();
+    return JNI_TRUE;
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_sun_nio_fs_GnomeFileTypeDetector_probeUsingGnomeVfs
+    (JNIEnv* env, jclass this, jlong pathAddress)
+{
+    char* path = (char*)jlong_to_ptr(pathAddress);
+    const char* mime = (*gnome_vfs_mime_type_from_name)(path);
+
+    if (mime == NULL) {
+        return NULL;
+    } else {
+        jbyteArray result;
+        jsize len = strlen(mime);
+        result = (*env)->NewByteArray(env, len);
+        if (result != NULL) {
+            (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)mime);
+        }
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+
+#include <stdio.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <mntent.h>
+
+#include "sun_nio_fs_LinuxNativeDispatcher.h"
+
+typedef size_t fgetxattr_func(int fd, const char* name, void* value, size_t size);
+typedef int fsetxattr_func(int fd, const char* name, void* value, size_t size, int flags);
+typedef int fremovexattr_func(int fd, const char* name);
+typedef int flistxattr_func(int fd, char* list, size_t size);
+
+fgetxattr_func* my_fgetxattr_func = NULL;
+fsetxattr_func* my_fsetxattr_func = NULL;
+fremovexattr_func* my_fremovexattr_func = NULL;
+flistxattr_func* my_flistxattr_func = NULL;
+
+static void throwUnixException(JNIEnv* env, int errnum) {
+    jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
+        "(I)V", errnum);
+    if (x != NULL) {
+        (*env)->Throw(env, x);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_LinuxNativeDispatcher_init(JNIEnv *env, jclass clazz)
+{
+    my_fgetxattr_func = (fgetxattr_func*)dlsym(RTLD_DEFAULT, "fgetxattr");
+    my_fsetxattr_func = (fsetxattr_func*)dlsym(RTLD_DEFAULT, "fsetxattr");
+    my_fremovexattr_func = (fremovexattr_func*)dlsym(RTLD_DEFAULT, "fremovexattr");
+    my_flistxattr_func = (flistxattr_func*)dlsym(RTLD_DEFAULT, "flistxattr");
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_LinuxNativeDispatcher_fgetxattr0(JNIEnv* env, jclass clazz,
+    jint fd, jlong nameAddress, jlong valueAddress, jint valueLen)
+{
+    size_t res = -1;
+    const char* name = jlong_to_ptr(nameAddress);
+    void* value = jlong_to_ptr(valueAddress);
+
+    if (my_fgetxattr_func == NULL) {
+        errno = ENOTSUP;
+    } else {
+        /* EINTR not documented */
+        res = (*my_fgetxattr_func)(fd, name, value, valueLen);
+    }
+    if (res == (size_t)-1)
+        throwUnixException(env, errno);
+    return (jint)res;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_LinuxNativeDispatcher_fsetxattr0(JNIEnv* env, jclass clazz,
+    jint fd, jlong nameAddress, jlong valueAddress, jint valueLen)
+{
+    int res = -1;
+    const char* name = jlong_to_ptr(nameAddress);
+    void* value = jlong_to_ptr(valueAddress);
+
+    if (my_fsetxattr_func == NULL) {
+        errno = ENOTSUP;
+    } else {
+        /* EINTR not documented */
+        res = (*my_fsetxattr_func)(fd, name, value, valueLen, 0);
+    }
+    if (res == -1)
+        throwUnixException(env, errno);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_LinuxNativeDispatcher_fremovexattr0(JNIEnv* env, jclass clazz,
+    jint fd, jlong nameAddress)
+{
+    int res = -1;
+    const char* name = jlong_to_ptr(nameAddress);
+
+    if (my_fremovexattr_func == NULL) {
+        errno = ENOTSUP;
+    } else {
+        /* EINTR not documented */
+        res = (*my_fremovexattr_func)(fd, name);
+    }
+    if (res == -1)
+        throwUnixException(env, errno);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_LinuxNativeDispatcher_flistxattr(JNIEnv* env, jclass clazz,
+    jint fd, jlong listAddress, jint size)
+{
+    size_t res = -1;
+    char* list = jlong_to_ptr(listAddress);
+
+    if (my_flistxattr_func == NULL) {
+        errno = ENOTSUP;
+    } else {
+        /* EINTR not documented */
+        res = (*my_flistxattr_func)(fd, list, (size_t)size);
+    }
+    if (res == (size_t)-1)
+        throwUnixException(env, errno);
+    return (jint)res;
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_LinuxNativeDispatcher_setmntent0(JNIEnv* env, jclass this, jlong pathAddress,
+                                                 jlong modeAddress)
+{
+    FILE* fp = NULL;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+    const char* mode = (const char*)jlong_to_ptr(modeAddress);
+
+    do {
+        fp = setmntent(path, mode);
+    } while (fp == NULL && errno == EINTR);
+    if (fp == NULL) {
+        throwUnixException(env, errno);
+    }
+    return ptr_to_jlong(fp);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_LinuxNativeDispatcher_endmntent(JNIEnv* env, jclass this, jlong stream)
+{
+    FILE* fp = jlong_to_ptr(stream);
+    /* FIXME - man page doesn't explain how errors are returned */
+    endmntent(fp);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/fs/LinuxWatchService.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+
+#include "sun_nio_fs_LinuxWatchService.h"
+
+/* inotify.h may not be available at build time */
+#ifdef  __cplusplus
+extern "C" {
+#endif
+struct inotify_event
+{
+  int wd;
+  uint32_t mask;
+  uint32_t cookie;
+  uint32_t len;
+  char name __flexarr;
+};
+#ifdef  __cplusplus
+}
+#endif
+
+typedef int inotify_init_func(void);
+typedef int inotify_add_watch_func(int fd, const char* path, uint32_t mask);
+typedef int inotify_rm_watch_func(int fd, uint32_t wd);
+
+inotify_init_func* my_inotify_init_func = NULL;
+inotify_add_watch_func* my_inotify_add_watch_func = NULL;
+inotify_rm_watch_func* my_inotify_rm_watch_func = NULL;
+
+static void throwUnixException(JNIEnv* env, int errnum) {
+    jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
+        "(I)V", errnum);
+    if (x != NULL) {
+        (*env)->Throw(env, x);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_LinuxWatchService_init(JNIEnv *env, jclass clazz)
+{
+    my_inotify_init_func = (inotify_init_func*)
+        dlsym(RTLD_DEFAULT, "inotify_init");
+    my_inotify_add_watch_func =
+        (inotify_add_watch_func*) dlsym(RTLD_DEFAULT, "inotify_add_watch");
+    my_inotify_rm_watch_func =
+        (inotify_rm_watch_func*) dlsym(RTLD_DEFAULT, "inotify_rm_watch");
+
+    if ((my_inotify_init_func == NULL) || (my_inotify_add_watch_func == NULL) ||
+        (my_inotify_rm_watch_func == NULL)) {
+        JNU_ThrowInternalError(env, "unable to get address of inotify functions");
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_LinuxWatchService_eventSize(JNIEnv *env, jclass clazz)
+{
+    return (jint)sizeof(struct inotify_event);
+}
+
+JNIEXPORT jintArray JNICALL
+Java_sun_nio_fs_LinuxWatchService_eventOffsets(JNIEnv *env, jclass clazz)
+{
+    jintArray result = (*env)->NewIntArray(env, 5);
+    if (result != NULL) {
+        jint arr[5];
+        arr[0] = (jint)offsetof(struct inotify_event, wd);
+        arr[1] = (jint)offsetof(struct inotify_event, mask);
+        arr[2] = (jint)offsetof(struct inotify_event, cookie);
+        arr[3] = (jint)offsetof(struct inotify_event, len);
+        arr[4] = (jint)offsetof(struct inotify_event, name);
+        (*env)->SetIntArrayRegion(env, result, 0, 5, arr);
+    }
+    return result;
+}
+
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_LinuxWatchService_inotifyInit
+    (JNIEnv* env, jclass clazz)
+{
+    int ifd = (*my_inotify_init_func)();
+    if (ifd == -1) {
+        throwUnixException(env, errno);
+    }
+    return (jint)ifd;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_LinuxWatchService_inotifyAddWatch
+    (JNIEnv* env, jclass clazz, jint fd, jlong address, jint mask)
+{
+    int wfd = -1;
+    const char* path = (const char*)jlong_to_ptr(address);
+
+    wfd = (*my_inotify_add_watch_func)((int)fd, path, mask);
+    if (wfd == -1) {
+        throwUnixException(env, errno);
+    }
+    return (jint)wfd;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_LinuxWatchService_inotifyRmWatch
+    (JNIEnv* env, jclass clazz, jint fd, jint wd)
+{
+    int err = (*my_inotify_rm_watch_func)((int)fd, (int)wd);
+    if (err == -1)
+        throwUnixException(env, errno);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_LinuxWatchService_configureBlocking
+    (JNIEnv* env, jclass clazz, jint fd, jboolean blocking)
+{
+    int flags = fcntl(fd, F_GETFL);
+
+    if ((blocking == JNI_FALSE) && !(flags & O_NONBLOCK))
+        fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+    else if ((blocking == JNI_TRUE) && (flags & O_NONBLOCK))
+        fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_LinuxWatchService_socketpair
+    (JNIEnv* env, jclass clazz, jintArray sv)
+{
+    int sp[2];
+    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) {
+        throwUnixException(env, errno);
+    } else {
+        jint res[2];
+        res[0] = (jint)sp[0];
+        res[1] = (jint)sp[1];
+        (*env)->SetIntArrayRegion(env, sv, 0, 2, &res[0]);
+    }
+
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_LinuxWatchService_poll
+    (JNIEnv* env, jclass clazz, jint fd1, jint fd2)
+{
+    struct pollfd ufds[2];
+    int n;
+
+    ufds[0].fd = fd1;
+    ufds[0].events = POLLIN;
+    ufds[1].fd = fd2;
+    ufds[1].events = POLLIN;
+
+    n = poll(&ufds[0], 2, -1);
+    if (n == -1) {
+        if (errno == EINTR) {
+            n = 0;
+        } else {
+            throwUnixException(env, errno);
+        }
+     }
+    return (jint)n;
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/fs/SolarisNativeDispatcher.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <sys/acl.h>
+
+#include "sun_nio_fs_SolarisNativeDispatcher.h"
+
+static void throwUnixException(JNIEnv* env, int errnum) {
+    jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
+        "(I)V", errnum);
+    if (x != NULL) {
+        (*env)->Throw(env, x);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_SolarisNativeDispatcher_init(JNIEnv *env, jclass clazz) {
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_SolarisNativeDispatcher_facl(JNIEnv* env, jclass this, jint fd,
+    jint cmd, jint nentries, jlong address)
+{
+    void* aclbufp = jlong_to_ptr(address);
+    int n = -1;
+
+    n = facl((int)fd, (int)cmd, (int)nentries, aclbufp);
+    if (n == -1) {
+        throwUnixException(env, errno);
+    }
+    return (jint)n;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/fs/SolarisWatchService.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <port.h>       // Solaris 10
+
+#include "sun_nio_fs_SolarisWatchService.h"
+
+static void throwUnixException(JNIEnv* env, int errnum) {
+    jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
+        "(I)V", errnum);
+    if (x != NULL) {
+        (*env)->Throw(env, x);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_SolarisWatchService_init(JNIEnv *env, jclass clazz)
+{
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_SolarisWatchService_portCreate
+    (JNIEnv* env, jclass clazz)
+{
+    int port = port_create();
+    if (port == -1) {
+        throwUnixException(env, errno);
+    }
+    return (jint)port;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_SolarisWatchService_portAssociate
+    (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress, jint events)
+{
+    uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
+
+    if (port_associate((int)port, (int)source, object, (int)events, NULL) == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_SolarisWatchService_portDissociate
+    (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress)
+{
+    uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
+
+    if (port_dissociate((int)port, (int)source, object) == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_SolarisWatchService_portSend(JNIEnv* env, jclass clazz,
+    jint port, jint events)
+{
+    if (port_send((int)port, (int)events, NULL) == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_SolarisWatchService_portGetn(JNIEnv* env, jclass clazz,
+    jint port, jlong arrayAddress, jint max)
+{
+    uint_t n = 1;
+    port_event_t* list = (port_event_t*)jlong_to_ptr(arrayAddress);
+
+    if (port_getn((int)port, list, (uint_t)max, &n, NULL) == -1) {
+        throwUnixException(env, errno);
+    }
+    return (jint)n;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/fs/UnixCopyFile.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jlong.h"
+
+#include <unistd.h>
+#include <errno.h>
+
+#include "sun_nio_fs_UnixCopyFile.h"
+
+#define RESTARTABLE(_cmd, _result) do { \
+  do { \
+    _result = _cmd; \
+  } while((_result == -1) && (errno == EINTR)); \
+} while(0)
+
+static void throwUnixException(JNIEnv* env, int errnum) {
+    jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
+        "(I)V", errnum);
+    if (x != NULL) {
+        (*env)->Throw(env, x);
+    }
+}
+
+/**
+ * Transfer all bytes from src to dst via user-space buffers
+ */
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixCopyFile_transfer
+    (JNIEnv* env, jclass this, jint dst, jint src, jlong cancelAddress)
+{
+    char buf[8192];
+    volatile jint* cancel = (jint*)jlong_to_ptr(cancelAddress);
+
+    for (;;) {
+        ssize_t n, pos, len;
+        RESTARTABLE(read((int)src, &buf, sizeof(buf)), n);
+        if (n <= 0) {
+            if (n < 0)
+                throwUnixException(env, errno);
+            return;
+        }
+        if (cancel != NULL && *cancel != 0) {
+            throwUnixException(env, ECANCELED);
+            return;
+        }
+        pos = 0;
+        len = n;
+        do {
+            char* bufp = buf;
+            bufp += pos;
+            RESTARTABLE(write((int)dst, bufp, len), n);
+            if (n == -1) {
+                throwUnixException(env, errno);
+                return;
+            }
+            pos += n;
+            len -= n;
+        } while (len > 0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,1080 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/time.h>
+
+#ifdef __solaris__
+#include <strings.h>
+#include <sys/mnttab.h>
+#include <sys/mkdev.h>
+#endif
+
+#ifdef __linux__
+#include <string.h>
+#include <mntent.h>
+#endif
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jlong.h"
+
+#include "sun_nio_fs_UnixNativeDispatcher.h"
+
+#define RESTARTABLE(_cmd, _result) do { \
+  do { \
+    _result = _cmd; \
+  } while((_result == -1) && (errno == EINTR)); \
+} while(0)
+
+static jfieldID attrs_st_mode;
+static jfieldID attrs_st_ino;
+static jfieldID attrs_st_dev;
+static jfieldID attrs_st_rdev;
+static jfieldID attrs_st_nlink;
+static jfieldID attrs_st_uid;
+static jfieldID attrs_st_gid;
+static jfieldID attrs_st_size;
+static jfieldID attrs_st_atime;
+static jfieldID attrs_st_mtime;
+static jfieldID attrs_st_ctime;
+
+static jfieldID attrs_f_frsize;
+static jfieldID attrs_f_blocks;
+static jfieldID attrs_f_bfree;
+static jfieldID attrs_f_bavail;
+
+static jfieldID entry_name;
+static jfieldID entry_dir;
+static jfieldID entry_fstype;
+static jfieldID entry_options;
+static jfieldID entry_dev;
+
+/**
+ * System calls that may not be available at build time.
+ */
+typedef int openat64_func(int, const char *, int, ...);
+typedef int fstatat64_func(int, const char *, struct stat64 *, int);
+typedef int unlinkat_func(int, const char*, int);
+typedef int renameat_func(int, const char*, int, const char*);
+typedef int futimesat_func(int, const char *, const struct timeval *);
+typedef DIR* fdopendir_func(int);
+
+static openat64_func* my_openat64_func = NULL;
+static fstatat64_func* my_fstatat64_func = NULL;
+static unlinkat_func* my_unlinkat_func = NULL;
+static renameat_func* my_renameat_func = NULL;
+static futimesat_func* my_futimesat_func = NULL;
+static fdopendir_func* my_fdopendir_func = NULL;
+
+/**
+ * fstatat missing from glibc on Linux. Temporary workaround
+ * for x86/x64.
+ */
+#if defined(__linux__) && defined(__i386)
+#define FSTATAT64_SYSCALL_AVAILABLE
+static int fstatat64_wrapper(int dfd, const char *path,
+                             struct stat64 *statbuf, int flag)
+{
+    #ifndef __NR_fstatat64
+    #define __NR_fstatat64  300
+    #endif
+    return syscall(__NR_fstatat64, dfd, path, statbuf, flag);
+}
+#endif
+
+#if defined(__linux__) && defined(__x86_64__)
+#define FSTATAT64_SYSCALL_AVAILABLE
+static int fstatat64_wrapper(int dfd, const char *path,
+                             struct stat64 *statbuf, int flag)
+{
+    #ifndef __NR_newfstatat
+    #define __NR_newfstatat  262
+    #endif
+    return syscall(__NR_newfstatat, dfd, path, statbuf, flag);
+}
+#endif
+
+/**
+ * Call this to throw an internal UnixException when a system/library
+ * call fails
+ */
+static void throwUnixException(JNIEnv* env, int errnum) {
+    jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
+        "(I)V", errnum);
+    if (x != NULL) {
+        (*env)->Throw(env, x);
+    }
+}
+
+/**
+ * Initialize jfieldIDs
+ */
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_initIDs(JNIEnv* env, jclass this)
+{
+    jclass clazz;
+
+    clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileAttributes");
+    if (clazz == NULL) {
+        return;
+    }
+    attrs_st_mode = (*env)->GetFieldID(env, clazz, "st_mode", "I");
+    attrs_st_ino = (*env)->GetFieldID(env, clazz, "st_ino", "J");
+    attrs_st_dev = (*env)->GetFieldID(env, clazz, "st_dev", "J");
+    attrs_st_rdev = (*env)->GetFieldID(env, clazz, "st_rdev", "J");
+    attrs_st_nlink = (*env)->GetFieldID(env, clazz, "st_nlink", "I");
+    attrs_st_uid = (*env)->GetFieldID(env, clazz, "st_uid", "I");
+    attrs_st_gid = (*env)->GetFieldID(env, clazz, "st_gid", "I");
+    attrs_st_size = (*env)->GetFieldID(env, clazz, "st_size", "J");
+    attrs_st_atime = (*env)->GetFieldID(env, clazz, "st_atime", "J");
+    attrs_st_mtime = (*env)->GetFieldID(env, clazz, "st_mtime", "J");
+    attrs_st_ctime = (*env)->GetFieldID(env, clazz, "st_ctime", "J");
+
+    clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes");
+    if (clazz == NULL) {
+        return;
+    }
+    attrs_f_frsize = (*env)->GetFieldID(env, clazz, "f_frsize", "J");
+    attrs_f_blocks = (*env)->GetFieldID(env, clazz, "f_blocks", "J");
+    attrs_f_bfree = (*env)->GetFieldID(env, clazz, "f_bfree", "J");
+    attrs_f_bavail = (*env)->GetFieldID(env, clazz, "f_bavail", "J");
+
+    clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry");
+    if (clazz == NULL) {
+        return;
+    }
+    entry_name = (*env)->GetFieldID(env, clazz, "name", "[B");
+    entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B");
+    entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B");
+    entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B");
+    entry_dev = (*env)->GetFieldID(env, clazz, "dev", "J");
+
+    /* system calls that might not be available at build time */
+
+#if defined(__solaris__) && defined(_LP64)
+    /* Solaris 64-bit does not have openat64/fstatat64 */
+    my_openat64_func = (openat64_func*)dlsym(RTLD_DEFAULT, "openat");
+    my_fstatat64_func = (fstatat64_func*)dlsym(RTLD_DEFAULT, "fstatat");
+#else
+    my_openat64_func = (openat64_func*) dlsym(RTLD_DEFAULT, "openat64");
+    my_fstatat64_func = (fstatat64_func*) dlsym(RTLD_DEFAULT, "fstatat64");
+#endif
+    my_unlinkat_func = (unlinkat_func*) dlsym(RTLD_DEFAULT, "unlinkat");
+    my_renameat_func = (renameat_func*) dlsym(RTLD_DEFAULT, "renameat");
+    my_futimesat_func = (futimesat_func*) dlsym(RTLD_DEFAULT, "futimesat");
+    my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir");
+
+#if defined(FSTATAT64_SYSCALL_AVAILABLE)
+    /* fstatat64 missing from glibc */
+    if (my_fstatat64_func == NULL)
+        my_fstatat64_func = (fstatat64_func*)&fstatat64_wrapper;
+#endif
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_getcwd(JNIEnv* env, jclass this) {
+    jbyteArray result = NULL;
+    char buf[PATH_MAX+1];
+
+    /* EINTR not listed as a possible error */
+    char* cwd = getcwd(buf, sizeof(buf));
+    if (cwd == NULL) {
+        throwUnixException(env, errno);
+    } else {
+        jsize len = (jsize)strlen(buf);
+        result = (*env)->NewByteArray(env, len);
+        if (result != NULL) {
+            (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)buf);
+        }
+    }
+    return result;
+}
+
+JNIEXPORT jbyteArray
+Java_sun_nio_fs_UnixNativeDispatcher_strerror(JNIEnv* env, jclass this, jint error)
+{
+    char* msg;
+    jsize len;
+    jbyteArray bytes;
+
+    msg = strerror((int)error);
+    len = strlen(msg);
+    bytes = (*env)->NewByteArray(env, len);
+    if (bytes != NULL) {
+        (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)msg);
+    }
+    return bytes;
+}
+
+JNIEXPORT jint
+Java_sun_nio_fs_UnixNativeDispatcher_dup(JNIEnv* env, jclass this, jint fd) {
+
+    int res = -1;
+
+    RESTARTABLE(dup((int)fd), res);
+    if (fd == -1) {
+        throwUnixException(env, errno);
+    }
+    return (jint)res;
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_fopen0(JNIEnv* env, jclass this,
+    jlong pathAddress, jlong modeAddress)
+{
+    FILE* fp = NULL;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+    const char* mode = (const char*)jlong_to_ptr(modeAddress);
+
+    do {
+        fp = fopen(path, mode);
+    } while (fp == NULL && errno == EINTR);
+
+    if (fp == NULL) {
+        throwUnixException(env, errno);
+    }
+
+    return ptr_to_jlong(fp);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_fclose(JNIEnv* env, jclass this, jlong stream)
+{
+    int res;
+    FILE* fp = jlong_to_ptr(stream);
+
+    do {
+        res = fclose(fp);
+    } while (res == EOF && errno == EINTR);
+    if (res == EOF) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_open0(JNIEnv* env, jclass this,
+    jlong pathAddress, jint oflags, jint mode)
+{
+    jint fd;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    RESTARTABLE(open64(path, (int)oflags, (mode_t)mode), fd);
+    if (fd == -1) {
+        throwUnixException(env, errno);
+    }
+    return fd;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_openat0(JNIEnv* env, jclass this, jint dfd,
+    jlong pathAddress, jint oflags, jint mode)
+{
+    jint fd;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    if (my_openat64_func == NULL) {
+        JNU_ThrowInternalError(env, "should not reach here");
+        return -1;
+    }
+
+    RESTARTABLE((*my_openat64_func)(dfd, path, (int)oflags, (mode_t)mode), fd);
+    if (fd == -1) {
+        throwUnixException(env, errno);
+    }
+    return fd;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_close(JNIEnv* env, jclass this, jint fd) {
+    int err;
+    /* TDB - need to decide if EIO and other errors should cause exception */
+    RESTARTABLE(close((int)fd), err);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_read(JNIEnv* env, jclass this, jint fd,
+    jlong address, jint nbytes)
+{
+    ssize_t n;
+    void* bufp = jlong_to_ptr(address);
+    RESTARTABLE(read((int)fd, bufp, (size_t)nbytes), n);
+    if (n == -1) {
+        throwUnixException(env, errno);
+    }
+    return (jint)n;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_write(JNIEnv* env, jclass this, jint fd,
+    jlong address, jint nbytes)
+{
+    ssize_t n;
+    void* bufp = jlong_to_ptr(address);
+    RESTARTABLE(write((int)fd, bufp, (size_t)nbytes), n);
+    if (n == -1) {
+        throwUnixException(env, errno);
+    }
+    return (jint)n;
+}
+
+/**
+ * Copy stat64 members into sun.nio.fs.UnixFileAttributes
+ */
+static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) {
+    (*env)->SetIntField(env, attrs, attrs_st_mode, (jint)buf->st_mode);
+    (*env)->SetLongField(env, attrs, attrs_st_ino, (jlong)buf->st_ino);
+    (*env)->SetLongField(env, attrs, attrs_st_dev, (jlong)buf->st_dev);
+    (*env)->SetLongField(env, attrs, attrs_st_rdev, (jlong)buf->st_rdev);
+    (*env)->SetIntField(env, attrs, attrs_st_nlink, (jint)buf->st_nlink);
+    (*env)->SetIntField(env, attrs, attrs_st_uid, (jint)buf->st_uid);
+    (*env)->SetIntField(env, attrs, attrs_st_gid, (jint)buf->st_gid);
+    (*env)->SetLongField(env, attrs, attrs_st_size, (jlong)buf->st_size);
+    (*env)->SetLongField(env, attrs, attrs_st_atime, (jlong)buf->st_atime * 1000);
+    (*env)->SetLongField(env, attrs, attrs_st_mtime, (jlong)buf->st_mtime * 1000);
+    (*env)->SetLongField(env, attrs, attrs_st_ctime, (jlong)buf->st_ctime * 1000);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this,
+    jlong pathAddress, jobject attrs)
+{
+    int err;
+    struct stat64 buf;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    RESTARTABLE(stat64(path, &buf), err);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    } else {
+        prepAttributes(env, &buf, attrs);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_lstat0(JNIEnv* env, jclass this,
+    jlong pathAddress, jobject attrs)
+{
+    int err;
+    struct stat64 buf;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    RESTARTABLE(lstat64(path, &buf), err);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    } else {
+        prepAttributes(env, &buf, attrs);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_fstat(JNIEnv* env, jclass this, jint fd,
+    jobject attrs)
+{
+    int err;
+    struct stat64 buf;
+
+    RESTARTABLE(fstat64((int)fd, &buf), err);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    } else {
+        prepAttributes(env, &buf, attrs);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd,
+    jlong pathAddress, jint flag, jobject attrs)
+{
+    int err;
+    struct stat64 buf;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    if (my_fstatat64_func == NULL) {
+        JNU_ThrowInternalError(env, "should not reach here");
+        return;
+    }
+    RESTARTABLE((*my_fstatat64_func)((int)dfd, path, &buf, (int)flag), err);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    } else {
+        prepAttributes(env, &buf, attrs);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_chmod0(JNIEnv* env, jclass this,
+    jlong pathAddress, jint mode)
+{
+    int err;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    RESTARTABLE(chmod(path, (mode_t)mode), err);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_fchmod(JNIEnv* env, jclass this, jint filedes,
+    jint mode)
+{
+    int err;
+
+    RESTARTABLE(fchmod((int)filedes, (mode_t)mode), err);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_chown0(JNIEnv* env, jclass this,
+    jlong pathAddress, jint uid, jint gid)
+{
+    int err;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    RESTARTABLE(chown(path, (uid_t)uid, (gid_t)gid), err);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_lchown0(JNIEnv* env, jclass this, jlong pathAddress, jint uid, jint gid)
+{
+    int err;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    RESTARTABLE(lchown(path, (uid_t)uid, (gid_t)gid), err);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_fchown(JNIEnv* env, jclass this, jint filedes, jint uid, jint gid)
+{
+    int err;
+
+    RESTARTABLE(fchown(filedes, (uid_t)uid, (gid_t)gid), err);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_utimes0(JNIEnv* env, jclass this,
+    jlong pathAddress, jlong accessTime, jlong modificationTime)
+{
+    int err;
+    struct timeval times[2];
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    times[0].tv_sec = accessTime / 1000;
+    times[0].tv_usec = (accessTime % 1000) * 1000;
+
+    times[1].tv_sec = modificationTime / 1000;
+    times[1].tv_usec = (modificationTime % 1000) * 1000;
+
+    RESTARTABLE(utimes(path, &times[0]), err);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint filedes,
+    jlong accessTime, jlong modificationTime)
+{
+    struct timeval times[2];
+    int err = 0;
+
+    times[0].tv_sec = accessTime / 1000;
+    times[0].tv_usec = (accessTime % 1000) * 1000;
+
+    times[1].tv_sec = modificationTime / 1000;
+    times[1].tv_usec = (modificationTime % 1000) * 1000;
+
+    if (my_futimesat_func != NULL) {
+        RESTARTABLE((*my_futimesat_func)(filedes, NULL, &times[0]), err);
+        if (err == -1) {
+            throwUnixException(env, errno);
+        }
+    }
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this,
+    jlong pathAddress)
+{
+    DIR* dir;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    /* EINTR not listed as a possible error */
+    dir = opendir(path);
+    if (dir == NULL) {
+        throwUnixException(env, errno);
+    }
+    return ptr_to_jlong(dir);
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_fdopendir(JNIEnv* env, jclass this, int dfd) {
+    DIR* dir;
+
+    if (my_fdopendir_func == NULL) {
+        JNU_ThrowInternalError(env, "should not reach here");
+        return (jlong)-1;
+    }
+
+    /* EINTR not listed as a possible error */
+    dir = (*my_fdopendir_func)((int)dfd);
+    if (dir == NULL) {
+        throwUnixException(env, errno);
+    }
+    return ptr_to_jlong(dir);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_closedir(JNIEnv* env, jclass this, jlong dir) {
+    int err;
+    DIR* dirp = jlong_to_ptr(dir);
+
+    RESTARTABLE(closedir(dirp), err);
+    if (errno == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_readdir(JNIEnv* env, jclass this, jlong value) {
+    char entry[sizeof(struct dirent64) + PATH_MAX + 1];
+    struct dirent64* ptr = (struct dirent64*)&entry;
+    struct dirent64* result;
+    int res;
+    DIR* dirp = jlong_to_ptr(value);
+
+    /* EINTR not listed as a possible error */
+    /* TDB: reentrant version probably not required here */
+    res = readdir64_r(dirp, ptr, &result);
+    if (res != 0) {
+        throwUnixException(env, res);
+        return NULL;
+    } else {
+        if (result == NULL) {
+            return NULL;
+        } else {
+            jsize len = strlen(ptr->d_name);
+            jbyteArray bytes = (*env)->NewByteArray(env, len);
+            if (bytes != NULL) {
+                (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)(ptr->d_name));
+            }
+            return bytes;
+        }
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_mkdir0(JNIEnv* env, jclass this,
+    jlong pathAddress, jint mode)
+{
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    /* EINTR not listed as a possible error */
+    if (mkdir(path, (mode_t)mode) == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_rmdir0(JNIEnv* env, jclass this,
+    jlong pathAddress)
+{
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    /* EINTR not listed as a possible error */
+    if (rmdir(path) == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_link0(JNIEnv* env, jclass this,
+    jlong existingAddress, jlong newAddress)
+{
+    int err;
+    const char* existing = (const char*)jlong_to_ptr(existingAddress);
+    const char* newname = (const char*)jlong_to_ptr(newAddress);
+
+    RESTARTABLE(link(existing, newname), err);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_unlink0(JNIEnv* env, jclass this,
+    jlong pathAddress)
+{
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    /* EINTR not listed as a possible error */
+    if (unlink(path) == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_unlinkat0(JNIEnv* env, jclass this, jint dfd,
+                                               jlong pathAddress, jint flags)
+{
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    if (my_unlinkat_func == NULL) {
+        JNU_ThrowInternalError(env, "should not reach here");
+        return;
+    }
+
+    /* EINTR not listed as a possible error */
+    if ((*my_unlinkat_func)((int)dfd, path, (int)flags) == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_rename0(JNIEnv* env, jclass this,
+    jlong fromAddress, jlong toAddress)
+{
+    const char* from = (const char*)jlong_to_ptr(fromAddress);
+    const char* to = (const char*)jlong_to_ptr(toAddress);
+
+    /* EINTR not listed as a possible error */
+    if (rename(from, to) == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_renameat0(JNIEnv* env, jclass this,
+    jint fromfd, jlong fromAddress, jint tofd, jlong toAddress)
+{
+    const char* from = (const char*)jlong_to_ptr(fromAddress);
+    const char* to = (const char*)jlong_to_ptr(toAddress);
+
+    if (my_renameat_func == NULL) {
+        JNU_ThrowInternalError(env, "should not reach here");
+        return;
+    }
+
+    /* EINTR not listed as a possible error */
+    if ((*my_renameat_func)((int)fromfd, from, (int)tofd, to) == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_symlink0(JNIEnv* env, jclass this,
+    jlong targetAddress, jlong linkAddress)
+{
+    const char* target = (const char*)jlong_to_ptr(targetAddress);
+    const char* link = (const char*)jlong_to_ptr(linkAddress);
+
+    /* EINTR not listed as a possible error */
+    if (symlink(target, link) == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_readlink0(JNIEnv* env, jclass this,
+    jlong pathAddress)
+{
+    jbyteArray result = NULL;
+    char target[PATH_MAX+1];
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    /* EINTR not listed as a possible error */
+    int n = readlink(path, target, sizeof(target));
+    if (n == -1) {
+        throwUnixException(env, errno);
+    } else {
+        jsize len;
+        if (n == sizeof(target)) {
+            n--;
+        }
+        target[n] = '\0';
+        len = (jsize)strlen(target);
+        result = (*env)->NewByteArray(env, len);
+        if (result != NULL) {
+            (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)target);
+        }
+    }
+    return result;
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_realpath0(JNIEnv* env, jclass this,
+    jlong pathAddress)
+{
+    jbyteArray result = NULL;
+    char resolved[PATH_MAX+1];
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    /* EINTR not listed as a possible error */
+    if (realpath(path, resolved) == NULL) {
+        throwUnixException(env, errno);
+    } else {
+        jsize len = (jsize)strlen(resolved);
+        result = (*env)->NewByteArray(env, len);
+        if (result != NULL) {
+            (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)resolved);
+        }
+    }
+    return result;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this,
+    jlong pathAddress, jint amode)
+{
+    int err;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    RESTARTABLE(access(path, (int)amode), err);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_statvfs0(JNIEnv* env, jclass this,
+    jlong pathAddress, jobject attrs)
+{
+    int err;
+    struct statvfs64 buf;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+
+    RESTARTABLE(statvfs64(path, &buf), err);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    } else {
+        (*env)->SetLongField(env, attrs, attrs_f_frsize, long_to_jlong(buf.f_frsize));
+        (*env)->SetLongField(env, attrs, attrs_f_blocks, long_to_jlong(buf.f_blocks));
+        (*env)->SetLongField(env, attrs, attrs_f_bfree,  long_to_jlong(buf.f_bfree));
+        (*env)->SetLongField(env, attrs, attrs_f_bavail, long_to_jlong(buf.f_bavail));
+    }
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_pathconf0(JNIEnv* env, jclass this,
+    jlong pathAddress, jint name)
+{
+    long err;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    err = pathconf(path, (int)name);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    }
+    return (jlong)err;
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_fpathconf(JNIEnv* env, jclass this,
+    jint fd, jint name)
+{
+    long err;
+
+    err = fpathconf((int)fd, (int)name);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    }
+    return (jlong)err;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_mknod0(JNIEnv* env, jclass this,
+    jlong pathAddress, jint mode, jlong dev)
+{
+    int err;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    RESTARTABLE(mknod(path, (mode_t)mode, (dev_t)dev), err);
+    if (err == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_getpwuid(JNIEnv* env, jclass this, jint uid)
+{
+    jbyteArray result = NULL;
+    int buflen;
+
+    buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX);
+    if (buflen == -1) {
+        throwUnixException(env, errno);
+    } else {
+        char* pwbuf = (char*)malloc(buflen);
+        if (pwbuf == NULL) {
+            JNU_ThrowOutOfMemoryError(env, "native heap");
+        } else {
+            struct passwd pwent;
+            struct passwd* p;
+            int res = 0;
+
+#ifdef __solaris__
+            p = getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen);
+#else
+            res = getpwuid_r((uid_t)uid, &pwent, pwbuf, (size_t)buflen, &p);
+#endif
+
+            if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') {
+                throwUnixException(env, errno);
+            } else {
+                jsize len = strlen(p->pw_name);
+                result = (*env)->NewByteArray(env, len);
+                if (result != NULL) {
+                    (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(p->pw_name));
+                }
+            }
+            free(pwbuf);
+        }
+    }
+    return result;
+}
+
+
+JNIEXPORT jbyteArray JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_getgrgid(JNIEnv* env, jclass this, jint gid)
+{
+    jbyteArray result = NULL;
+    int buflen;
+
+    buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX);
+    if (buflen == -1) {
+        throwUnixException(env, errno);
+    } else {
+        char* grbuf = (char*)malloc(buflen);
+        if (grbuf == NULL) {
+            JNU_ThrowOutOfMemoryError(env, "native heap");
+        } else {
+            struct group grent;
+            struct group* g;
+            int res = 0;
+
+#ifdef __solaris__
+            g = getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen);
+#else
+            res = getgrgid_r((gid_t)gid, &grent, grbuf, (size_t)buflen, &g);
+#endif
+            if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') {
+                throwUnixException(env, errno);
+            } else {
+                jsize len = strlen(g->gr_name);
+                result = (*env)->NewByteArray(env, len);
+                if (result != NULL) {
+                    (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(g->gr_name));
+                }
+            }
+            free(grbuf);
+        }
+    }
+    return result;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_getpwnam0(JNIEnv* env, jclass this,
+    jlong nameAddress)
+{
+    jint uid = -1;
+    int buflen;
+    char* pwbuf;
+    struct passwd pwent;
+    struct passwd* p;
+    int res = 0;
+    const char* name = (const char*)jlong_to_ptr(nameAddress);
+
+    buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX);
+    if (buflen == -1) {
+        throwUnixException(env, errno);
+        return -1;
+    }
+    pwbuf = (char*)malloc(buflen);
+    if (pwbuf == NULL) {
+        JNU_ThrowOutOfMemoryError(env, "native heap");
+        return -1;
+    }
+
+#ifdef __solaris__
+    p = getpwnam_r(name, &pwent, pwbuf, (size_t)buflen);
+#else
+    res = getpwnam_r(name, &pwent, pwbuf, (size_t)buflen, &p);
+#endif
+
+    if (res != 0 || p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') {
+        /* not found or error */
+    } else {
+        uid = p->pw_uid;
+    }
+
+    free(pwbuf);
+
+    return uid;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this,
+    jlong nameAddress)
+{
+    jint gid = -1;
+    int buflen;
+    char* grbuf;
+    struct group grent;
+    struct group* g;
+    int res = 0;
+    const char* name = (const char*)jlong_to_ptr(nameAddress);
+
+    buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX);
+    if (buflen == -1) {
+        throwUnixException(env, errno);
+        return -1;
+    }
+    grbuf = (char*)malloc(buflen);
+    if (grbuf == NULL) {
+        JNU_ThrowOutOfMemoryError(env, "native heap");
+        return -1;
+    }
+
+#ifdef __solaris__
+    g = getgrnam_r(name, &grent, grbuf, (size_t)buflen);
+#else
+    res = getgrnam_r(name, &grent, grbuf, (size_t)buflen, &g);
+#endif
+
+    if (res != 0 || g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') {
+        /* not found or error */
+    } else {
+        gid = g->gr_gid;
+    }
+    free(grbuf);
+
+    return gid;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_UnixNativeDispatcher_getextmntent(JNIEnv* env, jclass this,
+    jlong value, jobject entry)
+{
+#ifdef __solaris__
+    struct extmnttab ent;
+#else
+    struct mntent ent;
+    char buf[1024];
+    int buflen = sizeof(buf);
+    struct mntent* m;
+#endif
+    FILE* fp = jlong_to_ptr(value);
+    jsize len;
+    jbyteArray bytes;
+    char* name;
+    char* dir;
+    char* fstype;
+    char* options;
+    dev_t dev;
+
+#ifdef __solaris__
+    if (getextmntent(fp, &ent, 0))
+        return -1;
+    name = ent.mnt_special;
+    dir = ent.mnt_mountp;
+    fstype = ent.mnt_fstype;
+    options = ent.mnt_mntopts;
+    dev = makedev(ent.mnt_major, ent.mnt_minor);
+    if (dev == NODEV) {
+        /* possible bug on Solaris 8 and 9 */
+        throwUnixException(env, errno);
+        return -1;
+    }
+#else
+    m = getmntent_r(fp, &ent, (char*)&buf, buflen);
+    if (m == NULL)
+        return -1;
+    name = m->mnt_fsname;
+    dir = m->mnt_dir;
+    fstype = m->mnt_type;
+    options = m->mnt_opts;
+    dev = 0;
+#endif
+
+    len = strlen(name);
+    bytes = (*env)->NewByteArray(env, len);
+    if (bytes == NULL)
+        return -1;
+    (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)name);
+    (*env)->SetObjectField(env, entry, entry_name, bytes);
+
+    len = strlen(dir);
+    bytes = (*env)->NewByteArray(env, len);
+    if (bytes == NULL)
+        return -1;
+    (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)dir);
+    (*env)->SetObjectField(env, entry, entry_dir, bytes);
+
+    len = strlen(fstype);
+    bytes = (*env)->NewByteArray(env, len);
+    if (bytes == NULL)
+        return -1;
+    (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype);
+    (*env)->SetObjectField(env, entry, entry_fstype, bytes);
+
+    len = strlen(options);
+    bytes = (*env)->NewByteArray(env, len);
+    if (bytes == NULL)
+        return -1;
+    (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)options);
+    (*env)->SetObjectField(env, entry, entry_options, bytes);
+
+    if (dev != 0)
+        (*env)->SetLongField(env, entry, entry_dev, (jlong)dev);
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/fs/genSolarisConstants.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/acl.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+
+/**
+ * Generates sun.nio.fs.SolarisConstants
+ */
+
+static void out(char* s) {
+    printf("%s\n", s);
+}
+
+static void emit(char* name, int value) {
+    printf("    static final int %s = %d;\n", name, value);
+}
+
+static void emitX(char* name, int value) {
+    printf("    static final int %s = 0x%x;\n", name, value);
+}
+
+#define DEF(X) emit(#X, X);
+#define DEFX(X) emitX(#X, X);
+
+int main(int argc, const char* argv[]) {
+    out("// AUTOMATICALLY GENERATED FILE - DO NOT EDIT                                  ");
+    out("package sun.nio.fs;                                                            ");
+    out("class SolarisConstants {                                                       ");
+    out("    private SolarisConstants() { }                                             ");
+
+    // extended attributes
+    DEFX(O_XATTR);
+    DEF(_PC_XATTR_ENABLED);
+
+    // ACL configuration
+    DEF(_PC_ACL_ENABLED);
+    DEFX(_ACL_ACE_ENABLED);
+
+    // ACL commands
+    DEFX(ACE_GETACL);
+    DEFX(ACE_SETACL);
+
+    // ACL mask/flags/types
+    DEFX(ACE_ACCESS_ALLOWED_ACE_TYPE);
+    DEFX(ACE_ACCESS_DENIED_ACE_TYPE);
+    DEFX(ACE_SYSTEM_AUDIT_ACE_TYPE);
+    DEFX(ACE_SYSTEM_ALARM_ACE_TYPE);
+    DEFX(ACE_READ_DATA);
+    DEFX(ACE_LIST_DIRECTORY);
+    DEFX(ACE_WRITE_DATA);
+    DEFX(ACE_ADD_FILE);
+    DEFX(ACE_APPEND_DATA);
+    DEFX(ACE_ADD_SUBDIRECTORY);
+    DEFX(ACE_READ_NAMED_ATTRS);
+    DEFX(ACE_WRITE_NAMED_ATTRS);
+    DEFX(ACE_EXECUTE);
+    DEFX(ACE_DELETE_CHILD);
+    DEFX(ACE_READ_ATTRIBUTES);
+    DEFX(ACE_WRITE_ATTRIBUTES);
+    DEFX(ACE_DELETE);
+    DEFX(ACE_READ_ACL);
+    DEFX(ACE_WRITE_ACL);
+    DEFX(ACE_WRITE_OWNER);
+    DEFX(ACE_SYNCHRONIZE);
+    DEFX(ACE_FILE_INHERIT_ACE);
+    DEFX(ACE_DIRECTORY_INHERIT_ACE);
+    DEFX(ACE_NO_PROPAGATE_INHERIT_ACE);
+    DEFX(ACE_INHERIT_ONLY_ACE);
+    DEFX(ACE_SUCCESSFUL_ACCESS_ACE_FLAG);
+    DEFX(ACE_FAILED_ACCESS_ACE_FLAG);
+    DEFX(ACE_IDENTIFIER_GROUP);
+    DEFX(ACE_OWNER);
+    DEFX(ACE_GROUP);
+    DEFX(ACE_EVERYONE);
+
+    out("}                                                                              ");
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/fs/genUnixConstants.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+
+/**
+ * Generates sun.nio.fs.UnixConstants
+ */
+
+static void out(char* s) {
+    printf("%s\n", s);
+}
+
+static void emit(char* name, int value) {
+    printf("    static final int %s = %d;\n", name, value);
+}
+
+static void emitX(char* name, int value) {
+    printf("    static final int %s = 0x%x;\n", name, value);
+}
+
+#define DEF(X) emit(#X, X);
+#define DEFX(X) emitX(#X, X);
+
+int main(int argc, const char* argv[]) {
+    out("// AUTOMATICALLY GENERATED FILE - DO NOT EDIT                                  ");
+    out("package sun.nio.fs;                                                            ");
+    out("class UnixConstants {                                                          ");
+    out("    private UnixConstants() { }                                                ");
+
+    // open flags
+    DEF(O_RDONLY);
+    DEF(O_WRONLY);
+    DEF(O_RDWR);
+    DEFX(O_APPEND);
+    DEFX(O_CREAT);
+    DEFX(O_EXCL);
+    DEFX(O_TRUNC);
+    DEFX(O_SYNC);
+    DEFX(O_DSYNC);
+    DEFX(O_NOFOLLOW);
+
+    // flags used with openat/unlinkat/etc.
+#ifdef __solaris__
+    DEFX(AT_SYMLINK_NOFOLLOW);
+    DEFX(AT_REMOVEDIR);
+#endif
+#ifdef __linux__
+    emitX("AT_SYMLINK_NOFOLLOW", 0x100);        // since 2.6.16
+    emitX("AT_REMOVEDIR", 0x200);
+#endif
+
+    // mode masks
+    emitX("S_IAMB",
+         (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH));
+    DEF(S_IRUSR);
+    DEF(S_IWUSR);
+    DEF(S_IXUSR);
+    DEF(S_IRGRP);
+    DEF(S_IWGRP);
+    DEF(S_IXGRP);
+    DEF(S_IROTH);
+    DEF(S_IWOTH);
+    DEF(S_IXOTH);
+    DEFX(S_IFMT);
+    DEFX(S_IFREG);
+    DEFX(S_IFDIR);
+    DEFX(S_IFLNK);
+    DEFX(S_IFCHR);
+    DEFX(S_IFBLK);
+    DEFX(S_IFIFO);
+
+    // access modes
+    DEF(R_OK);
+    DEF(W_OK);
+    DEF(X_OK);
+    DEF(F_OK);
+
+    // errors
+    DEF(ENOENT);
+    DEF(EACCES);
+    DEF(EEXIST);
+    DEF(ENOTDIR);
+    DEF(EINVAL);
+    DEF(EXDEV);
+    DEF(EISDIR);
+    DEF(ENOTEMPTY);
+    DEF(ENOSPC);
+    DEF(EAGAIN);
+    DEF(ENOSYS);
+    DEF(ELOOP);
+    DEF(EROFS);
+    DEF(ENODATA);
+    DEF(ERANGE);
+
+    out("}                                                                              ");
+
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+
+/**
+ * Creates this platform's default asynchronous channel provider
+ */
+
+public class DefaultAsynchronousChannelProvider {
+    private DefaultAsynchronousChannelProvider() { }
+
+    /**
+     * Returns the default AsynchronousChannelProvider.
+     */
+    public static AsynchronousChannelProvider create() {
+        return new WindowsAsynchronousChannelProvider();
+    }
+}
--- a/jdk/src/windows/classes/sun/nio/ch/FileDispatcher.java	Wed Feb 11 13:16:53 2009 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-/*
- * Copyright 2000-2003 Sun Microsystems, Inc.  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.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.nio.ch;
-
-import java.io.*;
-
-
-/**
- * Allows different platforms to call different native methods
- * for read and write operations.
- */
-
-class FileDispatcher extends NativeDispatcher
-{
-
-    static {
-        Util.load();
-    }
-
-    int read(FileDescriptor fd, long address, int len)
-        throws IOException
-    {
-        return read0(fd, address, len);
-    }
-
-    int pread(FileDescriptor fd, long address, int len,
-                             long position, Object lock) throws IOException
-    {
-        synchronized(lock) {
-            return pread0(fd, address, len, position);
-        }
-    }
-
-    long readv(FileDescriptor fd, long address, int len) throws IOException {
-        return readv0(fd, address, len);
-    }
-
-    int write(FileDescriptor fd, long address, int len) throws IOException {
-        return write0(fd, address, len);
-    }
-
-    int pwrite(FileDescriptor fd, long address, int len,
-                             long position, Object lock) throws IOException
-    {
-        synchronized(lock) {
-            return pwrite0(fd, address, len, position);
-        }
-    }
-
-    long writev(FileDescriptor fd, long address, int len) throws IOException {
-        return writev0(fd, address, len);
-    }
-
-    void close(FileDescriptor fd) throws IOException {
-        close0(fd);
-    }
-
-    //-- Native methods
-
-    static native int read0(FileDescriptor fd, long address, int len)
-        throws IOException;
-
-    static native int pread0(FileDescriptor fd, long address, int len,
-                             long position) throws IOException;
-
-    static native long readv0(FileDescriptor fd, long address, int len)
-        throws IOException;
-
-    static native int write0(FileDescriptor fd, long address, int len)
-        throws IOException;
-
-    static native int pwrite0(FileDescriptor fd, long address, int len,
-                             long position) throws IOException;
-
-    static native long writev0(FileDescriptor fd, long address, int len)
-        throws IOException;
-
-    static native void close0(FileDescriptor fd) throws IOException;
-
-    static native void closeByHandle(long fd) throws IOException;
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.io.*;
+
+class FileDispatcherImpl extends FileDispatcher
+{
+
+    static {
+        Util.load();
+    }
+
+    int read(FileDescriptor fd, long address, int len)
+        throws IOException
+    {
+        return read0(fd, address, len);
+    }
+
+    int pread(FileDescriptor fd, long address, int len,
+                             long position, Object lock) throws IOException
+    {
+        synchronized(lock) {
+            return pread0(fd, address, len, position);
+        }
+    }
+
+    long readv(FileDescriptor fd, long address, int len) throws IOException {
+        return readv0(fd, address, len);
+    }
+
+    int write(FileDescriptor fd, long address, int len) throws IOException {
+        return write0(fd, address, len);
+    }
+
+    int pwrite(FileDescriptor fd, long address, int len,
+                             long position, Object lock) throws IOException
+    {
+        synchronized(lock) {
+            return pwrite0(fd, address, len, position);
+        }
+    }
+
+    long writev(FileDescriptor fd, long address, int len) throws IOException {
+        return writev0(fd, address, len);
+    }
+
+    int force(FileDescriptor fd, boolean metaData) throws IOException {
+        return force0(fd, metaData);
+    }
+
+    int truncate(FileDescriptor fd, long size) throws IOException {
+        return truncate0(fd, size);
+    }
+
+    long size(FileDescriptor fd) throws IOException {
+        return size0(fd);
+    }
+
+    int lock(FileDescriptor fd, boolean blocking, long pos, long size,
+             boolean shared) throws IOException
+    {
+        return lock0(fd, blocking, pos, size, shared);
+    }
+
+    void release(FileDescriptor fd, long pos, long size) throws IOException {
+        release0(fd, pos, size);
+    }
+
+    void close(FileDescriptor fd) throws IOException {
+        close0(fd);
+    }
+
+    //-- Native methods
+
+    static native int read0(FileDescriptor fd, long address, int len)
+        throws IOException;
+
+    static native int pread0(FileDescriptor fd, long address, int len,
+                             long position) throws IOException;
+
+    static native long readv0(FileDescriptor fd, long address, int len)
+        throws IOException;
+
+    static native int write0(FileDescriptor fd, long address, int len)
+        throws IOException;
+
+    static native int pwrite0(FileDescriptor fd, long address, int len,
+                             long position) throws IOException;
+
+    static native long writev0(FileDescriptor fd, long address, int len)
+        throws IOException;
+
+    static native int force0(FileDescriptor fd, boolean metaData)
+        throws IOException;
+
+    static native int truncate0(FileDescriptor fd, long size)
+        throws IOException;
+
+    static native long size0(FileDescriptor fd) throws IOException;
+
+    static native int lock0(FileDescriptor fd, boolean blocking, long pos,
+                            long size, boolean shared) throws IOException;
+
+    static native void release0(FileDescriptor fd, long pos, long size)
+        throws IOException;
+
+    static native void close0(FileDescriptor fd) throws IOException;
+
+    static native void closeByHandle(long fd) throws IOException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/ch/Iocp.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,437 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import sun.misc.Unsafe;
+
+/**
+ * Windows implementation of AsynchronousChannelGroup encapsulating an I/O
+ * completion port.
+ */
+
+class Iocp extends AsynchronousChannelGroupImpl {
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private static final long INVALID_HANDLE_VALUE  = -1L;
+
+    // maps completion key to channel
+    private final ReadWriteLock keyToChannelLock = new ReentrantReadWriteLock();
+    private final Map<Integer,OverlappedChannel> keyToChannel =
+        new HashMap<Integer,OverlappedChannel>();
+    private int nextCompletionKey;
+
+    // handle to completion port
+    private final long port;
+
+    // true if port has been closed
+    private boolean closed;
+
+    // the set of "stale" OVERLAPPED structures. These OVERLAPPED structures
+    // relate to I/O operations where the completion notification was not
+    // received in a timely manner after the channel is closed.
+    private final Set<Long> staleIoSet = new HashSet<Long>();
+
+    Iocp(AsynchronousChannelProvider provider, ThreadPool pool)
+        throws IOException
+    {
+        super(provider, pool);
+        this.port =
+          createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, fixedThreadCount());
+        this.nextCompletionKey = 1;
+    }
+
+    Iocp start() {
+        startThreads(new EventHandlerTask());
+        return this;
+    }
+
+    /*
+     * Channels implements this interface support overlapped I/O and can be
+     * associated with a completion port.
+     */
+    static interface OverlappedChannel extends Closeable {
+        /**
+         * Returns a reference to the pending I/O result.
+         */
+        <V,A> PendingFuture<V,A> getByOverlapped(long overlapped);
+    }
+
+    // release all resources
+    void implClose() {
+        synchronized (this) {
+            if (closed)
+                return;
+            closed = true;
+        }
+        close0(port);
+        synchronized (staleIoSet) {
+            for (Long ov: staleIoSet) {
+                unsafe.freeMemory(ov);
+            }
+            staleIoSet.clear();
+        }
+    }
+
+    @Override
+    boolean isEmpty() {
+        keyToChannelLock.writeLock().lock();
+        try {
+            return keyToChannel.isEmpty();
+        } finally {
+            keyToChannelLock.writeLock().unlock();
+        }
+    }
+
+    @Override
+    final Object attachForeignChannel(final Channel channel, FileDescriptor fdObj)
+        throws IOException
+    {
+        int key = associate(new OverlappedChannel() {
+            public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
+                return null;
+            }
+            public void close() throws IOException {
+                channel.close();
+            }
+        }, 0L);
+        return Integer.valueOf(key);
+    }
+
+    @Override
+    final void detachForeignChannel(Object key) {
+        disassociate((Integer)key);
+    }
+
+    @Override
+    void closeAllChannels() {
+        /**
+         * On Windows the close operation will close the socket/file handle
+         * and then wait until all outstanding I/O operations have aborted.
+         * This is necessary as each channel's cache of OVERLAPPED structures
+         * can only be freed once all I/O operations have completed. As I/O
+         * completion requires a lookup of the keyToChannel then we must close
+         * the channels when not holding the write lock.
+         */
+        final int MAX_BATCH_SIZE = 32;
+        OverlappedChannel channels[] = new OverlappedChannel[MAX_BATCH_SIZE];
+        int count;
+        do {
+            // grab a batch of up to 32 channels
+            keyToChannelLock.writeLock().lock();
+            count = 0;
+            try {
+                for (Integer key: keyToChannel.keySet()) {
+                    channels[count++] = keyToChannel.get(key);
+                    if (count >= MAX_BATCH_SIZE)
+                        break;
+                }
+            } finally {
+                keyToChannelLock.writeLock().unlock();
+            }
+
+            // close them
+            for (int i=0; i<count; i++) {
+                try {
+                    channels[i].close();
+                } catch (IOException ignore) { }
+            }
+        } while (count > 0);
+    }
+
+    private void wakeup() {
+        try {
+            postQueuedCompletionStatus(port, 0);
+        } catch (IOException e) {
+            // should not happen
+            throw new AssertionError(e);
+        }
+    }
+
+    @Override
+    void executeOnHandlerTask(Runnable task) {
+        synchronized (this) {
+            if (closed)
+                throw new RejectedExecutionException();
+            offerTask(task);
+            wakeup();
+        }
+
+    }
+
+    @Override
+    void shutdownHandlerTasks() {
+        // shutdown all handler threads
+        int nThreads = threadCount();
+        while (nThreads-- > 0) {
+            wakeup();
+        }
+    }
+
+    /**
+     * Associate the given handle with this group
+     */
+    int associate(OverlappedChannel ch, long handle) throws IOException {
+        keyToChannelLock.writeLock().lock();
+
+        // generate a completion key (if not shutdown)
+        int key;
+        try {
+            if (isShutdown())
+                throw new ShutdownChannelGroupException();
+
+            // generate unique key
+            do {
+                key = nextCompletionKey++;
+            } while ((key == 0) || keyToChannel.containsKey(key));
+
+            // associate with I/O completion port
+            if (handle != 0L)
+                createIoCompletionPort(handle, port, key, 0);
+
+            // setup mapping
+            keyToChannel.put(key, ch);
+        } finally {
+            keyToChannelLock.writeLock().unlock();
+        }
+        return key;
+    }
+
+    /**
+     * Disassociate channel from the group.
+     */
+    void disassociate(int key) {
+        boolean checkForShutdown = false;
+
+        keyToChannelLock.writeLock().lock();
+        try {
+            keyToChannel.remove(key);
+
+            // last key to be removed so check if group is shutdown
+            if (keyToChannel.isEmpty())
+                checkForShutdown = true;
+
+        } finally {
+            keyToChannelLock.writeLock().unlock();
+        }
+
+        // continue shutdown
+        if (checkForShutdown && isShutdown()) {
+            try {
+                shutdownNow();
+            } catch (IOException ignore) { }
+        }
+    }
+
+    /**
+     * Invoked when a channel associated with this port is closed before
+     * notifications for all outstanding I/O operations have been received.
+     */
+    void makeStale(Long overlapped) {
+        synchronized (staleIoSet) {
+            staleIoSet.add(overlapped);
+        }
+    }
+
+    /**
+     * Checks if the given OVERLAPPED is stale and if so, releases it.
+     */
+    private void checkIfStale(long ov) {
+        synchronized (staleIoSet) {
+            boolean removed = staleIoSet.remove(ov);
+            if (removed) {
+                unsafe.freeMemory(ov);
+            }
+        }
+    }
+
+    /**
+     * The handler for consuming the result of an asynchronous I/O operation.
+     */
+    static interface ResultHandler {
+        /**
+         * Invoked if the I/O operation completes successfully.
+         */
+        public void completed(int bytesTransferred);
+
+        /**
+         * Invoked if the I/O operation fails.
+         */
+        public void failed(int error, IOException ioe);
+    }
+
+    // Creates IOException for the given I/O error.
+    private static IOException translateErrorToIOException(int error) {
+        String msg = getErrorMessage(error);
+        if (msg == null)
+            msg = "Unknown error: 0x0" + Integer.toHexString(error);
+        return new IOException(msg);
+    }
+
+    /**
+     * Long-running task servicing system-wide or per-file completion port
+     */
+    private class EventHandlerTask implements Runnable {
+        public void run() {
+            Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
+                Invoker.getGroupAndInvokeCount();
+            CompletionStatus ioResult = new CompletionStatus();
+            boolean replaceMe = false;
+
+            try {
+                for (;;) {
+                    // reset invoke count
+                    if (myGroupAndInvokeCount != null)
+                        myGroupAndInvokeCount.resetInvokeCount();
+
+                    // wait for I/O completion event
+                    // A error here is fatal (thread will not be replaced)
+                    replaceMe = false;
+                    try {
+                        getQueuedCompletionStatus(port, ioResult);
+                    } catch (IOException x) {
+                        // should not happen
+                        x.printStackTrace();
+                        return;
+                    }
+
+                    // handle wakeup to execute task or shutdown
+                    if (ioResult.completionKey() == 0 &&
+                        ioResult.overlapped() == 0L)
+                    {
+                        Runnable task = pollTask();
+                        if (task == null) {
+                            // shutdown request
+                            return;
+                        }
+
+                        // run task
+                        // (if error/exception then replace thread)
+                        replaceMe = true;
+                        task.run();
+                        continue;
+                    }
+
+                    // map key to channel
+                    OverlappedChannel ch = null;
+                    keyToChannelLock.readLock().lock();
+                    try {
+                        ch = keyToChannel.get(ioResult.completionKey());
+                        if (ch == null) {
+                            checkIfStale(ioResult.overlapped());
+                            continue;
+                        }
+                    } finally {
+                        keyToChannelLock.readLock().unlock();
+                    }
+
+                    // lookup I/O request
+                    PendingFuture<?,?> result = ch.getByOverlapped(ioResult.overlapped());
+                    if (result == null) {
+                        // we get here if the OVERLAPPED structure is associated
+                        // with an I/O operation on a channel that was closed
+                        // but the I/O operation event wasn't read in a timely
+                        // manner. Alternatively, it may be related to a
+                        // tryLock operation as the OVERLAPPED structures for
+                        // these operations are not in the I/O cache.
+                        checkIfStale(ioResult.overlapped());
+                        continue;
+                    }
+
+                    // synchronize on result in case I/O completed immediately
+                    // and was handled by initiator
+                    synchronized (result) {
+                        if (result.isDone()) {
+                            continue;
+                        }
+                        // not handled by initiator
+                    }
+
+                    // invoke I/O result handler
+                    int error = ioResult.error();
+                    ResultHandler rh = (ResultHandler)result.getContext();
+                    replaceMe = true; // (if error/exception then replace thread)
+                    if (error == 0) {
+                        rh.completed(ioResult.bytesTransferred());
+                    } else {
+                        rh.failed(error, translateErrorToIOException(error));
+                    }
+                }
+            } finally {
+                // last thread to exit when shutdown releases resources
+                int remaining = threadExit(this, replaceMe);
+                if (remaining == 0 && isShutdown()) {
+                    implClose();
+                }
+            }
+        }
+    }
+
+    /**
+     * Container for data returned by GetQueuedCompletionStatus
+     */
+    private static class CompletionStatus {
+        private int error;
+        private int bytesTransferred;
+        private int completionKey;
+        private long overlapped;
+
+        private CompletionStatus() { }
+        int error() { return error; }
+        int bytesTransferred() { return bytesTransferred; }
+        int completionKey() { return completionKey; }
+        long overlapped() { return overlapped; }
+    }
+
+    // -- native methods --
+
+    private static native void initIDs();
+
+    private static native long createIoCompletionPort(long handle,
+        long existingPort, int completionKey, int concurrency) throws IOException;
+
+    private static native void close0(long handle);
+
+    private static native void getQueuedCompletionStatus(long completionPort,
+        CompletionStatus status) throws IOException;
+
+    private static native void postQueuedCompletionStatus(long completionPort,
+        int completionKey) throws IOException;
+
+    private static native String getErrorMessage(int error);
+
+    static {
+        Util.load();
+        initIDs();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/ch/PendingIoCache.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.util.*;
+import sun.misc.Unsafe;
+
+/**
+ * Maintains a mapping of pending I/O requests (identified by the address of
+ * an OVERLAPPED structure) to Futures.
+ */
+
+class PendingIoCache {
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private static final int addressSize = unsafe.addressSize();
+
+    private static int dependsArch(int value32, int value64) {
+        return (addressSize == 4) ? value32 : value64;
+    }
+
+    /*
+     * typedef struct _OVERLAPPED {
+     *     DWORD  Internal;
+     *     DWORD  InternalHigh;
+     *     DWORD  Offset;
+     *     DWORD  OffsetHigh;
+     *     HANDLE hEvent;
+     * } OVERLAPPED;
+     */
+    private static final int SIZEOF_OVERLAPPED = dependsArch(20, 32);
+
+    // set to true when closed
+    private boolean closed;
+
+    // set to true when thread is waiting for all I/O operations to complete
+    private boolean closePending;
+
+    // maps OVERLAPPED to PendingFuture
+    private final Map<Long,PendingFuture> pendingIoMap =
+        new HashMap<Long,PendingFuture>();
+
+    // per-channel cache of OVERLAPPED structures
+    private long[] overlappedCache = new long[4];
+    private int overlappedCacheCount = 0;
+
+    PendingIoCache() {
+    }
+
+    long add(PendingFuture<?,?> result) {
+        synchronized (this) {
+            if (closed)
+                throw new AssertionError("Should not get here");
+            long ov;
+            if (overlappedCacheCount > 0) {
+                ov = overlappedCache[--overlappedCacheCount];
+            } else {
+                ov = unsafe.allocateMemory(SIZEOF_OVERLAPPED);
+            }
+            pendingIoMap.put(ov, result);
+            return ov;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    <V,A> PendingFuture<V,A> remove(long overlapped) {
+        synchronized (this) {
+            PendingFuture<V,A> res = pendingIoMap.remove(overlapped);
+            if (res != null) {
+                if (overlappedCacheCount < overlappedCache.length) {
+                    overlappedCache[overlappedCacheCount++] = overlapped;
+                } else {
+                    // cache full or channel closing
+                    unsafe.freeMemory(overlapped);
+                }
+                // notify closing thread.
+                if (closePending) {
+                    this.notifyAll();
+                }
+            }
+            return res;
+        }
+    }
+
+    void close() {
+        synchronized (this) {
+            if (closed)
+                return;
+
+            // handle the case that where there are I/O operations that have
+            // not completed.
+            if (!pendingIoMap.isEmpty())
+                clearPendingIoMap();
+
+            // release memory for any cached OVERLAPPED structures
+            while (overlappedCacheCount > 0) {
+                unsafe.freeMemory( overlappedCache[--overlappedCacheCount] );
+            }
+
+            // done
+            closed = true;
+        }
+    }
+
+    private void clearPendingIoMap() {
+        assert Thread.holdsLock(this);
+
+        // wait up to 50ms for the I/O operations to complete
+        closePending = true;
+        try {
+            this.wait(50);
+        } catch (InterruptedException x) { }
+        closePending = false;
+        if (pendingIoMap.isEmpty())
+            return;
+
+        // cause all pending I/O operations to fail
+        // simulate the failure of all pending I/O operations.
+        for (Long ov: pendingIoMap.keySet()) {
+            PendingFuture<?,?> result = pendingIoMap.get(ov);
+            assert !result.isDone();
+
+            // make I/O port aware of the stale OVERLAPPED structure
+            Iocp iocp = (Iocp)((Groupable)result.channel()).group();
+            iocp.makeStale(ov);
+
+            // execute a task that invokes the result handler's failed method
+            final Iocp.ResultHandler rh = (Iocp.ResultHandler)result.getContext();
+            Runnable task = new Runnable() {
+                public void run() {
+                    rh.failed(-1, new AsynchronousCloseException());
+                }
+            };
+            iocp.executeOnPooledThread(task);
+        }
+        pendingIoMap.clear();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousChannelProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.net.ProtocolFamily;
+import java.io.IOException;
+
+public class WindowsAsynchronousChannelProvider
+    extends AsynchronousChannelProvider
+{
+    private static volatile Iocp defaultIocp;
+
+    public WindowsAsynchronousChannelProvider() {
+        // nothing to do
+    }
+
+    private Iocp defaultIocp() throws IOException {
+        if (defaultIocp == null) {
+            synchronized (WindowsAsynchronousChannelProvider.class) {
+                if (defaultIocp == null) {
+                    // default thread pool may be shared with AsynchronousFileChannels
+                    defaultIocp = new Iocp(this, ThreadPool.getDefault()).start();
+                }
+            }
+        }
+        return defaultIocp;
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory)
+        throws IOException
+    {
+        return new Iocp(this, ThreadPool.create(nThreads, factory)).start();
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
+        throws IOException
+    {
+        return new Iocp(this, ThreadPool.wrap(executor, initialSize)).start();
+    }
+
+    private Iocp toIocp(AsynchronousChannelGroup group) throws IOException {
+        if (group == null) {
+            return defaultIocp();
+        } else {
+            if (!(group instanceof Iocp))
+                throw new IllegalChannelGroupException();
+            return (Iocp)group;
+        }
+    }
+
+    @Override
+    public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group)
+        throws IOException
+    {
+        return new WindowsAsynchronousServerSocketChannelImpl(toIocp(group));
+    }
+
+    @Override
+    public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group)
+        throws IOException
+    {
+        return new WindowsAsynchronousSocketChannelImpl(toIocp(group));
+    }
+
+    @Override
+    public AsynchronousDatagramChannel openAsynchronousDatagramChannel(ProtocolFamily family,
+                                                                       AsynchronousChannelGroup group)
+        throws IOException
+    {
+        return new SimpleAsynchronousDatagramChannelImpl(family, toIocp(group));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,741 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.util.concurrent.*;
+import java.nio.ByteBuffer;
+import java.nio.BufferOverflowException;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import sun.misc.SharedSecrets;
+import sun.misc.JavaIOFileDescriptorAccess;
+
+/**
+ * Windows implementation of AsynchronousFileChannel using overlapped I/O.
+ */
+
+public class WindowsAsynchronousFileChannelImpl
+    extends AsynchronousFileChannelImpl
+    implements Iocp.OverlappedChannel, Groupable
+{
+    private static final JavaIOFileDescriptorAccess fdAccess =
+        SharedSecrets.getJavaIOFileDescriptorAccess();
+
+    // error when EOF is detected asynchronously.
+    private static final int ERROR_HANDLE_EOF = 38;
+
+    // Lazy initialization of default I/O completion port
+    private static class DefaultIocpHolder {
+        static final Iocp defaultIocp = defaultIocp();
+        private static Iocp defaultIocp() {
+            try {
+                return new Iocp(null, ThreadPool.createDefault()).start();
+            } catch (IOException ioe) {
+                InternalError e = new InternalError();
+                e.initCause(ioe);
+                throw e;
+            }
+        }
+    }
+
+    // Used for force/truncate/size methods
+    private static final FileDispatcher nd = new FileDispatcherImpl();
+
+    // The handle is extracted for use in native methods invoked from this class.
+    private final long handle;
+
+    // The key that identifies the channel's association with the I/O port
+    private final int completionKey;
+
+    // I/O completion port (group)
+    private final Iocp iocp;
+
+    private final boolean isDefaultIocp;
+
+    // Caches OVERLAPPED structure for each outstanding I/O operation
+    private final PendingIoCache ioCache;
+
+
+    private WindowsAsynchronousFileChannelImpl(FileDescriptor fdObj,
+                                               boolean reading,
+                                               boolean writing,
+                                               Iocp iocp,
+                                               boolean isDefaultIocp)
+        throws IOException
+    {
+        super(fdObj, reading, writing, iocp.executor());
+        this.handle = fdAccess.getHandle(fdObj);
+        this.iocp = iocp;
+        this.isDefaultIocp = isDefaultIocp;
+        this.ioCache = new PendingIoCache();
+        this.completionKey = iocp.associate(this, handle);
+    }
+
+    public static AsynchronousFileChannel open(FileDescriptor fdo,
+                                               boolean reading,
+                                               boolean writing,
+                                               ThreadPool pool)
+        throws IOException
+    {
+        Iocp iocp;
+        boolean isDefaultIocp;
+        if (pool == null) {
+            iocp = DefaultIocpHolder.defaultIocp;
+            isDefaultIocp = true;
+        } else {
+            iocp = new Iocp(null, pool).start();
+            isDefaultIocp = false;
+        }
+        try {
+            return new
+                WindowsAsynchronousFileChannelImpl(fdo, reading, writing, iocp, isDefaultIocp);
+        } catch (IOException x) {
+            // error binding to port so need to close it (if created for this channel)
+            if (!isDefaultIocp)
+                iocp.implClose();
+            throw x;
+        }
+    }
+
+    @Override
+    public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
+        return ioCache.remove(overlapped);
+    }
+
+    @Override
+    public void close() throws IOException {
+        closeLock.writeLock().lock();
+        try {
+            if (closed)
+                return;     // already closed
+            closed = true;
+        } finally {
+            closeLock.writeLock().unlock();
+        }
+
+        // invalidate all locks held for this channel
+        invalidateAllLocks();
+
+        // close the file
+        close0(handle);
+
+        // waits until all I/O operations have completed
+        ioCache.close();
+
+        // disassociate from port and shutdown thread pool if not default
+        iocp.disassociate(completionKey);
+        if (!isDefaultIocp)
+            iocp.shutdown();
+    }
+
+    @Override
+    public AsynchronousChannelGroupImpl group() {
+        return iocp;
+    }
+
+    /**
+     * Translates Throwable to IOException
+     */
+    private static IOException toIOException(Throwable x) {
+        if (x instanceof IOException) {
+            if (x instanceof ClosedChannelException)
+                x = new AsynchronousCloseException();
+            return (IOException)x;
+        }
+        return new IOException(x);
+    }
+
+    @Override
+    public long size() throws IOException {
+        try {
+            begin();
+            return nd.size(fdObj);
+        } finally {
+            end();
+        }
+    }
+
+    @Override
+    public AsynchronousFileChannel truncate(long size) throws IOException {
+        if (size < 0)
+            throw new IllegalArgumentException("Negative size");
+        if (!writing)
+            throw new NonWritableChannelException();
+        try {
+            begin();
+            if (size > nd.size(fdObj))
+                return this;
+            nd.truncate(fdObj, size);
+        } finally {
+            end();
+        }
+        return this;
+    }
+
+    @Override
+    public void force(boolean metaData) throws IOException {
+        try {
+            begin();
+            nd.force(fdObj, metaData);
+        } finally {
+            end();
+        }
+    }
+
+    // -- file locking --
+
+    /**
+     * Task that initiates locking operation and handles completion result.
+     */
+    private class LockTask<A> implements Runnable, Iocp.ResultHandler {
+        private final long position;
+        private final FileLockImpl fli;
+        private final PendingFuture<FileLock,A> result;
+
+        LockTask(long position,
+                 FileLockImpl fli,
+                 PendingFuture<FileLock,A> result)
+        {
+            this.position = position;
+            this.fli = fli;
+            this.result = result;
+        }
+
+        @Override
+        public void run() {
+            long overlapped = 0L;
+            try {
+                begin();
+
+                // allocate OVERLAPPED structure
+                overlapped = ioCache.add(result);
+
+                // synchronize on result to avoid race with handler thread
+                // when lock is acquired immediately.
+                synchronized (result) {
+                    int n = lockFile(handle, position, fli.size(), fli.isShared(),
+                                     overlapped);
+                    if (n == IOStatus.UNAVAILABLE) {
+                        // I/O is pending
+                        return;
+                    }
+                    // acquired lock immediately
+                    result.setResult(fli);
+                }
+
+            } catch (Throwable x) {
+                // lock failed or channel closed
+                removeFromFileLockTable(fli);
+                if (overlapped != 0L)
+                    ioCache.remove(overlapped);
+                result.setFailure(toIOException(x));
+            } finally {
+                end();
+            }
+
+            // invoke completion handler
+            Invoker.invoke(result.handler(), result);
+        }
+
+        @Override
+        public void completed(int bytesTransferred) {
+            // release waiters and invoke completion handler
+            result.setResult(fli);
+            Invoker.invoke(result.handler(), result);
+        }
+
+        @Override
+        public void failed(int error, IOException x) {
+            // lock not acquired so remove from lock table
+            removeFromFileLockTable(fli);
+
+            // release waiters
+            if (isOpen()) {
+                result.setFailure(x);
+            } else {
+                result.setFailure(new AsynchronousCloseException());
+            }
+            Invoker.invoke(result.handler(), result);
+        }
+    }
+
+    @Override
+    public <A> Future<FileLock> lock(long position,
+                                     long size,
+                                     boolean shared,
+                                     A attachment,
+                                     CompletionHandler<FileLock,? super A> handler)
+    {
+        if (shared && !reading)
+            throw new NonReadableChannelException();
+        if (!shared && !writing)
+            throw new NonWritableChannelException();
+
+        // add to lock table
+        FileLockImpl fli = addToFileLockTable(position, size, shared);
+        if (fli == null) {
+            CompletedFuture<FileLock,A> result = CompletedFuture
+                .withFailure(this, new ClosedChannelException(), attachment);
+            Invoker.invoke(handler, result);
+            return result;
+        }
+
+        // create Future and task that will be invoked to acquire lock
+        PendingFuture<FileLock,A> result =
+            new PendingFuture<FileLock,A>(this, handler, attachment);
+        LockTask lockTask = new LockTask<A>(position, fli, result);
+        result.setContext(lockTask);
+
+        // initiate I/O (can only be done from thread in thread pool)
+        try {
+            Invoker.invokeOnThreadInThreadPool(this, lockTask);
+        } catch (ShutdownChannelGroupException e) {
+            // rollback
+            removeFromFileLockTable(fli);
+            throw e;
+        }
+        return result;
+    }
+
+    static final int NO_LOCK = -1;       // Failed to lock
+    static final int LOCKED = 0;         // Obtained requested lock
+
+    @Override
+    public FileLock tryLock(long position, long size, boolean shared)
+        throws IOException
+    {
+        if (shared && !reading)
+            throw new NonReadableChannelException();
+        if (!shared && !writing)
+            throw new NonWritableChannelException();
+
+        // add to lock table
+        final FileLockImpl fli = addToFileLockTable(position, size, shared);
+        if (fli == null)
+            throw new ClosedChannelException();
+
+        boolean gotLock = false;
+        try {
+            begin();
+            // try to acquire the lock
+            int res = nd.lock(fdObj, false, position, size, shared);
+            if (res == NO_LOCK)
+                return null;
+            gotLock = true;
+            return fli;
+        } finally {
+            if (!gotLock)
+                removeFromFileLockTable(fli);
+            end();
+        }
+    }
+
+    // invoke by FileFileImpl to release lock
+    @Override
+    void release(FileLockImpl fli) throws IOException {
+        try {
+            begin();
+            nd.release(fdObj, fli.position(), fli.size());
+            removeFromFileLockTable(fli);
+        } finally {
+            end();
+        }
+    }
+
+    /**
+     * Task that initiates read operation and handles completion result.
+     */
+    private class ReadTask<A> implements Runnable, Iocp.ResultHandler {
+        private final ByteBuffer dst;
+        private final int pos, rem;     // buffer position/remaining
+        private final long position;    // file position
+        private final PendingFuture<Integer,A> result;
+
+        // set to dst if direct; otherwise set to substituted direct buffer
+        private volatile ByteBuffer buf;
+
+        ReadTask(ByteBuffer dst,
+                 int pos,
+                 int rem,
+                 long position,
+                 PendingFuture<Integer,A> result)
+        {
+            this.dst = dst;
+            this.pos = pos;
+            this.rem = rem;
+            this.position = position;
+            this.result = result;
+        }
+
+        void releaseBufferIfSubstituted() {
+            if (buf != dst)
+                Util.releaseTemporaryDirectBuffer(buf);
+        }
+
+        void updatePosition(int bytesTransferred) {
+            // if the I/O succeeded then adjust buffer position
+            if (bytesTransferred > 0) {
+                if (buf == dst) {
+                    try {
+                        dst.position(pos + bytesTransferred);
+                    } catch (IllegalArgumentException x) {
+                        // someone has changed the position; ignore
+                    }
+                } else {
+                    // had to substitute direct buffer
+                    buf.position(bytesTransferred).flip();
+                    try {
+                        dst.put(buf);
+                    } catch (BufferOverflowException x) {
+                        // someone has changed the position; ignore
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void run() {
+            int n = -1;
+            long overlapped = 0L;
+            long address;
+
+            // Substitute a native buffer if not direct
+            if (dst instanceof DirectBuffer) {
+                buf = dst;
+                address = ((DirectBuffer)dst).address() + pos;
+            } else {
+                buf = Util.getTemporaryDirectBuffer(rem);
+                address = ((DirectBuffer)buf).address();
+            }
+
+            try {
+                begin();
+
+                // allocate OVERLAPPED
+                overlapped = ioCache.add(result);
+
+                // synchronize on result to allow this thread handle the case
+                // where the read completes immediately.
+                synchronized (result) {
+                    n = readFile(handle, address, rem, position, overlapped);
+                    if (n == IOStatus.UNAVAILABLE) {
+                        // I/O is pending
+                        return;
+                    }
+                    // read completed immediately:
+                    // 1. update buffer position
+                    // 2. release waiters
+                    updatePosition(n);
+                    result.setResult(n);
+                }
+            } catch (Throwable x) {
+                // failed to initiate read
+                result.setFailure(toIOException(x));
+            } finally {
+                end();
+            }
+
+            // read failed or EOF so completion port will not be notified
+            if (n < 0 && overlapped != 0L) {
+                ioCache.remove(overlapped);
+            }
+
+            // return direct buffer to cache if substituted
+            releaseBufferIfSubstituted();
+
+            // invoke completion handler
+            Invoker.invoke(result.handler(), result);
+        }
+
+        /**
+         * Executed when the I/O has completed
+         */
+        @Override
+        public void completed(int bytesTransferred) {
+            updatePosition(bytesTransferred);
+
+            // return direct buffer to cache if substituted
+            releaseBufferIfSubstituted();
+
+            // release waiters and invoke completion handler
+            result.setResult(bytesTransferred);
+            Invoker.invoke(result.handler(), result);
+        }
+
+        @Override
+        public void failed(int error, IOException x) {
+            // if EOF detected asynchronously then it is reported as error
+            if (error == ERROR_HANDLE_EOF) {
+                completed(-1);
+            } else {
+                // return direct buffer to cache if substituted
+                releaseBufferIfSubstituted();
+
+                // release waiters
+                if (isOpen()) {
+                    result.setFailure(x);
+                } else {
+                    result.setFailure(new AsynchronousCloseException());
+                }
+                Invoker.invoke(result.handler(), result);
+            }
+        }
+    }
+
+    @Override
+    public <A> Future<Integer> read(ByteBuffer dst,
+                                    long position,
+                                    A attachment,
+                                    CompletionHandler<Integer,? super A> handler)
+    {
+        if (!reading)
+            throw new NonReadableChannelException();
+        if (position < 0)
+            throw new IllegalArgumentException("Negative position");
+        if (dst.isReadOnly())
+            throw new IllegalArgumentException("Read-only buffer");
+
+        // check if channel is closed
+        if (!isOpen()) {
+            CompletedFuture<Integer,A> result = CompletedFuture
+                .withFailure(this, new ClosedChannelException(), attachment);
+            Invoker.invoke(handler, result);
+            return result;
+        }
+
+        int pos = dst.position();
+        int lim = dst.limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+
+        // no space remaining
+        if (rem == 0) {
+            CompletedFuture<Integer,A> result =
+                CompletedFuture.withResult(this, 0, attachment);
+            Invoker.invoke(handler, result);
+            return result;
+        }
+
+        // create Future and task that initiates read
+        PendingFuture<Integer,A> result =
+            new PendingFuture<Integer,A>(this, handler, attachment);
+        ReadTask readTask = new ReadTask<A>(dst, pos, rem, position, result);
+        result.setContext(readTask);
+
+        // initiate I/O (can only be done from thread in thread pool)
+        Invoker.invokeOnThreadInThreadPool(this, readTask);
+        return result;
+    }
+
+    /**
+     * Task that initiates write operation and handles completion result.
+     */
+    private class WriteTask<A> implements Runnable, Iocp.ResultHandler {
+        private final ByteBuffer src;
+        private final int pos, rem;     // buffer position/remaining
+        private final long position;    // file position
+        private final PendingFuture<Integer,A> result;
+
+        // set to src if direct; otherwise set to substituted direct buffer
+        private volatile ByteBuffer buf;
+
+        WriteTask(ByteBuffer src,
+                  int pos,
+                  int rem,
+                  long position,
+                  PendingFuture<Integer,A> result)
+        {
+            this.src = src;
+            this.pos = pos;
+            this.rem = rem;
+            this.position = position;
+            this.result = result;
+        }
+
+        void releaseBufferIfSubstituted() {
+            if (buf != src)
+                Util.releaseTemporaryDirectBuffer(buf);
+        }
+
+        void updatePosition(int bytesTransferred) {
+            // if the I/O succeeded then adjust buffer position
+            if (bytesTransferred > 0) {
+                try {
+                    src.position(pos + bytesTransferred);
+                } catch (IllegalArgumentException x) {
+                    // someone has changed the position
+                }
+            }
+        }
+
+        @Override
+        public void run() {
+            int n = -1;
+            long overlapped = 0L;
+            long address;
+
+            // Substitute a native buffer if not direct
+            if (src instanceof DirectBuffer) {
+                buf = src;
+                address = ((DirectBuffer)src).address() + pos;
+            } else {
+                buf = Util.getTemporaryDirectBuffer(rem);
+                buf.put(src);
+                buf.flip();
+                // temporarily restore position as we don't know how many bytes
+                // will be written
+                src.position(pos);
+                address = ((DirectBuffer)buf).address();
+            }
+
+            try {
+                begin();
+
+                // allocate an OVERLAPPED structure
+                overlapped = ioCache.add(result);
+
+                // synchronize on result to allow this thread handle the case
+                // where the read completes immediately.
+                synchronized (result) {
+                    n = writeFile(handle, address, rem, position, overlapped);
+                    if (n == IOStatus.UNAVAILABLE) {
+                        // I/O is pending
+                        return;
+                    }
+                    // read completed immediately:
+                    // 1. update buffer position
+                    // 2. release waiters
+                    updatePosition(n);
+                    result.setResult(n);
+                }
+            } catch (Throwable x) {
+                // failed to initiate read:
+                result.setFailure(toIOException(x));
+
+                // release resources
+                if (overlapped != 0L)
+                    ioCache.remove(overlapped);
+                releaseBufferIfSubstituted();
+
+            } finally {
+                end();
+            }
+
+            // invoke completion handler
+            Invoker.invoke(result.handler(), result);
+        }
+
+        /**
+         * Executed when the I/O has completed
+         */
+        @Override
+        public void completed(int bytesTransferred) {
+            updatePosition(bytesTransferred);
+
+            // return direct buffer to cache if substituted
+            releaseBufferIfSubstituted();
+
+            // release waiters and invoke completion handler
+            result.setResult(bytesTransferred);
+            Invoker.invoke(result.handler(), result);
+        }
+
+        @Override
+        public void failed(int error, IOException x) {
+            // return direct buffer to cache if substituted
+            releaseBufferIfSubstituted();
+
+            // release waiters and invoker completion handler
+            if (isOpen()) {
+                result.setFailure(x);
+            } else {
+                result.setFailure(new AsynchronousCloseException());
+            }
+            Invoker.invoke(result.handler(), result);
+        }
+    }
+
+    @Override
+    public <A> Future<Integer> write(ByteBuffer src,
+                                     long position,
+                                     A attachment,
+                                     CompletionHandler<Integer,? super A> handler)
+    {
+        if (!writing)
+            throw new NonWritableChannelException();
+        if (position < 0)
+            throw new IllegalArgumentException("Negative position");
+
+        // check if channel is closed
+        if (!isOpen()) {
+            CompletedFuture<Integer,A> result = CompletedFuture
+                .withFailure(this, new ClosedChannelException(), attachment);
+            Invoker.invoke(handler, result);
+            return result;
+        }
+
+        int pos = src.position();
+        int lim = src.limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+
+        // nothing to write
+        if (rem == 0) {
+            CompletedFuture<Integer,A> result =
+                CompletedFuture.withResult(this, 0, attachment);
+            Invoker.invoke(handler, result);
+            return result;
+        }
+
+        // create Future and task to initiate write
+        PendingFuture<Integer,A> result =
+            new PendingFuture<Integer,A>(this, handler, attachment);
+        WriteTask writeTask = new WriteTask<A>(src, pos, rem, position, result);
+        result.setContext(writeTask);
+
+        // initiate I/O (can only be done from thread in thread pool)
+        Invoker.invokeOnThreadInThreadPool(this, writeTask);
+        return result;
+    }
+
+    // -- Native methods --
+
+    private static native int readFile(long handle, long address, int len,
+        long offset, long overlapped) throws IOException;
+
+    private static native int writeFile(long handle, long address, int len,
+        long offset, long overlapped) throws IOException;
+
+    private static native int lockFile(long handle, long position, long size,
+        boolean shared, long overlapped) throws IOException;
+
+    private static native void close0(long handle);
+
+    static {
+        Util.load();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.net.InetSocketAddress;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.io.IOException;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.misc.Unsafe;
+
+/**
+ * Windows implementation of AsynchronousServerSocketChannel using overlapped I/O.
+ */
+
+class WindowsAsynchronousServerSocketChannelImpl
+    extends AsynchronousServerSocketChannelImpl implements Iocp.OverlappedChannel
+{
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    // 2 * (sizeof(SOCKET_ADDRESS) + 16)
+    private static final int DATA_BUFFER_SIZE = 88;
+
+    private final long handle;
+    private final int completionKey;
+    private final Iocp iocp;
+
+    // typically there will be zero, or one I/O operations pending. In rare
+    // cases there may be more. These rare cases arise when a sequence of accept
+    // operations complete immediately and handled by the initiating thread.
+    // The corresponding OVERLAPPED cannot be reused/released until the completion
+    // event has been posted.
+    private final PendingIoCache ioCache;
+
+    // the data buffer to receive the local/remote socket address
+    private final long dataBuffer;
+
+    // flag to indicate that an accept operation is outstanding
+    private AtomicBoolean accepting = new AtomicBoolean();
+
+
+    WindowsAsynchronousServerSocketChannelImpl(Iocp iocp) throws IOException {
+        super(iocp);
+
+        // associate socket with given completion port
+        long h = IOUtil.fdVal(fd);
+        int key;
+        try {
+            key = iocp.associate(this, h);
+        } catch (IOException x) {
+            closesocket0(h);   // prevent leak
+            throw x;
+        }
+
+        this.handle = h;
+        this.completionKey = key;
+        this.iocp = iocp;
+        this.ioCache = new PendingIoCache();
+        this.dataBuffer = unsafe.allocateMemory(DATA_BUFFER_SIZE);
+    }
+
+    @Override
+    public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
+        return ioCache.remove(overlapped);
+    }
+
+    @Override
+    void implClose() throws IOException {
+        // close socket (which may cause outstanding accept to be aborted).
+        closesocket0(handle);
+
+        // waits until the accept operations have completed
+        ioCache.close();
+
+        // finally disassociate from the completion port
+        iocp.disassociate(completionKey);
+
+        // release other resources
+        unsafe.freeMemory(dataBuffer);
+    }
+
+    @Override
+    public AsynchronousChannelGroupImpl group() {
+        return iocp;
+    }
+
+    /**
+     * Task to initiate accept operation and to handle result.
+     */
+    private class AcceptTask<A> implements Runnable, Iocp.ResultHandler {
+        private final WindowsAsynchronousSocketChannelImpl channel;
+        private final AccessControlContext acc;
+        private final PendingFuture<AsynchronousSocketChannel,A> result;
+
+        AcceptTask(WindowsAsynchronousSocketChannelImpl channel,
+                   AccessControlContext acc,
+                   PendingFuture<AsynchronousSocketChannel,A> result)
+        {
+            this.channel = channel;
+            this.acc = acc;
+            this.result = result;
+        }
+
+        void enableAccept() {
+            accepting.set(false);
+        }
+
+        void closeChildChannel() {
+            try {
+                channel.close();
+            } catch (IOException ignore) { }
+        }
+
+        // caller must have acquired read lock for the listener and child channel.
+        void finishAccept() throws IOException {
+            /**
+             * Set local/remote addresses. This is currently very inefficient
+             * in that it requires 2 calls to getsockname and 2 calls to getpeername.
+             * (should change this to use GetAcceptExSockaddrs)
+             */
+            updateAcceptContext(handle, channel.handle());
+
+            InetSocketAddress local = Net.localAddress(channel.fd);
+            final InetSocketAddress remote = Net.remoteAddress(channel.fd);
+            channel.setConnected(local, remote);
+
+            // permission check (in context of initiating thread)
+            if (acc != null) {
+                AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                    public Void run() {
+                        SecurityManager sm = System.getSecurityManager();
+                        sm.checkAccept(remote.getAddress().getHostAddress(),
+                                       remote.getPort());
+                        return null;
+                    }
+                }, acc);
+            }
+        }
+
+        /**
+         * Initiates the accept operation.
+         */
+        @Override
+        public void run() {
+            long overlapped = 0L;
+
+            try {
+                // begin usage of listener socket
+                begin();
+                try {
+                    // begin usage of child socket (as it is registered with
+                    // completion port and so may be closed in the event that
+                    // the group is forcefully closed).
+                    channel.begin();
+
+                    synchronized (result) {
+                        overlapped = ioCache.add(result);
+
+                        int n = accept0(handle, channel.handle(), overlapped, dataBuffer);
+                        if (n == IOStatus.UNAVAILABLE) {
+                            return;
+                        }
+
+                        // connection accepted immediately
+                        finishAccept();
+
+                        // allow another accept before the result is set
+                        enableAccept();
+                        result.setResult(channel);
+                    }
+                } finally {
+                    // end usage on child socket
+                    channel.end();
+                }
+            } catch (Throwable x) {
+                // failed to initiate accept so release resources
+                if (overlapped != 0L)
+                    ioCache.remove(overlapped);
+                closeChildChannel();
+                if (x instanceof ClosedChannelException)
+                    x = new AsynchronousCloseException();
+                if (!(x instanceof IOException) && !(x instanceof SecurityException))
+                    x = new IOException(x);
+                enableAccept();
+                result.setFailure(x);
+            } finally {
+                // end of usage of listener socket
+                end();
+            }
+
+            // accept completed immediately but may not have executed on
+            // initiating thread in which case the operation may have been
+            // cancelled.
+            if (result.isCancelled()) {
+                closeChildChannel();
+            }
+
+            // invoke completion handler
+            Invoker.invokeIndirectly(result.handler(), result);
+        }
+
+        /**
+         * Executed when the I/O has completed
+         */
+        @Override
+        public void completed(int bytesTransferred) {
+            try {
+                // connection accept after group has shutdown
+                if (iocp.isShutdown()) {
+                    throw new IOException(new ShutdownChannelGroupException());
+                }
+
+                // finish the accept
+                try {
+                    begin();
+                    try {
+                        channel.begin();
+                        finishAccept();
+                    } finally {
+                        channel.end();
+                    }
+                } finally {
+                    end();
+                }
+
+                // allow another accept before the result is set
+                enableAccept();
+                result.setResult(channel);
+            } catch (Throwable x) {
+                enableAccept();
+                closeChildChannel();
+                if (x instanceof ClosedChannelException)
+                    x = new AsynchronousCloseException();
+                if (!(x instanceof IOException) && !(x instanceof SecurityException))
+                    x = new IOException(x);
+                result.setFailure(x);
+            }
+
+            // if an async cancel has already cancelled the operation then
+            // close the new channel so as to free resources
+            if (result.isCancelled()) {
+                closeChildChannel();
+            }
+
+            // invoke handler (but not directly)
+            Invoker.invokeIndirectly(result.handler(), result);
+        }
+
+        @Override
+        public void failed(int error, IOException x) {
+            enableAccept();
+            closeChildChannel();
+
+            // release waiters
+            if (isOpen()) {
+                result.setFailure(x);
+            } else {
+                result.setFailure(new AsynchronousCloseException());
+            }
+            Invoker.invokeIndirectly(result.handler(), result);
+        }
+    }
+
+    @Override
+    public <A> Future<AsynchronousSocketChannel> accept(A attachment,
+        final CompletionHandler<AsynchronousSocketChannel,? super A> handler)
+    {
+        if (!isOpen()) {
+            CompletedFuture<AsynchronousSocketChannel,A> result = CompletedFuture
+                .withFailure(this, new ClosedChannelException(), attachment);
+            Invoker.invokeIndirectly(handler, result);
+            return result;
+        }
+        if (isAcceptKilled())
+            throw new RuntimeException("Accept not allowed due to cancellation");
+
+        // ensure channel is bound to local address
+        if (localAddress == null)
+            throw new NotYetBoundException();
+
+        // create the socket that will be accepted. The creation of the socket
+        // is enclosed by a begin/end for the listener socket to ensure that
+        // we check that the listener is open and also to prevent the I/O
+        // port from being closed as the new socket is registered.
+        WindowsAsynchronousSocketChannelImpl ch = null;
+        IOException ioe = null;
+        try {
+            begin();
+            ch = new WindowsAsynchronousSocketChannelImpl(iocp, false);
+        } catch (IOException x) {
+            ioe = x;
+        } finally {
+            end();
+        }
+        if (ioe != null) {
+            CompletedFuture<AsynchronousSocketChannel,A> result =
+                CompletedFuture.withFailure(this, ioe, attachment);
+            Invoker.invokeIndirectly(handler, result);
+            return result;
+        }
+
+        // need calling context when there is security manager as
+        // permission check may be done in a different thread without
+        // any application call frames on the stack
+        AccessControlContext acc = (System.getSecurityManager() == null) ?
+            null : AccessController.getContext();
+
+        PendingFuture<AsynchronousSocketChannel,A> result =
+            new PendingFuture<AsynchronousSocketChannel,A>(this, handler, attachment);
+        AcceptTask task = new AcceptTask<A>(ch, acc, result);
+        result.setContext(task);
+
+        // check and set flag to prevent concurrent accepting
+        if (!accepting.compareAndSet(false, true))
+            throw new AcceptPendingException();
+
+        // initiate accept. As I/O operations are tied to the initiating thread
+        // then it will only be invoked direcly if this thread is in the thread
+        // pool. If this thread is not in the thread pool when a task is
+        // submitted to initiate the accept.
+        Invoker.invokeOnThreadInThreadPool(this, task);
+        return result;
+    }
+
+    // -- Native methods --
+
+    private static native void initIDs();
+
+    private static native int accept0(long listenSocket, long acceptSocket,
+        long overlapped, long dataBuffer) throws IOException;
+
+    private static native void updateAcceptContext(long listenSocket,
+        long acceptSocket) throws IOException;
+
+    private static native void closesocket0(long socket) throws IOException;
+
+    static {
+        Util.load();
+        initIDs();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,911 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 conne02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.nio.ByteBuffer;
+import java.nio.BufferOverflowException;
+import java.net.*;
+import java.util.concurrent.*;
+import java.io.IOException;
+import sun.misc.Unsafe;
+
+/**
+ * Windows implementation of AsynchronousSocketChannel using overlapped I/O.
+ */
+
+class WindowsAsynchronousSocketChannelImpl
+    extends AsynchronousSocketChannelImpl implements Iocp.OverlappedChannel
+{
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private static int addressSize = unsafe.addressSize();
+
+    private static int dependsArch(int value32, int value64) {
+        return (addressSize == 4) ? value32 : value64;
+    }
+
+    /*
+     * typedef struct _WSABUF {
+     *     u_long      len;
+     *     char FAR *  buf;
+     * } WSABUF;
+     */
+    private static final int SIZEOF_WSABUF  = dependsArch(8, 16);
+    private static final int OFFSETOF_LEN   = 0;
+    private static final int OFFSETOF_BUF   = dependsArch(4, 8);
+
+    // maximum vector size for scatter/gather I/O
+    private static final int MAX_WSABUF     = 16;
+
+    private static final int SIZEOF_WSABUFARRAY = MAX_WSABUF * SIZEOF_WSABUF;
+
+
+    // socket handle. Use begin()/end() around each usage of this handle.
+    final long handle;
+
+    // I/O completion port that the socket is associated with
+    private final Iocp iocp;
+
+    // completion key to identify channel when I/O completes
+    private final int completionKey;
+
+    // Pending I/O operations are tied to an OVERLAPPED structure that can only
+    // be released when the I/O completion event is posted to the completion
+    // port. Where I/O operations complete immediately then it is possible
+    // there may be more than two OVERLAPPED structures in use.
+    private final PendingIoCache ioCache;
+
+    // per-channel arrays of WSABUF structures
+    private final long readBufferArray;
+    private final long writeBufferArray;
+
+
+    WindowsAsynchronousSocketChannelImpl(Iocp iocp, boolean failIfGroupShutdown)
+        throws IOException
+    {
+        super(iocp);
+
+        // associate socket with default completion port
+        long h = IOUtil.fdVal(fd);
+        int key = 0;
+        try {
+            key = iocp.associate(this, h);
+        } catch (ShutdownChannelGroupException x) {
+            if (failIfGroupShutdown) {
+                closesocket0(h);
+                throw x;
+            }
+        } catch (IOException x) {
+            closesocket0(h);
+            throw x;
+        }
+
+        this.handle = h;
+        this.iocp = iocp;
+        this.completionKey = key;
+        this.ioCache = new PendingIoCache();
+
+        // allocate WSABUF arrays
+        this.readBufferArray = unsafe.allocateMemory(SIZEOF_WSABUFARRAY);
+        this.writeBufferArray = unsafe.allocateMemory(SIZEOF_WSABUFARRAY);
+    }
+
+    WindowsAsynchronousSocketChannelImpl(Iocp iocp) throws IOException {
+        this(iocp, true);
+    }
+
+    @Override
+    public AsynchronousChannelGroupImpl group() {
+        return iocp;
+    }
+
+    /**
+     * Invoked by Iocp when an I/O operation competes.
+     */
+    @Override
+    public <V,A> PendingFuture<V,A> getByOverlapped(long overlapped) {
+        return ioCache.remove(overlapped);
+    }
+
+    // invoked by WindowsAsynchronousServerSocketChannelImpl
+    long handle() {
+        return handle;
+    }
+
+    // invoked by WindowsAsynchronousServerSocketChannelImpl when new connection
+    // accept
+    void setConnected(SocketAddress localAddress, SocketAddress remoteAddress) {
+        synchronized (stateLock) {
+            state = ST_CONNECTED;
+            this.localAddress = localAddress;
+            this.remoteAddress = remoteAddress;
+        }
+    }
+
+    @Override
+    void implClose() throws IOException {
+        // close socket (may cause outstanding async I/O operations to fail).
+        closesocket0(handle);
+
+        // waits until all I/O operations have completed
+        ioCache.close();
+
+        // release arrays of WSABUF structures
+        unsafe.freeMemory(readBufferArray);
+        unsafe.freeMemory(writeBufferArray);
+
+        // finally disassociate from the completion port (key can be 0 if
+        // channel created when group is shutdown)
+        if (completionKey != 0)
+            iocp.disassociate(completionKey);
+    }
+
+    @Override
+    public void onCancel(PendingFuture<?,?> task) {
+        if (task.getContext() instanceof ConnectTask)
+            killConnect();
+        if (task.getContext() instanceof ReadTask)
+            killReading();
+        if (task.getContext() instanceof WriteTask)
+            killWriting();
+    }
+
+    /**
+     * Implements the task to initiate a connection and the handler to
+     * consume the result when the connection is established (or fails).
+     */
+    private class ConnectTask<A> implements Runnable, Iocp.ResultHandler {
+        private final InetSocketAddress remote;
+        private final PendingFuture<Void,A> result;
+
+        ConnectTask(InetSocketAddress remote, PendingFuture<Void,A> result) {
+            this.remote = remote;
+            this.result = result;
+        }
+
+        private void closeChannel() {
+            try {
+                close();
+            } catch (IOException ignore) { }
+        }
+
+        private IOException toIOException(Throwable x) {
+            if (x instanceof IOException) {
+                if (x instanceof ClosedChannelException)
+                    x = new AsynchronousCloseException();
+                return (IOException)x;
+            }
+            return new IOException(x);
+        }
+
+        /**
+         * Invoke after a connection is successfully established.
+         */
+        private void afterConnect() throws IOException {
+            updateConnectContext(handle);
+            synchronized (stateLock) {
+                state = ST_CONNECTED;
+                remoteAddress = remote;
+            }
+        }
+
+        /**
+         * Task to initiate a connection.
+         */
+        @Override
+        public void run() {
+            long overlapped = 0L;
+            Throwable exc = null;
+            try {
+                begin();
+
+                // synchronize on result to allow this thread handle the case
+                // where the connection is established immediately.
+                synchronized (result) {
+                    overlapped = ioCache.add(result);
+                    // initiate the connection
+                    int n = connect0(handle, Net.isIPv6Available(), remote.getAddress(),
+                                     remote.getPort(), overlapped);
+                    if (n == IOStatus.UNAVAILABLE) {
+                        // connection is pending
+                        return;
+                    }
+
+                    // connection established immediately
+                    afterConnect();
+                    result.setResult(null);
+                }
+            } catch (Throwable x) {
+                exc = x;
+            } finally {
+                end();
+            }
+
+            if (exc != null) {
+                if (overlapped != 0L)
+                    ioCache.remove(overlapped);
+                closeChannel();
+                result.setFailure(toIOException(exc));
+            }
+            Invoker.invoke(result.handler(), result);
+        }
+
+        /**
+         * Invoked by handler thread when connection established.
+         */
+        @Override
+        public void completed(int bytesTransferred) {
+            Throwable exc = null;
+            try {
+                begin();
+                afterConnect();
+                result.setResult(null);
+            } catch (Throwable x) {
+                // channel is closed or unable to finish connect
+                exc = x;
+            } finally {
+                end();
+            }
+
+            // can't close channel while in begin/end block
+            if (exc != null) {
+                closeChannel();
+                result.setFailure(toIOException(exc));
+            }
+
+            Invoker.invoke(result.handler(), result);
+        }
+
+        /**
+         * Invoked by handler thread when failed to establish connection.
+         */
+        @Override
+        public void failed(int error, IOException x) {
+            if (isOpen()) {
+                closeChannel();
+                result.setFailure(x);
+            } else {
+                result.setFailure(new AsynchronousCloseException());
+            }
+            Invoker.invoke(result.handler(), result);
+        }
+    }
+
+    @Override
+    public <A> Future<Void> connect(SocketAddress remote,
+                                    A attachment,
+                                    CompletionHandler<Void,? super A> handler)
+    {
+        if (!isOpen()) {
+            CompletedFuture<Void,A> result = CompletedFuture
+                .withFailure(this, new ClosedChannelException(), attachment);
+            Invoker.invoke(handler, result);
+            return result;
+        }
+
+        InetSocketAddress isa = Net.checkAddress(remote);
+
+        // permission check
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
+
+        // check and update state
+        // ConnectEx requires the socket to be bound to a local address
+        IOException bindException = null;
+        synchronized (stateLock) {
+            if (state == ST_CONNECTED)
+                throw new AlreadyConnectedException();
+            if (state == ST_PENDING)
+                throw new ConnectionPendingException();
+            if (localAddress == null) {
+                try {
+                    bind(new InetSocketAddress(0));
+                } catch (IOException x) {
+                    bindException = x;
+                }
+            }
+            if (bindException == null)
+                state = ST_PENDING;
+        }
+
+        // handle bind failure
+        if (bindException != null) {
+            try {
+                close();
+            } catch (IOException ignore) { }
+            CompletedFuture<Void,A> result = CompletedFuture
+                .withFailure(this, bindException, attachment);
+            Invoker.invoke(handler, result);
+            return result;
+        }
+
+        // setup task
+        PendingFuture<Void,A> result =
+            new PendingFuture<Void,A>(this, handler, attachment);
+        ConnectTask task = new ConnectTask<A>(isa, result);
+        result.setContext(task);
+
+        // initiate I/O (can only be done from thread in thread pool)
+        Invoker.invokeOnThreadInThreadPool(this, task);
+        return result;
+    }
+
+    /**
+     * Implements the task to initiate a read and the handler to consume the
+     * result when the read completes.
+     */
+    private class ReadTask<V,A> implements Runnable, Iocp.ResultHandler {
+        private final ByteBuffer[] bufs;
+        private final int numBufs;
+        private final boolean scatteringRead;
+        private final PendingFuture<V,A> result;
+
+        // set by run method
+        private ByteBuffer[] shadow;
+
+        ReadTask(ByteBuffer[] bufs,
+                 boolean scatteringRead,
+                 PendingFuture<V,A> result)
+        {
+            this.bufs = bufs;
+            this.numBufs = (bufs.length > MAX_WSABUF) ? MAX_WSABUF : bufs.length;
+            this.scatteringRead = scatteringRead;
+            this.result = result;
+        }
+
+        /**
+         * Invoked prior to read to prepare the WSABUF array. Where necessary,
+         * it substitutes non-direct buffers with direct buffers.
+         */
+        void prepareBuffers() {
+            shadow = new ByteBuffer[numBufs];
+            long address = readBufferArray;
+            for (int i=0; i<numBufs; i++) {
+                ByteBuffer dst = bufs[i];
+                int pos = dst.position();
+                int lim = dst.limit();
+                assert (pos <= lim);
+                int rem = (pos <= lim ? lim - pos : 0);
+                long a;
+                if (!(dst instanceof DirectBuffer)) {
+                    // substitute with direct buffer
+                    ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
+                    shadow[i] = bb;
+                    a = ((DirectBuffer)bb).address();
+                } else {
+                    shadow[i] = dst;
+                    a = ((DirectBuffer)dst).address() + pos;
+                }
+                unsafe.putAddress(address + OFFSETOF_BUF, a);
+                unsafe.putInt(address + OFFSETOF_LEN, rem);
+                address += SIZEOF_WSABUF;
+            }
+        }
+
+        /**
+         * Invoked after a read has completed to update the buffer positions
+         * and release any substituted buffers.
+         */
+        void updateBuffers(int bytesRead) {
+            for (int i=0; i<numBufs; i++) {
+                ByteBuffer nextBuffer = shadow[i];
+                int pos = nextBuffer.position();
+                int len = nextBuffer.remaining();
+                if (bytesRead >= len) {
+                    bytesRead -= len;
+                    int newPosition = pos + len;
+                    try {
+                        nextBuffer.position(newPosition);
+                    } catch (IllegalArgumentException x) {
+                        // position changed by another
+                    }
+                } else { // Buffers not completely filled
+                    if (bytesRead > 0) {
+                        assert(pos + bytesRead < (long)Integer.MAX_VALUE);
+                        int newPosition = pos + bytesRead;
+                        try {
+                            nextBuffer.position(newPosition);
+                        } catch (IllegalArgumentException x) {
+                            // position changed by another
+                        }
+                    }
+                    break;
+                }
+            }
+
+            // Put results from shadow into the slow buffers
+            for (int i=0; i<numBufs; i++) {
+                if (!(bufs[i] instanceof DirectBuffer)) {
+                    shadow[i].flip();
+                    try {
+                        bufs[i].put(shadow[i]);
+                    } catch (BufferOverflowException x) {
+                        // position changed by another
+                    }
+                }
+            }
+        }
+
+        void releaseBuffers() {
+            for (int i=0; i<numBufs; i++) {
+                if (!(bufs[i] instanceof DirectBuffer)) {
+                    Util.releaseTemporaryDirectBuffer(shadow[i]);
+                }
+            }
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void run() {
+            long overlapped = 0L;
+            boolean prepared = false;
+            boolean pending = false;
+
+            try {
+                begin();
+
+                // substitute non-direct buffers
+                prepareBuffers();
+                prepared = true;
+
+                // get an OVERLAPPED structure (from the cache or allocate)
+                overlapped = ioCache.add(result);
+
+                // synchronize on result to allow this thread handle the case
+                // where the read completes immediately.
+                synchronized (result) {
+                    int n = read0(handle, numBufs, readBufferArray, overlapped);
+                    if (n == IOStatus.UNAVAILABLE) {
+                        // I/O is pending
+                        pending = true;
+                        return;
+                    }
+                    // read completed immediately:
+                    // 1. update buffer position
+                    // 2. reset read flag
+                    // 3. release waiters
+                    if (n == 0) {
+                        n = -1;
+                    } else {
+                        updateBuffers(n);
+                    }
+                    enableReading();
+
+                    if (scatteringRead) {
+                        result.setResult((V)Long.valueOf(n));
+                    } else {
+                        result.setResult((V)Integer.valueOf(n));
+                    }
+                }
+            } catch (Throwable x) {
+                // failed to initiate read:
+                // 1. reset read flag
+                // 2. free resources
+                // 3. release waiters
+                enableReading();
+                if (overlapped != 0L)
+                    ioCache.remove(overlapped);
+                if (x instanceof ClosedChannelException)
+                    x = new AsynchronousCloseException();
+                if (!(x instanceof IOException))
+                    x = new IOException(x);
+                result.setFailure(x);
+            } finally {
+                if (prepared && !pending) {
+                    // return direct buffer(s) to cache if substituted
+                    releaseBuffers();
+                }
+                end();
+            }
+
+            // invoke completion handler
+            Invoker.invoke(result.handler(), result);
+        }
+
+        /**
+         * Executed when the I/O has completed
+         */
+        @Override
+        @SuppressWarnings("unchecked")
+        public void completed(int bytesTransferred) {
+            if (bytesTransferred == 0) {
+                bytesTransferred = -1;  // EOF
+            } else {
+                updateBuffers(bytesTransferred);
+            }
+
+            // return direct buffer to cache if substituted
+            releaseBuffers();
+
+            // release waiters if not already released by timeout
+            synchronized (result) {
+                if (result.isDone())
+                    return;
+                enableReading();
+                if (scatteringRead) {
+                    result.setResult((V)Long.valueOf(bytesTransferred));
+                } else {
+                    result.setResult((V)Integer.valueOf(bytesTransferred));
+                }
+            }
+            Invoker.invoke(result.handler(), result);
+        }
+
+        @Override
+        public void failed(int error, IOException x) {
+            // return direct buffer to cache if substituted
+            releaseBuffers();
+
+            // release waiters if not already released by timeout
+            if (!isOpen())
+                x = new AsynchronousCloseException();
+
+            synchronized (result) {
+                if (result.isDone())
+                    return;
+                enableReading();
+                result.setFailure(x);
+            }
+            Invoker.invoke(result.handler(), result);
+        }
+
+        /**
+         * Invoked if timeout expires before it is cancelled
+         */
+        void timeout() {
+            // synchronize on result as the I/O could complete/fail
+            synchronized (result) {
+                if (result.isDone())
+                    return;
+
+                // kill further reading before releasing waiters
+                enableReading(true);
+                result.setFailure(new InterruptedByTimeoutException());
+            }
+
+            // invoke handler without any locks
+            Invoker.invoke(result.handler(), result);
+        }
+    }
+
+    @Override
+    <V extends Number,A> Future<V> readImpl(ByteBuffer[] bufs,
+                                            boolean scatteringRead,
+                                            long timeout,
+                                            TimeUnit unit,
+                                            A attachment,
+                                            CompletionHandler<V,? super A> handler)
+    {
+        // setup task
+        PendingFuture<V,A> result =
+            new PendingFuture<V,A>(this, handler, attachment);
+        final ReadTask readTask = new ReadTask<V,A>(bufs, scatteringRead, result);
+        result.setContext(readTask);
+
+        // schedule timeout
+        if (timeout > 0L) {
+            Future<?> timeoutTask = iocp.schedule(new Runnable() {
+                public void run() {
+                    readTask.timeout();
+                }
+            }, timeout, unit);
+            result.setTimeoutTask(timeoutTask);
+        }
+
+        // initiate I/O (can only be done from thread in thread pool)
+        Invoker.invokeOnThreadInThreadPool(this, readTask);
+        return result;
+    }
+
+    /**
+     * Implements the task to initiate a write and the handler to consume the
+     * result when the write completes.
+     */
+    private class WriteTask<V,A> implements Runnable, Iocp.ResultHandler {
+        private final ByteBuffer[] bufs;
+        private final int numBufs;
+        private final boolean gatheringWrite;
+        private final PendingFuture<V,A> result;
+
+        // set by run method
+        private ByteBuffer[] shadow;
+
+        WriteTask(ByteBuffer[] bufs,
+                  boolean gatheringWrite,
+                  PendingFuture<V,A> result)
+        {
+            this.bufs = bufs;
+            this.numBufs = (bufs.length > MAX_WSABUF) ? MAX_WSABUF : bufs.length;
+            this.gatheringWrite = gatheringWrite;
+            this.result = result;
+        }
+
+        /**
+         * Invoked prior to write to prepare the WSABUF array. Where necessary,
+         * it substitutes non-direct buffers with direct buffers.
+         */
+        void prepareBuffers() {
+            shadow = new ByteBuffer[numBufs];
+            long address = writeBufferArray;
+            for (int i=0; i<numBufs; i++) {
+                ByteBuffer src = bufs[i];
+                int pos = src.position();
+                int lim = src.limit();
+                assert (pos <= lim);
+                int rem = (pos <= lim ? lim - pos : 0);
+                long a;
+                if (!(src instanceof DirectBuffer)) {
+                    // substitute with direct buffer
+                    ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
+                    bb.put(src);
+                    bb.flip();
+                    src.position(pos);  // leave heap buffer untouched for now
+                    shadow[i] = bb;
+                    a = ((DirectBuffer)bb).address();
+                } else {
+                    shadow[i] = src;
+                    a = ((DirectBuffer)src).address() + pos;
+                }
+                unsafe.putAddress(address + OFFSETOF_BUF, a);
+                unsafe.putInt(address + OFFSETOF_LEN, rem);
+                address += SIZEOF_WSABUF;
+            }
+        }
+
+        /**
+         * Invoked after a write has completed to update the buffer positions
+         * and release any substituted buffers.
+         */
+        void updateBuffers(int bytesWritten) {
+            // Notify the buffers how many bytes were taken
+            for (int i=0; i<numBufs; i++) {
+                ByteBuffer nextBuffer = bufs[i];
+                int pos = nextBuffer.position();
+                int lim = nextBuffer.limit();
+                int len = (pos <= lim ? lim - pos : lim);
+                if (bytesWritten >= len) {
+                    bytesWritten -= len;
+                    int newPosition = pos + len;
+                    try {
+                        nextBuffer.position(newPosition);
+                    } catch (IllegalArgumentException x) {
+                        // position changed by someone else
+                    }
+                } else { // Buffers not completely filled
+                    if (bytesWritten > 0) {
+                        assert(pos + bytesWritten < (long)Integer.MAX_VALUE);
+                        int newPosition = pos + bytesWritten;
+                        try {
+                            nextBuffer.position(newPosition);
+                        } catch (IllegalArgumentException x) {
+                            // position changed by someone else
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+
+        void releaseBuffers() {
+            for (int i=0; i<numBufs; i++) {
+                if (!(bufs[i] instanceof DirectBuffer)) {
+                    Util.releaseTemporaryDirectBuffer(shadow[i]);
+                }
+            }
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void run() {
+            int n = -1;
+            long overlapped = 0L;
+            boolean prepared = false;
+            boolean pending = false;
+            boolean shutdown = false;
+
+            try {
+                begin();
+
+                // substitute non-direct buffers
+                prepareBuffers();
+                prepared = true;
+
+                // get an OVERLAPPED structure (from the cache or allocate)
+                overlapped = ioCache.add(result);
+
+                // synchronize on result to allow this thread handle the case
+                // where the read completes immediately.
+                synchronized (result) {
+                    n = write0(handle, numBufs, writeBufferArray, overlapped);
+                    if (n == IOStatus.UNAVAILABLE) {
+                        // I/O is pending
+                        pending = true;
+                        return;
+                    }
+
+                    enableWriting();
+
+                    if (n == IOStatus.EOF) {
+                        // special case for shutdown output
+                        shutdown = true;
+                        throw new ClosedChannelException();
+                    }
+
+                    // write completed immediately:
+                    // 1. enable writing
+                    // 2. update buffer position
+                    // 3. release waiters
+                    updateBuffers(n);
+
+                    // result is a Long or Integer
+                    if (gatheringWrite) {
+                        result.setResult((V)Long.valueOf(n));
+                    } else {
+                        result.setResult((V)Integer.valueOf(n));
+                    }
+                }
+            } catch (Throwable x) {
+                enableWriting();
+
+                // failed to initiate read:
+                if (!shutdown && (x instanceof ClosedChannelException))
+                    x = new AsynchronousCloseException();
+                if (!(x instanceof IOException))
+                    x = new IOException(x);
+                result.setFailure(x);
+
+                // release resources
+                if (overlapped != 0L)
+                    ioCache.remove(overlapped);
+
+            } finally {
+                if (prepared && !pending) {
+                    // return direct buffer(s) to cache if substituted
+                    releaseBuffers();
+                }
+                end();
+            }
+
+            // invoke completion handler
+            Invoker.invoke(result.handler(), result);
+        }
+
+        /**
+         * Executed when the I/O has completed
+         */
+        @Override
+        @SuppressWarnings("unchecked")
+        public void completed(int bytesTransferred) {
+            updateBuffers(bytesTransferred);
+
+            // return direct buffer to cache if substituted
+            releaseBuffers();
+
+            // release waiters if not already released by timeout
+            synchronized (result) {
+                if (result.isDone())
+                    return;
+                enableWriting();
+                if (gatheringWrite) {
+                    result.setResult((V)Long.valueOf(bytesTransferred));
+                } else {
+                    result.setResult((V)Integer.valueOf(bytesTransferred));
+                }
+            }
+            Invoker.invoke(result.handler(), result);
+        }
+
+        @Override
+        public void failed(int error, IOException x) {
+            // return direct buffer to cache if substituted
+            releaseBuffers();
+
+            // release waiters if not already released by timeout
+            if (!isOpen())
+                x = new AsynchronousCloseException();
+
+            synchronized (result) {
+                if (result.isDone())
+                    return;
+                enableWriting();
+                result.setFailure(x);
+            }
+            Invoker.invoke(result.handler(), result);
+        }
+
+        /**
+         * Invoked if timeout expires before it is cancelled
+         */
+        void timeout() {
+            // synchronize on result as the I/O could complete/fail
+            synchronized (result) {
+                if (result.isDone())
+                    return;
+
+                // kill further writing before releasing waiters
+                enableWriting(true);
+                result.setFailure(new InterruptedByTimeoutException());
+            }
+
+            // invoke handler without any locks
+            Invoker.invoke(result.handler(), result);
+        }
+    }
+
+    @Override
+    <V extends Number,A> Future<V> writeImpl(ByteBuffer[] bufs,
+                                             boolean gatheringWrite,
+                                             long timeout,
+                                             TimeUnit unit,
+                                             A attachment,
+                                             CompletionHandler<V,? super A> handler)
+    {
+        // setup task
+        PendingFuture<V,A> result =
+            new PendingFuture<V,A>(this, handler, attachment);
+        final WriteTask writeTask = new WriteTask<V,A>(bufs, gatheringWrite, result);
+        result.setContext(writeTask);
+
+        // schedule timeout
+        if (timeout > 0L) {
+            Future<?> timeoutTask = iocp.schedule(new Runnable() {
+                public void run() {
+                    writeTask.timeout();
+                }
+            }, timeout, unit);
+            result.setTimeoutTask(timeoutTask);
+        }
+
+        // initiate I/O (can only be done from thread in thread pool)
+        Invoker.invokeOnThreadInThreadPool(this, writeTask);
+        return result;
+    }
+
+    // -- Native methods --
+
+    private static native void initIDs();
+
+    private static native int connect0(long socket, boolean preferIPv6,
+        InetAddress remote, int remotePort, long overlapped) throws IOException;
+
+    private static native void updateConnectContext(long socket) throws IOException;
+
+    private static native int read0(long socket, int count, long addres, long overlapped)
+        throws IOException;
+
+    private static native int write0(long socket, int count, long address,
+        long overlapped) throws IOException;
+
+    private static native void shutdown0(long socket, int how) throws IOException;
+
+    private static native void closesocket0(long socket) throws IOException;
+
+    static {
+        Util.load();
+        initIDs();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/DefaultFileSystemProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.spi.FileSystemProvider;
+
+/**
+ * Creates default provider on Windows
+ */
+public class DefaultFileSystemProvider {
+    private DefaultFileSystemProvider() { }
+    public static FileSystemProvider create() {
+        return new WindowsFileSystemProvider();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/DefaultFileTypeDetector.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.spi.FileTypeDetector;
+
+public class DefaultFileTypeDetector {
+    private DefaultFileTypeDetector() { }
+
+    public static FileTypeDetector create() {
+        return new RegistryFileTypeDetector();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/RegistryFileTypeDetector.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * File type detector that does lookup of file extension using Windows Registry.
+ */
+
+public class RegistryFileTypeDetector
+    extends AbstractFileTypeDetector
+{
+    public RegistryFileTypeDetector() {
+        super();
+    }
+
+    @Override
+    public String implProbeContentType(FileRef file) throws IOException {
+        if (!(file instanceof Path))
+            return null;
+
+        // get file extension
+        Path name = ((Path)file).getName();
+        if (name == null)
+            return null;
+        String filename = name.toString();
+        int dot = filename.lastIndexOf('.');
+        if ((dot < 0) || (dot == (filename.length()-1)))
+            return null;
+
+        // query HKEY_CLASSES_ROOT\<ext>
+        String key = filename.substring(dot);
+        NativeBuffer keyBuffer = WindowsNativeDispatcher.asNativeBuffer(key);
+        NativeBuffer nameBuffer = WindowsNativeDispatcher.asNativeBuffer("Content Type");
+        try {
+            return queryStringValue(keyBuffer.address(), nameBuffer.address());
+        } finally {
+            nameBuffer.release();
+            keyBuffer.release();
+        }
+    }
+
+    private static native String queryStringValue(long subKey, long name);
+
+    static {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run() {
+                // nio.dll has dependency on net.dll
+                System.loadLibrary("net");
+                System.loadLibrary("nio");
+                return null;
+        }});
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.ProviderMismatchException;
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.io.IOException;
+
+import static sun.nio.fs.WindowsNativeDispatcher.*;
+import static sun.nio.fs.WindowsConstants.*;
+
+/**
+ * Windows implementation of AclFileAttributeView.
+ */
+
+class WindowsAclFileAttributeView
+    extends AbstractAclFileAttributeView
+{
+    /**
+     * typedef struct _SECURITY_DESCRIPTOR {
+     *     BYTE  Revision;
+     *     BYTE  Sbz1;
+     *     SECURITY_DESCRIPTOR_CONTROL Control;
+     *     PSID Owner;
+     *     PSID Group;
+     *     PACL Sacl;
+     *     PACL Dacl;
+     * } SECURITY_DESCRIPTOR;
+     */
+    private static final short SIZEOF_SECURITY_DESCRIPTOR   = 20;
+
+    private final WindowsPath file;
+    private final boolean followLinks;
+
+    WindowsAclFileAttributeView(WindowsPath file, boolean followLinks) {
+        this.file = file;
+        this.followLinks = followLinks;
+    }
+
+    // permision check
+    private void checkAccess(WindowsPath file,
+                             boolean checkRead,
+                             boolean checkWrite)
+    {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            if (checkRead)
+                sm.checkRead(file.getPathForPermissionCheck());
+            if (checkWrite)
+                sm.checkWrite(file.getPathForPermissionCheck());
+            sm.checkPermission(new RuntimePermission("accessUserInformation"));
+        }
+    }
+
+    // invokes GetFileSecurity to get requested security information
+    static NativeBuffer getFileSecurity(String path, int request)
+        throws IOException
+    {
+        // invoke get to buffer size
+        int size = 0;
+        try {
+            size = GetFileSecurity(path, request, 0L, 0);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(path);
+        }
+        assert size > 0;
+
+        // allocate buffer and re-invoke to get security information
+        NativeBuffer buffer = NativeBuffers.getNativeBuffer(size);
+        try {
+            for (;;) {
+                int newSize = GetFileSecurity(path, request, buffer.address(), size);
+                if (newSize <= size)
+                    return buffer;
+
+                // buffer was insufficient
+                buffer.release();
+                buffer = NativeBuffers.getNativeBuffer(newSize);
+                size = newSize;
+            }
+        } catch (WindowsException x) {
+            buffer.release();
+            x.rethrowAsIOException(path);
+            return null;
+        }
+    }
+
+    @Override
+    public UserPrincipal getOwner()
+        throws IOException
+    {
+        checkAccess(file, true, false);
+
+        // GetFileSecurity does not follow links so when following links we
+        // need the final target
+        String path = WindowsLinkSupport.getFinalPath(file, followLinks);
+        NativeBuffer buffer = getFileSecurity(path, OWNER_SECURITY_INFORMATION);
+        try {
+            // get the address of the SID
+            long sidAddress = GetSecurityDescriptorOwner(buffer.address());
+            if (sidAddress == 0L)
+                throw new IOException("no owner");
+            return WindowsUserPrincipals.fromSid(sidAddress);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(file);
+            return null;
+        } finally {
+            buffer.release();
+        }
+    }
+
+    @Override
+    public List<AclEntry> getAcl()
+        throws IOException
+    {
+        checkAccess(file, true, false);
+
+        // GetFileSecurity does not follow links so when following links we
+        // need the final target
+        String path = WindowsLinkSupport.getFinalPath(file, followLinks);
+
+        // ALLOW and DENY entries in DACL;
+        // AUDIT entries in SACL (ignore for now as it requires privileges)
+        NativeBuffer buffer = getFileSecurity(path, DACL_SECURITY_INFORMATION);
+        try {
+            return WindowsSecurityDescriptor.getAcl(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+
+    @Override
+    public void setOwner(UserPrincipal obj)
+        throws IOException
+    {
+        if (obj == null)
+            throw new NullPointerException("'owner' is null");
+        if (!(obj instanceof WindowsUserPrincipals.User))
+            throw new ProviderMismatchException();
+        WindowsUserPrincipals.User owner = (WindowsUserPrincipals.User)obj;
+
+        // permission check
+        checkAccess(file, false, true);
+
+        // SetFileSecurity does not follow links so when following links we
+        // need the final target
+        String path = WindowsLinkSupport.getFinalPath(file, followLinks);
+
+        // ConvertStringSidToSid allocates memory for SID so must invoke
+        // LocalFree to free it when we are done
+        long pOwner = 0L;
+        try {
+            pOwner = ConvertStringSidToSid(owner.sidString());
+        } catch (WindowsException x) {
+            throw new IOException("Failed to get SID for " + owner.getName()
+                + ": " + x.errorString());
+        }
+
+        // Allocate buffer for security descriptor, initialize it, set
+        // owner information and update the file.
+        try {
+            NativeBuffer buffer = NativeBuffers.getNativeBuffer(SIZEOF_SECURITY_DESCRIPTOR);
+            try {
+                InitializeSecurityDescriptor(buffer.address());
+                SetSecurityDescriptorOwner(buffer.address(), pOwner);
+                // may need SeRestorePrivilege to set the owner
+                WindowsSecurity.Privilege priv =
+                    WindowsSecurity.enablePrivilege("SeRestorePrivilege");
+                try {
+                    SetFileSecurity(path,
+                                    OWNER_SECURITY_INFORMATION,
+                                    buffer.address());
+                } finally {
+                    priv.drop();
+                }
+            } catch (WindowsException x) {
+                x.rethrowAsIOException(file);
+            } finally {
+                buffer.release();
+            }
+        } finally {
+            LocalFree(pOwner);
+        }
+    }
+
+    @Override
+    public void setAcl(List<AclEntry> acl) throws IOException {
+        checkAccess(file, false, true);
+
+        // SetFileSecurity does not follow links so when following links we
+        // need the final target
+        String path = WindowsLinkSupport.getFinalPath(file, followLinks);
+        WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.create(acl);
+        try {
+            SetFileSecurity(path, DACL_SECURITY_INFORMATION, sd.address());
+        } catch (WindowsException x) {
+             x.rethrowAsIOException(file);
+        } finally {
+            sd.release();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.channels.*;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.*;
+
+import com.sun.nio.file.ExtendedOpenOption;
+
+import sun.nio.ch.FileChannelImpl;
+import sun.nio.ch.ThreadPool;
+import sun.nio.ch.WindowsAsynchronousFileChannelImpl;
+import sun.misc.SharedSecrets;
+import sun.misc.JavaIOFileDescriptorAccess;
+
+import static sun.nio.fs.WindowsNativeDispatcher.*;
+import static sun.nio.fs.WindowsConstants.*;
+
+/**
+ * Factory to create FileChannels and AsynchronousFileChannels.
+ */
+
+class WindowsChannelFactory {
+    private static final JavaIOFileDescriptorAccess fdAccess =
+        SharedSecrets.getJavaIOFileDescriptorAccess();
+
+    private WindowsChannelFactory() { }
+
+    /**
+     * Do not follow reparse points when opening an existing file. Do not fail
+     * if the file is a reparse point.
+     */
+    static final OpenOption OPEN_REPARSE_POINT = new OpenOption() { };
+
+    /**
+     * Represents the flags from a user-supplied set of open options.
+     */
+    private static class Flags {
+        boolean read;
+        boolean write;
+        boolean append;
+        boolean truncateExisting;
+        boolean create;
+        boolean createNew;
+        boolean deleteOnClose;
+        boolean sparse;
+        boolean overlapped;
+        boolean sync;
+        boolean dsync;
+
+        // non-standard
+        boolean shareRead = true;
+        boolean shareWrite = true;
+        boolean shareDelete = true;
+        boolean noFollowLinks;
+        boolean openReparsePoint;
+
+        static Flags toFlags(Set<? extends OpenOption> options) {
+            Flags flags = new Flags();
+            for (OpenOption option: options) {
+                if (option instanceof StandardOpenOption) {
+                    switch ((StandardOpenOption)option) {
+                        case READ : flags.read = true; break;
+                        case WRITE : flags.write = true; break;
+                        case APPEND : flags.append = true; break;
+                        case TRUNCATE_EXISTING : flags.truncateExisting = true; break;
+                        case CREATE : flags.create = true; break;
+                        case CREATE_NEW : flags.createNew = true; break;
+                        case DELETE_ON_CLOSE : flags.deleteOnClose = true; break;
+                        case SPARSE : flags.sparse = true; break;
+                        case SYNC : flags.sync = true; break;
+                        case DSYNC : flags.dsync = true; break;
+                        default: throw new UnsupportedOperationException();
+                    }
+                    continue;
+                }
+                if (option instanceof ExtendedOpenOption) {
+                    switch ((ExtendedOpenOption)option) {
+                        case NOSHARE_READ : flags.shareRead = false; break;
+                        case NOSHARE_WRITE : flags.shareWrite = false; break;
+                        case NOSHARE_DELETE : flags.shareDelete = false; break;
+                        default: throw new UnsupportedOperationException();
+                    }
+                    continue;
+                }
+                if (option == LinkOption.NOFOLLOW_LINKS) {
+                    flags.noFollowLinks = true;
+                    continue;
+                }
+                if (option == OPEN_REPARSE_POINT) {
+                    flags.openReparsePoint = true;
+                    continue;
+                }
+                if (option == null)
+                    throw new NullPointerException();
+                throw new UnsupportedOperationException();
+            }
+            return flags;
+        }
+    }
+
+    /**
+     * Open/creates file, returning FileChannel to access the file
+     *
+     * @param   pathForWindows
+     *          The path of the file to open/create
+     * @param   pathToCheck
+     *          The path used for permission checks (if security manager)
+     */
+    static FileChannel newFileChannel(String pathForWindows,
+                                      String pathToCheck,
+                                      Set<? extends OpenOption> options,
+                                      long pSecurityDescriptor)
+        throws WindowsException
+    {
+        Flags flags = Flags.toFlags(options);
+
+        // default is reading; append => writing
+        if (!flags.read && !flags.write) {
+            if (flags.append) {
+                flags.write = true;
+            } else {
+                flags.read = true;
+            }
+        }
+
+        // validation
+        if (flags.read && flags.append)
+            throw new IllegalArgumentException("READ + APPEND not allowed");
+        if (flags.append && flags.truncateExisting)
+            throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
+
+        FileDescriptor fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor);
+        return FileChannelImpl.open(fdObj, flags.read, flags.write, null);
+    }
+
+    /**
+     * Open/creates file, returning AsynchronousFileChannel to access the file
+     *
+     * @param   pathForWindows
+     *          The path of the file to open/create
+     * @param   pathToCheck
+     *          The path used for permission checks (if security manager)
+     * @param   pool
+     *          The thread pool that the channel is associated with
+     */
+    static AsynchronousFileChannel newAsynchronousFileChannel(String pathForWindows,
+                                                              String pathToCheck,
+                                                              Set<? extends OpenOption> options,
+                                                              long pSecurityDescriptor,
+                                                              ThreadPool pool)
+        throws IOException
+    {
+        Flags flags = Flags.toFlags(options);
+
+        // Overlapped I/O required
+        flags.overlapped = true;
+
+        // default is reading
+        if (!flags.read && !flags.write) {
+            flags.read = true;
+        }
+
+        // validation
+        if (flags.append)
+            throw new UnsupportedOperationException("APPEND not allowed");
+
+        // open file for overlapped I/O
+        FileDescriptor fdObj;
+        try {
+            fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(pathForWindows);
+            return null;
+        }
+
+        // create the AsynchronousFileChannel
+        try {
+            return WindowsAsynchronousFileChannelImpl.open(fdObj, flags.read, flags.write, pool);
+        } catch (IOException x) {
+            // IOException is thrown if the file handle cannot be associated
+            // with the completion port. All we can do is close the file.
+            long handle = fdAccess.getHandle(fdObj);
+            CloseHandle(handle);
+            throw x;
+        }
+    }
+
+    /**
+     * Opens file based on parameters and options, returning a FileDescriptor
+     * encapsulating the handle to the open file.
+     */
+    private static FileDescriptor open(String pathForWindows,
+                                       String pathToCheck,
+                                       Flags flags,
+                                       long pSecurityDescriptor)
+        throws WindowsException
+    {
+        // set to true if file must be truncated after open
+        boolean truncateAfterOpen = false;
+
+        // map options
+        int dwDesiredAccess = 0;
+        if (flags.read)
+            dwDesiredAccess |= GENERIC_READ;
+        if (flags.write)
+            dwDesiredAccess |= (flags.append) ? FILE_APPEND_DATA : GENERIC_WRITE;
+
+        int dwShareMode = 0;
+        if (flags.shareRead)
+            dwShareMode |= FILE_SHARE_READ;
+        if (flags.shareWrite)
+            dwShareMode |= FILE_SHARE_WRITE;
+        if (flags.shareDelete)
+            dwShareMode |= FILE_SHARE_DELETE;
+
+        int dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
+        int dwCreationDisposition = OPEN_EXISTING;
+        if (flags.write) {
+            if (flags.createNew) {
+                dwCreationDisposition = CREATE_NEW;
+                // force create to fail if file is orphaned reparse point
+                dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
+            } else {
+                if (flags.create)
+                    dwCreationDisposition = OPEN_ALWAYS;
+                if (flags.truncateExisting) {
+                    // Windows doesn't have a creation disposition that exactly
+                    // corresponds to CREATE + TRUNCATE_EXISTING so we use
+                    // the OPEN_ALWAYS mode and then truncate the file.
+                    if (dwCreationDisposition == OPEN_ALWAYS) {
+                        truncateAfterOpen = true;
+                    } else {
+                        dwCreationDisposition = TRUNCATE_EXISTING;
+                    }
+                }
+            }
+        }
+
+        if (flags.dsync || flags.sync)
+            dwFlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
+        if (flags.overlapped)
+            dwFlagsAndAttributes |= FILE_FLAG_OVERLAPPED;
+        if (flags.deleteOnClose)
+            dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
+
+        // NOFOLLOW_LINKS and NOFOLLOW_REPARSEPOINT mean open reparse point
+        boolean okayToFollowLinks = true;
+        if (dwCreationDisposition != CREATE_NEW &&
+            (flags.noFollowLinks ||
+             flags.openReparsePoint ||
+             flags.deleteOnClose))
+        {
+            if (flags.noFollowLinks || flags.deleteOnClose)
+                okayToFollowLinks = false;
+            dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
+        }
+
+        // permission check
+        if (pathToCheck != null) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                if (flags.read)
+                    sm.checkRead(pathToCheck);
+                if (flags.write)
+                    sm.checkWrite(pathToCheck);
+                if (flags.deleteOnClose)
+                    sm.checkDelete(pathToCheck);
+            }
+        }
+
+        // open file
+        long handle = CreateFile(pathForWindows,
+                                 dwDesiredAccess,
+                                 dwShareMode,
+                                 pSecurityDescriptor,
+                                 dwCreationDisposition,
+                                 dwFlagsAndAttributes);
+
+        // make sure this isn't a symbolic link.
+        if (!okayToFollowLinks) {
+            try {
+                if (WindowsFileAttributes.readAttributes(handle).isSymbolicLink())
+                    throw new WindowsException("File is symbolic link");
+            } catch (WindowsException x) {
+                CloseHandle(handle);
+                throw x;
+            }
+        }
+
+        // truncate file (for CREATE + TRUNCATE_EXISTING case)
+        if (truncateAfterOpen) {
+            try {
+                SetEndOfFile(handle);
+            } catch (WindowsException x) {
+                CloseHandle(handle);
+                throw x;
+            }
+        }
+
+        // make the file sparse if needed
+        if (dwCreationDisposition == CREATE_NEW && flags.sparse) {
+            try {
+                DeviceIoControlSetSparse(handle);
+            } catch (WindowsException x) {
+                // ignore as sparse option is hint
+            }
+        }
+
+        // create FileDescriptor and return
+        FileDescriptor fdObj = new FileDescriptor();
+        fdAccess.setHandle(fdObj, handle);
+        return fdObj;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+/**
+ * Win32 APIs constants.
+ */
+
+class WindowsConstants {
+    private WindowsConstants() { }
+
+    // general
+    public static final long INVALID_HANDLE_VALUE = -1L;
+
+    // generic rights
+    public static final int GENERIC_READ        = 0x80000000;
+    public static final int GENERIC_WRITE       = 0x40000000;
+
+    // share modes
+    public static final int FILE_SHARE_READ     = 0x00000001;
+    public static final int FILE_SHARE_WRITE    = 0x00000002;
+    public static final int FILE_SHARE_DELETE   = 0x00000004;
+
+    // creation modes
+    public static final int CREATE_NEW          = 1;
+    public static final int CREATE_ALWAYS       = 2;
+    public static final int OPEN_EXISTING       = 3;
+    public static final int OPEN_ALWAYS         = 4;
+    public static final int TRUNCATE_EXISTING   = 5;
+
+    // attributes and flags
+    public static final int FILE_ATTRIBUTE_READONLY         = 0x00000001;
+    public static final int FILE_ATTRIBUTE_HIDDEN           = 0x00000002;
+    public static final int FILE_ATTRIBUTE_SYSTEM           = 0x00000004;
+    public static final int FILE_ATTRIBUTE_DIRECTORY        = 0x00000010;
+    public static final int FILE_ATTRIBUTE_ARCHIVE          = 0x00000020;
+    public static final int FILE_ATTRIBUTE_DEVICE           = 0x00000040;
+    public static final int FILE_ATTRIBUTE_NORMAL           = 0x00000080;
+    public static final int FILE_ATTRIBUTE_REPARSE_POINT    = 0x400;
+    public static final int FILE_FLAG_NO_BUFFERING          = 0x20000000;
+    public static final int FILE_FLAG_OVERLAPPED            = 0x40000000;
+    public static final int FILE_FLAG_WRITE_THROUGH         = 0x80000000;
+    public static final int FILE_FLAG_BACKUP_SEMANTICS      = 0x02000000;
+    public static final int FILE_FLAG_DELETE_ON_CLOSE       = 0x04000000;
+    public static final int FILE_FLAG_OPEN_REPARSE_POINT    = 0x00200000;
+
+    // stream ids
+    public static final int BACKUP_ALTERNATE_DATA           = 0x00000004;
+    public static final int BACKUP_SPARSE_BLOCK             = 0x00000009;
+
+    // reparse point/symbolic link related constants
+    public static final int IO_REPARSE_TAG_SYMLINK              = 0xA000000C;
+    public static final int MAXIMUM_REPARSE_DATA_BUFFER_SIZE    = 16 * 1024;
+    public static final int SYMBOLIC_LINK_FLAG_DIRECTORY        = 0x1;
+
+    // volume flags
+    public static final int FILE_CASE_SENSITIVE_SEARCH      = 0x00000001;
+    public static final int FILE_CASE_PRESERVED_NAMES       = 0x00000002;
+    public static final int FILE_PERSISTENT_ACLS            = 0x00000008;
+    public static final int FILE_VOLUME_IS_COMPRESSED       = 0x00008000;
+    public static final int FILE_NAMED_STREAMS              = 0x00040000;
+    public static final int FILE_READ_ONLY_VOLUME           = 0x00080000;
+
+    // error codes
+    public static final int ERROR_FILE_NOT_FOUND        = 2;
+    public static final int ERROR_PATH_NOT_FOUND        = 3;
+    public static final int ERROR_ACCESS_DENIED         = 5;
+    public static final int ERROR_INVALID_HANDLE        = 6;
+    public static final int ERROR_INVALID_DATA          = 13;
+    public static final int ERROR_NOT_SAME_DEVICE       = 17;
+    public static final int ERROR_NOT_READY             = 21;
+    public static final int ERROR_FILE_EXISTS           = 80;
+    public static final int ERROR_DISK_FULL             = 112;
+    public static final int ERROR_INSUFFICIENT_BUFFER   = 122;
+    public static final int ERROR_INVALID_LEVEL         = 124;
+    public static final int ERROR_DIR_NOT_EMPTY         = 145;
+    public static final int ERROR_ALREADY_EXISTS        = 183;
+    public static final int ERROR_DIRECTORY             = 267;
+    public static final int ERROR_NOTIFY_ENUM_DIR       = 1022;
+    public static final int ERROR_NONE_MAPPED           = 1332;
+    public static final int ERROR_NOT_A_REPARSE_POINT   = 4390;
+    public static final int ERROR_INVALID_REPARSE_DATA  = 4392;
+
+    // notify filters
+    public static final int FILE_NOTIFY_CHANGE_FILE_NAME   = 0x00000001;
+    public static final int FILE_NOTIFY_CHANGE_DIR_NAME    = 0x00000002;
+    public static final int FILE_NOTIFY_CHANGE_ATTRIBUTES  = 0x00000004;
+    public static final int FILE_NOTIFY_CHANGE_SIZE        = 0x00000008;
+    public static final int FILE_NOTIFY_CHANGE_LAST_WRITE  = 0x00000010;
+    public static final int FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x00000020;
+    public static final int FILE_NOTIFY_CHANGE_CREATION    = 0x00000040;
+    public static final int FILE_NOTIFY_CHANGE_SECURITY    = 0x00000100;
+
+    // notify actions
+    public final static int FILE_ACTION_ADDED              = 0x00000001;
+    public final static int FILE_ACTION_REMOVED            = 0x00000002;
+    public final static int FILE_ACTION_MODIFIED           = 0x00000003;
+    public final static int FILE_ACTION_RENAMED_OLD_NAME   = 0x00000004;
+    public final static int FILE_ACTION_RENAMED_NEW_NAME   = 0x00000005;
+
+    // copy flags
+    public static final int COPY_FILE_FAIL_IF_EXISTS       = 0x00000001;
+    public static final int COPY_FILE_COPY_SYMLINK         = 0x00000800;
+
+    // move flags
+    public static final int MOVEFILE_REPLACE_EXISTING       = 0x00000001;
+    public static final int MOVEFILE_COPY_ALLOWED           = 0x00000002;
+
+    // drive types
+    public static final int DRIVE_UNKNOWN                   = 0;
+    public static final int DRIVE_NO_ROOT_DIR               = 1;
+    public static final int DRIVE_REMOVABLE                 = 2;
+    public static final int DRIVE_FIXED                     = 3;
+    public static final int DRIVE_REMOTE                    = 4;
+    public static final int DRIVE_CDROM                     = 5;
+    public static final int DRIVE_RAMDISK                   = 6;
+
+    // file security
+    public static final int OWNER_SECURITY_INFORMATION      = 0x00000001;
+    public static final int GROUP_SECURITY_INFORMATION      = 0x00000002;
+    public static final int DACL_SECURITY_INFORMATION       = 0x00000004;
+    public static final int SACL_SECURITY_INFORMATION       = 0x00000008;
+
+    public static final int SidTypeUser = 1;
+    public static final int SidTypeGroup = 2;
+    public static final int SidTypeDomain = 3;
+    public static final int SidTypeAlias = 4;
+    public static final int SidTypeWellKnownGroup = 5;
+    public static final int SidTypeDeletedAccount = 6;
+    public static final int SidTypeInvalid = 7;
+    public static final int SidTypeUnknown = 8;
+    public static final int SidTypeComputer= 9;
+
+    public static final byte ACCESS_ALLOWED_ACE_TYPE         = 0x0;
+    public static final byte ACCESS_DENIED_ACE_TYPE          = 0x1;
+
+    public static final byte OBJECT_INHERIT_ACE              = 0x1;
+    public static final byte CONTAINER_INHERIT_ACE           = 0x2;
+    public static final byte NO_PROPAGATE_INHERIT_ACE        = 0x4;
+    public static final byte INHERIT_ONLY_ACE                = 0x8;
+
+    public static final int DELETE                      = 0x00010000;
+    public static final int READ_CONTROL                = 0x00020000;
+    public static final int WRITE_DAC                   = 0x00040000;
+    public static final int WRITE_OWNER                 = 0x00080000;
+    public static final int SYNCHRONIZE                 = 0x00100000;
+
+    public static final int FILE_LIST_DIRECTORY         = 0x0001;
+    public static final int FILE_READ_DATA              = 0x0001;
+    public static final int FILE_WRITE_DATA             = 0x0002;
+    public static final int FILE_APPEND_DATA            = 0x0004;
+    public static final int FILE_READ_EA                = 0x0008;
+    public static final int FILE_WRITE_EA               = 0x0010;
+    public static final int FILE_EXECUTE                = 0x0020;
+    public static final int FILE_DELETE_CHILD           = 0x0040;
+    public static final int FILE_READ_ATTRIBUTES        = 0x0080;
+    public static final int FILE_WRITE_ATTRIBUTES       = 0x0100;
+
+    // operating system security
+    public static final int TOKEN_DUPLICATE             = 0x0002;
+    public static final int TOKEN_IMPERSONATE           = 0x0004;
+    public static final int TOKEN_QUERY                 = 0x0008;
+    public static final int TOKEN_ADJUST_PRIVILEGES     = 0x0020;
+
+    public static final int SE_PRIVILEGE_ENABLED        = 0x00000002;
+
+    public static final int TokenUser                   = 1;
+    public static final int PROCESS_QUERY_INFORMATION   = 0x0400;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.util.Iterator;
+import java.util.ConcurrentModificationException;
+import java.util.NoSuchElementException;
+import java.io.IOException;
+
+import static sun.nio.fs.WindowsNativeDispatcher.*;
+import static sun.nio.fs.WindowsConstants.*;
+
+/**
+ * Windows implementation of DirectoryStream
+ */
+
+class WindowsDirectoryStream
+    implements DirectoryStream<Path>
+{
+    private final WindowsPath dir;
+    private final DirectoryStream.Filter<? super Path> filter;
+
+    // handle to directory
+    private final long handle;
+    // first entry in the directory
+    private final String firstName;
+
+    private final Object closeLock = new Object();
+
+    // need closeLock to access these
+    private boolean isOpen = true;
+    private Iterator<Path> iterator;
+
+
+    WindowsDirectoryStream(WindowsPath dir, DirectoryStream.Filter<? super Path> filter)
+        throws IOException
+    {
+        this.dir = dir;
+        this.filter = filter;
+
+        try {
+            // Need to append * or \* to match entries in directory.
+            String search = dir.getPathForWin32Calls();
+            char last = search.charAt(search.length() -1);
+            if (last == ':' || last == '\\') {
+                search += "*";
+            } else {
+                search += "\\*";
+            }
+
+            FirstFile first = FindFirstFile(search);
+            this.handle = first.handle();
+            this.firstName = first.name();
+        } catch (WindowsException x) {
+            if (x.lastError() == ERROR_DIRECTORY) {
+                throw new NotDirectoryException(dir.getPathForExceptionMessage());
+            }
+            x.rethrowAsIOException(dir);
+
+            // keep compiler happy
+            throw new AssertionError();
+        }
+    }
+
+    @Override
+    public void close()
+        throws IOException
+    {
+        synchronized (closeLock) {
+            if (!isOpen)
+                return;
+            isOpen = false;
+        }
+        try {
+            FindClose(handle);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(dir);
+        }
+    }
+
+    @Override
+    public Iterator<Path> iterator() {
+        if (!isOpen) {
+            throw new IllegalStateException("Directory stream is closed");
+        }
+        synchronized (this) {
+            if (iterator != null)
+                throw new IllegalStateException("Iterator already obtained");
+            iterator = new WindowsDirectoryIterator(firstName);
+            return iterator;
+        }
+    }
+
+    private static void throwAsConcurrentModificationException(Throwable t) {
+        ConcurrentModificationException cme = new ConcurrentModificationException();
+        cme.initCause(t);
+        throw cme;
+    }
+
+    private class WindowsDirectoryIterator implements Iterator<Path> {
+        private boolean atEof;
+        private String first;
+        private Path nextEntry;
+        private Path prevEntry;
+
+        WindowsDirectoryIterator(String first) {
+            atEof = false;
+            this.first = first;
+        }
+
+        // applies filter and also ignores "." and ".."
+        private Path acceptEntry(String s) {
+            if (s.equals(".") || s.equals(".."))
+                return null;
+            Path entry = WindowsPath
+                .createFromNormalizedPath(dir.getFileSystem(), dir + "\\" + s);
+            if (filter.accept(entry)) {
+                return entry;
+            } else {
+                return null;
+            }
+        }
+
+        // reads next directory entry
+        private Path readNextEntry() {
+            // handle first element returned by search
+            if (first != null) {
+                nextEntry = acceptEntry(first);
+                first = null;
+                if (nextEntry != null)
+                    return nextEntry;
+            }
+
+            String name = null;
+            for (;;) {
+                // synchronize on closeLock to prevent close while reading
+                synchronized (closeLock) {
+                    if (!isOpen)
+                        throwAsConcurrentModificationException(new
+                            IllegalStateException("Directory stream is closed"));
+                    try {
+                        name = FindNextFile(handle);
+                    } catch (WindowsException x) {
+                        try {
+                            x.rethrowAsIOException(dir);
+                        } catch (IOException ioe) {
+                            throwAsConcurrentModificationException(ioe);
+                        }
+                    }
+                }
+
+                // EOF
+                if (name == null)
+                    return null;
+
+                Path entry = acceptEntry(name);
+                if (entry != null)
+                    return entry;
+            }
+        }
+
+        @Override
+        public synchronized boolean hasNext() {
+            if (nextEntry == null && !atEof) {
+                nextEntry = readNextEntry();
+                atEof = (nextEntry == null);
+            }
+            return nextEntry != null;
+        }
+
+        @Override
+        public synchronized Path next() {
+            if (nextEntry == null) {
+                if (!atEof) {
+                    nextEntry = readNextEntry();
+                }
+                if (nextEntry == null) {
+                    atEof = true;
+                    throw new NoSuchElementException();
+                }
+            }
+            prevEntry = nextEntry;
+            nextEntry = null;
+            return prevEntry;
+        }
+
+        @Override
+        public void remove() {
+            if (!isOpen) {
+                throw new IllegalStateException("Directory stream is closed");
+            }
+            Path entry;
+            synchronized (this) {
+                if (prevEntry == null)
+                    throw new IllegalStateException("no last element");
+                entry = prevEntry;
+                prevEntry = null;
+            }
+            try {
+                entry.delete(true);
+            } catch (IOException ioe) {
+                throwAsConcurrentModificationException(ioe);
+            } catch (SecurityException se) {
+                throwAsConcurrentModificationException(se);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsException.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.io.IOException;
+
+import static sun.nio.fs.WindowsConstants.*;
+
+/**
+ * Internal exception thrown when a Win32 calls fails.
+ */
+
+class WindowsException extends Exception {
+    static final long serialVersionUID = 2765039493083748820L;
+
+    private int lastError;
+    private String msg;
+
+    WindowsException(int lastError) {
+        this.lastError = lastError;
+        this.msg = null;
+    }
+
+    WindowsException(String msg) {
+        this.lastError = 0;
+        this.msg = msg;
+    }
+
+    int lastError() {
+        return lastError;
+    }
+
+    String errorString() {
+        if (msg == null) {
+            msg = WindowsNativeDispatcher.FormatMessage(lastError);
+            if (msg == null) {
+                msg = "Unknown error: 0x" + Integer.toHexString(lastError);
+            }
+        }
+        return msg;
+    }
+
+    @Override
+    public String getMessage() {
+        return errorString();
+    }
+
+    private IOException translateToIOException(String file, String other) {
+        // not created with last error
+        if (lastError() == 0)
+            return new IOException(errorString());
+
+        // handle specific cases
+        if (lastError() == ERROR_FILE_NOT_FOUND || lastError() == ERROR_PATH_NOT_FOUND)
+            return new NoSuchFileException(file, other, null);
+        if (lastError() == ERROR_FILE_EXISTS || lastError() == ERROR_ALREADY_EXISTS)
+            return new FileAlreadyExistsException(file, other, null);
+        if (lastError() == ERROR_ACCESS_DENIED)
+            return new AccessDeniedException(file, other, null);
+
+        // fallback to the more general exception
+        return new FileSystemException(file, other, errorString());
+    }
+
+    void rethrowAsIOException(String file) throws IOException {
+        IOException x = translateToIOException(file, null);
+        throw x;
+    }
+
+    void rethrowAsIOException(WindowsPath file, WindowsPath other) throws IOException {
+        String a = (file == null) ? null : file.getPathForExceptionMessage();
+        String b = (other == null) ? null : other.getPathForExceptionMessage();
+        IOException x = translateToIOException(a, b);
+        throw x;
+    }
+
+    void rethrowAsIOException(WindowsPath file) throws IOException {
+        rethrowAsIOException(file, null);
+    }
+
+    IOException asIOException(WindowsPath file) {
+        return translateToIOException(file.getPathForExceptionMessage(), null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.io.IOException;
+
+import static sun.nio.fs.WindowsNativeDispatcher.*;
+import static sun.nio.fs.WindowsConstants.*;
+
+class WindowsFileAttributeViews {
+
+    private static class Basic extends AbstractBasicFileAttributeView {
+        final WindowsPath file;
+        final boolean followLinks;
+
+        Basic(WindowsPath file, boolean followLinks) {
+            this.file = file;
+            this.followLinks = followLinks;
+        }
+
+        @Override
+        public WindowsFileAttributes readAttributes() throws IOException {
+            try {
+                return WindowsFileAttributes.get(file, followLinks);
+            } catch (WindowsException x) {
+                x.rethrowAsIOException(file);
+                return null;    // keep compiler happy
+            }
+        }
+
+        /**
+         * Parameter values in Windows times.
+         */
+        void setFileTimes(long createTime, long lastAccessTime, long lastWriteTime)
+            throws IOException
+        {
+            long handle = -1L;
+            try {
+                int flags = FILE_FLAG_BACKUP_SEMANTICS;
+                if (!followLinks && file.getFileSystem().supportsLinks())
+                    flags |= FILE_FLAG_OPEN_REPARSE_POINT;
+
+                handle = CreateFile(file.getPathForWin32Calls(),
+                                    FILE_WRITE_ATTRIBUTES,
+                                    (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
+                                    OPEN_EXISTING,
+                                    flags);
+            } catch (WindowsException x) {
+                x.rethrowAsIOException(file);
+            }
+
+            // update attributes
+            try {
+                SetFileTime(handle, createTime, lastAccessTime, lastWriteTime);
+            } catch (WindowsException x) {
+                x.rethrowAsIOException(file);
+            } finally {
+                CloseHandle(handle);
+            }
+        }
+
+        @Override
+        public void setTimes(Long lastModifiedTime,
+                             Long lastAccessTime,
+                             Long createTime,
+                             TimeUnit unit) throws IOException
+        {
+            file.checkWrite();
+
+            // if all null then do nothing
+            if (lastModifiedTime == null && lastAccessTime == null &&
+                createTime == null)
+            {
+                // no effect
+                return;
+            }
+
+            // null => no change
+            // -1 => change to current time
+            long now = System.currentTimeMillis();
+            long modTime = 0L, accTime = 0L, crTime = 0L;
+            if (lastModifiedTime != null) {
+                if (lastModifiedTime < 0L) {
+                    if (lastModifiedTime != -1L)
+                        throw new IllegalArgumentException();
+                    modTime = now;
+                } else {
+                    modTime = TimeUnit.MILLISECONDS.convert(lastModifiedTime, unit);
+                }
+                modTime = WindowsFileAttributes.toWindowsTime(modTime);
+            }
+            if (lastAccessTime != null) {
+                if (lastAccessTime < 0L) {
+                    if (lastAccessTime != -1L)
+                        throw new IllegalArgumentException();
+                    accTime = now;
+                } else {
+                    accTime = TimeUnit.MILLISECONDS.convert(lastAccessTime, unit);
+                }
+                accTime = WindowsFileAttributes.toWindowsTime(accTime);
+            }
+            if (createTime != null) {
+                if (createTime < 0L) {
+                    if (createTime != -1L)
+                        throw new IllegalArgumentException();
+                    crTime = now;
+                } else {
+                    crTime = TimeUnit.MILLISECONDS.convert(createTime, unit);
+                }
+                crTime = WindowsFileAttributes.toWindowsTime(crTime);
+            }
+
+            setFileTimes(crTime, accTime, modTime);
+        }
+    }
+
+    static class Dos extends Basic implements DosFileAttributeView {
+        private static final String READONLY_NAME = "readonly";
+        private static final String ARCHIVE_NAME = "archive";
+        private static final String SYSTEM_NAME = "system";
+        private static final String HIDDEN_NAME = "hidden";
+        private static final String ATTRIBUTES_NAME = "attributes";
+
+        Dos(WindowsPath file, boolean followLinks) {
+            super(file, followLinks);
+        }
+
+        @Override
+        public String name() {
+            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
+        {
+            if (attribute.equals(READONLY_NAME)) {
+                setReadOnly((Boolean)value);
+                return;
+            }
+            if (attribute.equals(ARCHIVE_NAME)) {
+                setArchive((Boolean)value);
+                return;
+            }
+            if (attribute.equals(SYSTEM_NAME)) {
+                setSystem((Boolean)value);
+                return;
+            }
+            if (attribute.equals(HIDDEN_NAME)) {
+                setHidden((Boolean)value);
+                return;
+            }
+            super.setAttribute(attribute, value);
+        }
+
+        @Override
+        public Map<String,?> readAttributes(String first, String[] rest)
+            throws IOException
+        {
+            AttributesBuilder builder = AttributesBuilder.create(first, rest);
+            WindowsFileAttributes attrs = readAttributes();
+            addBasicAttributesToBuilder(attrs, builder);
+            if (builder.match(READONLY_NAME))
+                builder.add(READONLY_NAME, attrs.isReadOnly());
+            if (builder.match(ARCHIVE_NAME))
+                builder.add(ARCHIVE_NAME, attrs.isArchive());
+            if (builder.match(SYSTEM_NAME))
+                builder.add(SYSTEM_NAME, attrs.isSystem());
+            if (builder.match(HIDDEN_NAME))
+                builder.add(HIDDEN_NAME, attrs.isHidden());
+            if (builder.match(ATTRIBUTES_NAME))
+                builder.add(ATTRIBUTES_NAME, attrs.attributes());
+            return builder.unmodifiableMap();
+        }
+
+        /**
+         * Update DOS attributes
+         */
+        private void updateAttributes(int flag, boolean enable)
+            throws IOException
+        {
+            file.checkWrite();
+
+            // GetFileAttribtues & SetFileAttributes do not follow links so when
+            // following links we need the final target
+            String path = WindowsLinkSupport.getFinalPath(file, followLinks);
+            try {
+                int oldValue = GetFileAttributes(path);
+                int newValue = oldValue;
+                if (enable) {
+                    newValue |= flag;
+                } else {
+                    newValue &= ~flag;
+                }
+                if (newValue != oldValue) {
+                    SetFileAttributes(path, newValue);
+                }
+            } catch (WindowsException x) {
+                // don't reveal target in exception
+                x.rethrowAsIOException(file);
+            }
+        }
+
+        @Override
+        public void setReadOnly(boolean value) throws IOException {
+            updateAttributes(FILE_ATTRIBUTE_READONLY, value);
+        }
+
+        @Override
+        public void setHidden(boolean value) throws IOException {
+            updateAttributes(FILE_ATTRIBUTE_HIDDEN, value);
+        }
+
+        @Override
+        public void setArchive(boolean value) throws IOException {
+            updateAttributes(FILE_ATTRIBUTE_ARCHIVE, value);
+        }
+
+        @Override
+        public void setSystem(boolean value) throws IOException {
+            updateAttributes(FILE_ATTRIBUTE_SYSTEM, value);
+        }
+
+        // package-private
+        // Copy given attributes to the file.
+        void setAttributes(WindowsFileAttributes attrs)
+            throws IOException
+        {
+            // copy DOS attributes to target
+            int flags = 0;
+            if (attrs.isReadOnly()) flags |= FILE_ATTRIBUTE_READONLY;
+            if (attrs.isHidden()) flags |= FILE_ATTRIBUTE_HIDDEN;
+            if (attrs.isArchive()) flags |= FILE_ATTRIBUTE_ARCHIVE;
+            if (attrs.isSystem()) flags |= FILE_ATTRIBUTE_SYSTEM;
+            updateAttributes(flags, true);
+
+            // copy file times to target - must be done after updating FAT attributes
+            // as otherwise the last modified time may be wrong.
+            setFileTimes(
+                WindowsFileAttributes.toWindowsTime(attrs.creationTime()),
+                WindowsFileAttributes.toWindowsTime(attrs.lastModifiedTime()),
+                WindowsFileAttributes.toWindowsTime(attrs.lastAccessTime()));
+        }
+    }
+
+    static BasicFileAttributeView createBasicView(WindowsPath file, boolean followLinks) {
+        return new Basic(file, followLinks);
+    }
+
+    static WindowsFileAttributeViews.Dos createDosView(WindowsPath file, boolean followLinks) {
+        return new Dos(file, followLinks);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,403 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.attribute.*;
+import java.util.concurrent.TimeUnit;
+import java.security.AccessController;
+import sun.misc.Unsafe;
+import sun.security.action.GetPropertyAction;
+
+import static sun.nio.fs.WindowsNativeDispatcher.*;
+import static sun.nio.fs.WindowsConstants.*;
+
+/**
+ * Windows implementation of DosFileAttributes/BasicFileAttributes
+ */
+
+class WindowsFileAttributes
+    implements DosFileAttributes
+{
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    /*
+     * typedef struct _BY_HANDLE_FILE_INFORMATION {
+     *     DWORD    dwFileAttributes;
+     *     FILETIME ftCreationTime;
+     *     FILETIME ftLastAccessTime;
+     *     FILETIME ftLastWriteTime;
+     *     DWORD    dwVolumeSerialNumber;
+     *     DWORD    nFileSizeHigh;
+     *     DWORD    nFileSizeLow;
+     *     DWORD    nNumberOfLinks;
+     *     DWORD    nFileIndexHigh;
+     *     DWORD    nFileIndexLow;
+     * } BY_HANDLE_FILE_INFORMATION;
+     */
+    private static final short SIZEOF_FILE_INFORMATION  = 52;
+    private static final short OFFSETOF_FILE_INFORMATION_ATTRIBUTES      = 0;
+    private static final short OFFSETOF_FILE_INFORMATION_CREATETIME      = 4;
+    private static final short OFFSETOF_FILE_INFORMATION_LASTACCESSTIME  = 12;
+    private static final short OFFSETOF_FILE_INFORMATION_LASTWRITETIME   = 20;
+    private static final short OFFSETOF_FILE_INFORMATION_VOLSERIALNUM    = 28;
+    private static final short OFFSETOF_FILE_INFORMATION_SIZEHIGH        = 32;
+    private static final short OFFSETOF_FILE_INFORMATION_SIZELOW         = 36;
+    private static final short OFFSETOF_FILE_INFORMATION_NUMLINKS        = 40;
+    private static final short OFFSETOF_FILE_INFORMATION_INDEXHIGH       = 44;
+    private static final short OFFSETOF_FILE_INFORMATION_INDEXLOW        = 48;
+
+    /*
+     * typedef struct _WIN32_FILE_ATTRIBUTE_DATA {
+     *   DWORD dwFileAttributes;
+     *   FILETIME ftCreationTime;
+     *   FILETIME ftLastAccessTime;
+     *   FILETIME ftLastWriteTime;
+     *   DWORD nFileSizeHigh;
+     *   DWORD nFileSizeLow;
+     * } WIN32_FILE_ATTRIBUTE_DATA;
+     */
+    private static final short SIZEOF_FILE_ATTRIBUTE_DATA = 36;
+    private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES      = 0;
+    private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_CREATETIME      = 4;
+    private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_LASTACCESSTIME  = 12;
+    private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_LASTWRITETIME   = 20;
+    private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_SIZEHIGH        = 28;
+    private static final short OFFSETOF_FILE_ATTRIBUTE_DATA_SIZELOW         = 32;
+
+    // indicates if accurate metadata is required (interesting on NTFS only)
+    private static final boolean ensureAccurateMetadata;
+    static {
+        String propValue = AccessController.doPrivileged(
+            new GetPropertyAction("sun.nio.fs.ensureAccurateMetadata", "false"));
+        ensureAccurateMetadata = (propValue.length() == 0) ?
+            true : Boolean.valueOf(propValue);
+    }
+
+    // attributes
+    private final int fileAttrs;
+    private final long creationTime;
+    private final long lastAccessTime;
+    private final long lastWriteTime;
+    private final long size;
+    private final int reparseTag;
+
+    // additional attributes when using GetFileInformationByHandle
+    private final int linkCount;
+    private final int volSerialNumber;
+    private final int fileIndexHigh;
+    private final int fileIndexLow;
+
+    /**
+     * Convert 64-bit value representing the number of 100-nanosecond intervals
+     * since January 1, 1601 to java time.
+     */
+    private static long toJavaTime(long time) {
+        time /= 10000L;
+        time -= 11644473600000L;
+        return time;
+    }
+
+    /**
+     * Convert java time to 64-bit value representing the number of 100-nanosecond
+     * intervals since January 1, 1601.
+     */
+    static long toWindowsTime(long time) {
+        time += 11644473600000L;
+        time *= 10000L;
+        return time;
+    }
+
+    /**
+     * Initialize a new instance of this class
+     */
+    private WindowsFileAttributes(int fileAttrs,
+                                  long creationTime,
+                                  long lastAccessTime,
+                                  long lastWriteTime,
+                                  long size,
+                                  int reparseTag,
+                                  int linkCount,
+                                  int volSerialNumber,
+                                  int fileIndexHigh,
+                                  int fileIndexLow)
+    {
+        this.fileAttrs = fileAttrs;
+        this.creationTime = creationTime;
+        this.lastAccessTime = lastAccessTime;
+        this.lastWriteTime = lastWriteTime;
+        this.size = size;
+        this.reparseTag = reparseTag;
+        this.linkCount = linkCount;
+        this.volSerialNumber = volSerialNumber;
+        this.fileIndexHigh = fileIndexHigh;
+        this.fileIndexLow = fileIndexLow;
+    }
+
+    /**
+     * Create a WindowsFileAttributes from a BY_HANDLE_FILE_INFORMATION structure
+     */
+    private static WindowsFileAttributes fromFileInformation(long address, int reparseTag) {
+        int fileAttrs = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES);
+        long creationTime =
+            toJavaTime(unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_CREATETIME));
+        long lastAccessTime =
+            toJavaTime(unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_LASTACCESSTIME));
+        long lastWriteTime =
+            toJavaTime(unsafe.getLong(address + OFFSETOF_FILE_INFORMATION_LASTWRITETIME));
+        long size = ((long)(unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_SIZEHIGH)) << 32)
+            + (unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_SIZELOW) & 0xFFFFFFFFL);
+        int linkCount = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_NUMLINKS);
+        int volSerialNumber = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_VOLSERIALNUM);
+        int fileIndexHigh = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_INDEXHIGH);
+        int fileIndexLow = unsafe.getInt(address + OFFSETOF_FILE_INFORMATION_INDEXLOW);
+        return new WindowsFileAttributes(fileAttrs,
+                                         creationTime,
+                                         lastAccessTime,
+                                         lastWriteTime,
+                                         size,
+                                         reparseTag,
+                                         linkCount,
+                                         volSerialNumber,
+                                         fileIndexHigh,
+                                         fileIndexLow);
+    }
+
+    /**
+     * Create a WindowsFileAttributes from a WIN32_FILE_ATTRIBUTE_DATA structure
+     */
+    private static WindowsFileAttributes fromFileAttributeData(long address, int reparseTag) {
+        int fileAttrs = unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES);
+        long creationTime =
+            toJavaTime(unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_CREATETIME));
+        long lastAccessTime =
+            toJavaTime(unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_LASTACCESSTIME));
+        long lastWriteTime =
+            toJavaTime(unsafe.getLong(address + OFFSETOF_FILE_ATTRIBUTE_DATA_LASTWRITETIME));
+        long size = ((long)(unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_SIZEHIGH)) << 32)
+            + (unsafe.getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_SIZELOW) & 0xFFFFFFFFL);
+        return new WindowsFileAttributes(fileAttrs,
+                                         creationTime,
+                                         lastAccessTime,
+                                         lastWriteTime,
+                                         size,
+                                         reparseTag,
+                                         1,  // linkCount
+                                         0,  // volSerialNumber
+                                         0,  // fileIndexHigh
+                                         0); // fileIndexLow
+    }
+
+    /**
+     * Reads the attributes of an open file
+     */
+    static WindowsFileAttributes readAttributes(long handle)
+        throws WindowsException
+    {
+        NativeBuffer buffer = NativeBuffers
+            .getNativeBuffer(SIZEOF_FILE_INFORMATION);
+        try {
+            long address = buffer.address();
+            GetFileInformationByHandle(handle, address);
+
+            // if file is a reparse point then read the tag
+            int reparseTag = 0;
+            int fileAttrs = unsafe
+                .getInt(address + OFFSETOF_FILE_INFORMATION_ATTRIBUTES);
+            if ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
+                int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
+                NativeBuffer reparseBuffer = NativeBuffers.getNativeBuffer(size);
+                try {
+                    DeviceIoControlGetReparsePoint(handle, reparseBuffer.address(), size);
+                    reparseTag = (int)unsafe.getLong(reparseBuffer.address());
+                } finally {
+                    reparseBuffer.release();
+                }
+            }
+
+            return fromFileInformation(address, reparseTag);
+        } finally {
+            buffer.release();
+        }
+    }
+
+    /**
+     * Returns attributes of given file.
+     */
+    static WindowsFileAttributes get(WindowsPath path, boolean followLinks)
+        throws WindowsException
+    {
+        if (!ensureAccurateMetadata) {
+            NativeBuffer buffer =
+                NativeBuffers.getNativeBuffer(SIZEOF_FILE_ATTRIBUTE_DATA);
+            try {
+                long address = buffer.address();
+                GetFileAttributesEx(path.getPathForWin32Calls(), address);
+                // if reparse point then file may be a sym link; otherwise
+                // just return the attributes
+                int fileAttrs = unsafe
+                    .getInt(address + OFFSETOF_FILE_ATTRIBUTE_DATA_ATTRIBUTES);
+                if ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
+                    return fromFileAttributeData(address, 0);
+            } finally {
+                buffer.release();
+            }
+        }
+
+        // file is reparse point so need to open file to get attributes
+        long handle = path.openForReadAttributeAccess(followLinks);
+        try {
+            return readAttributes(handle);
+        } finally {
+            CloseHandle(handle);
+        }
+    }
+
+    /**
+     * Returns true if the attribtues are of the same file - both files must
+     * be open.
+     */
+    static boolean isSameFile(WindowsFileAttributes attrs1,
+                              WindowsFileAttributes attrs2)
+    {
+        // volume serial number and file index must be the same
+        return (attrs1.volSerialNumber == attrs2.volSerialNumber) &&
+               (attrs1.fileIndexHigh == attrs2.fileIndexHigh) &&
+               (attrs1.fileIndexLow == attrs2.fileIndexLow);
+    }
+
+    // package-private
+    int attributes() {
+        return fileAttrs;
+    }
+
+    int volSerialNumber() {
+        if (volSerialNumber == 0)
+            throw new AssertionError("Should not get here");
+        return volSerialNumber;
+    }
+
+    int fileIndexHigh() {
+        if (volSerialNumber == 0)
+            throw new AssertionError("Should not get here");
+        return fileIndexHigh;
+    }
+
+    int fileIndexLow() {
+        if (volSerialNumber == 0)
+            throw new AssertionError("Should not get here");
+        return fileIndexLow;
+    }
+
+    @Override
+    public long size() {
+        return size;
+    }
+
+    @Override
+    public long lastModifiedTime() {
+        return (lastWriteTime >= 0L) ? lastWriteTime : 0L;
+    }
+
+    @Override
+    public long lastAccessTime() {
+        return (lastAccessTime >= 0L) ? lastAccessTime : 0L;
+    }
+
+    @Override
+    public long creationTime() {
+        return (creationTime >= 0L) ? creationTime : 0L;
+    }
+
+    @Override
+    public TimeUnit resolution() {
+        return TimeUnit.MILLISECONDS;
+    }
+
+    @Override
+    public int linkCount() {
+        return linkCount;
+    }
+
+    @Override
+    public Object fileKey() {
+        return null;
+    }
+
+    // package private
+    boolean isReparsePoint() {
+        return (fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
+    }
+
+    boolean isDirectoryLink() {
+        return isSymbolicLink() && ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0);
+    }
+
+    @Override
+    public boolean isSymbolicLink() {
+        return reparseTag == IO_REPARSE_TAG_SYMLINK;
+    }
+
+    @Override
+    public boolean isDirectory() {
+        // ignore FILE_ATTRIBUTE_DIRECTORY attribute if file is a sym link
+        if (isSymbolicLink())
+            return false;
+        return ((fileAttrs & FILE_ATTRIBUTE_DIRECTORY) != 0);
+    }
+
+    @Override
+    public boolean isOther() {
+        if (isSymbolicLink())
+            return false;
+        // return true if device or reparse point
+        return ((fileAttrs & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT)) != 0);
+    }
+
+    @Override
+    public boolean isRegularFile() {
+        return !isSymbolicLink() && !isDirectory() && !isOther();
+    }
+
+    @Override
+    public boolean isReadOnly() {
+        return (fileAttrs & FILE_ATTRIBUTE_READONLY) != 0;
+    }
+
+    @Override
+    public boolean isHidden() {
+        return (fileAttrs & FILE_ATTRIBUTE_HIDDEN) != 0;
+    }
+
+    @Override
+    public boolean isArchive() {
+        return (fileAttrs & FILE_ATTRIBUTE_ARCHIVE) != 0;
+    }
+
+    @Override
+    public boolean isSystem() {
+        return (fileAttrs & FILE_ATTRIBUTE_SYSTEM) != 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileCopy.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,519 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import com.sun.nio.file.ExtendedCopyOption;
+
+import static sun.nio.fs.WindowsNativeDispatcher.*;
+import static sun.nio.fs.WindowsConstants.*;
+
+/**
+ * Utility methods for copying and moving files.
+ */
+
+class WindowsFileCopy {
+    private WindowsFileCopy() {
+    }
+
+    /**
+     * Copy file from source to target
+     */
+    static void copy(final WindowsPath source,
+                     final WindowsPath target,
+                     CopyOption... options)
+        throws IOException
+    {
+        // map options
+        boolean replaceExisting = false;
+        boolean copyAttributes = false;
+        boolean followLinks = true;
+        boolean interruptible = false;
+        for (CopyOption option: options) {
+            if (option == StandardCopyOption.REPLACE_EXISTING) {
+                replaceExisting = true;
+                continue;
+            }
+            if (option == LinkOption.NOFOLLOW_LINKS) {
+                followLinks = false;
+                continue;
+            }
+            if (option == StandardCopyOption.COPY_ATTRIBUTES) {
+                copyAttributes = true;
+                continue;
+            }
+            if (option == ExtendedCopyOption.INTERRUPTIBLE) {
+                interruptible = true;
+                continue;
+            }
+            if (option == null)
+                throw new NullPointerException();
+            throw new UnsupportedOperationException("Unsupported copy option");
+        }
+
+        // check permissions. If the source file is a symbolic link then
+        // later we must also check LinkPermission
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            source.checkRead();
+            target.checkWrite();
+        }
+
+        // get attributes of source file
+        // attempt to get attributes of target file
+        // if both files are the same there is nothing to do
+        // if target exists and !replace then throw exception
+
+        WindowsFileAttributes sourceAttrs = null;
+        WindowsFileAttributes targetAttrs = null;
+
+        long sourceHandle = 0L;
+        try {
+            sourceHandle = source.openForReadAttributeAccess(followLinks);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(source);
+        }
+        try {
+            // source attributes
+            try {
+                sourceAttrs = WindowsFileAttributes.readAttributes(sourceHandle);
+            } catch (WindowsException x) {
+                x.rethrowAsIOException(source);
+            }
+
+            // open target (don't follow links)
+            long targetHandle = 0L;
+            try {
+                targetHandle = target.openForReadAttributeAccess(false);
+                try {
+                    targetAttrs = WindowsFileAttributes.readAttributes(targetHandle);
+
+                    // if both files are the same then nothing to do
+                    if (WindowsFileAttributes.isSameFile(sourceAttrs, targetAttrs)) {
+                        return;
+                    }
+
+                    // can't replace file
+                    if (!replaceExisting) {
+                        throw new FileAlreadyExistsException(
+                            target.getPathForExceptionMessage());
+                    }
+
+                } finally {
+                    CloseHandle(targetHandle);
+                }
+            } catch (WindowsException x) {
+                // ignore
+            }
+
+        } finally {
+            CloseHandle(sourceHandle);
+        }
+
+        // if source file is a symbolic link then we must check for LinkPermission
+        if (sm != null && sourceAttrs.isSymbolicLink()) {
+            sm.checkPermission(new LinkPermission("symbolic"));
+        }
+
+        final String sourcePath = asWin32Path(source);
+        final String targetPath = asWin32Path(target);
+
+        // if target exists then delete it.
+        if (targetAttrs != null) {
+            try {
+                if (targetAttrs.isDirectory() || targetAttrs.isDirectoryLink()) {
+                    RemoveDirectory(targetPath);
+                } else {
+                    DeleteFile(targetPath);
+                }
+            } catch (WindowsException x) {
+                if (targetAttrs.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 FileAlreadyExistsException(
+                            target.getPathForExceptionMessage());
+                    }
+                }
+                x.rethrowAsIOException(target);
+            }
+        }
+
+        // Use CopyFileEx if the file is not a directory or junction
+        if (!sourceAttrs.isDirectory() && !sourceAttrs.isDirectoryLink()) {
+            final int flags =
+                (source.getFileSystem().supportsLinks() && !followLinks) ?
+                COPY_FILE_COPY_SYMLINK : 0;
+
+            if (interruptible) {
+                // interruptible copy
+                Cancellable copyTask = new Cancellable() {
+                    @Override
+                    public int cancelValue() {
+                        return 1;  // TRUE
+                    }
+                    @Override
+                    public void implRun() throws IOException {
+                        try {
+                            CopyFileEx(sourcePath, targetPath, flags,
+                                       addressToPollForCancel());
+                        } catch (WindowsException x) {
+                            x.rethrowAsIOException(source, target);
+                        }
+                    }
+                };
+                try {
+                    Cancellable.runInterruptibly(copyTask);
+                } catch (ExecutionException e) {
+                    Throwable t = e.getCause();
+                    if (t instanceof IOException)
+                        throw (IOException)t;
+                    throw new IOException(t);
+                }
+            } else {
+                // non-interruptible copy
+                try {
+                    CopyFileEx(sourcePath, targetPath, flags, 0L);
+                } catch (WindowsException x) {
+                    x.rethrowAsIOException(source, target);
+                }
+            }
+            if (copyAttributes) {
+                // CopyFileEx does not copy security attributes
+                try {
+                    copySecurityAttributes(source, target, followLinks);
+                } catch (IOException x) {
+                    // ignore
+                }
+            }
+            return;
+        }
+
+        // copy directory or directory junction
+        try {
+            if (sourceAttrs.isDirectory()) {
+                CreateDirectory(targetPath, 0L);
+            } else {
+                String linkTarget = WindowsLinkSupport.readLink(source);
+                int flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
+                CreateSymbolicLink(targetPath,
+                                   addPrefixIfNeeded(linkTarget),
+                                   flags);
+            }
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(target);
+        }
+        if (copyAttributes) {
+            // copy DOS/timestamps attributes
+            WindowsFileAttributeViews.Dos view =
+                WindowsFileAttributeViews.createDosView(target, false);
+            try {
+                view.setAttributes(sourceAttrs);
+            } catch (IOException x) {
+                if (sourceAttrs.isDirectory()) {
+                    try {
+                        RemoveDirectory(targetPath);
+                    } catch (WindowsException ignore) { }
+                }
+            }
+
+            // copy security attributes. If this fail it doesn't cause the move
+            // to fail.
+            try {
+                copySecurityAttributes(source, target, followLinks);
+            } catch (IOException ignore) { }
+        }
+    }
+
+    /**
+     * Move file from source to target
+     */
+    static void move(WindowsPath source, WindowsPath target, CopyOption... options)
+        throws IOException
+    {
+        // map options
+        boolean atomicMove = false;
+        boolean replaceExisting = false;
+        for (CopyOption option: options) {
+            if (option == StandardCopyOption.ATOMIC_MOVE) {
+                atomicMove = true;
+                continue;
+            }
+            if (option == StandardCopyOption.REPLACE_EXISTING) {
+                replaceExisting = true;
+                continue;
+            }
+            if (option == LinkOption.NOFOLLOW_LINKS) {
+                // ignore
+                continue;
+            }
+            if (option == null) throw new NullPointerException();
+            throw new UnsupportedOperationException("Unsupported copy option");
+        }
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            source.checkWrite();
+            target.checkWrite();
+        }
+
+        final String sourcePath = asWin32Path(source);
+        final String targetPath = asWin32Path(target);
+
+        // atomic case
+        if (atomicMove) {
+            try {
+                MoveFileEx(sourcePath, targetPath, MOVEFILE_REPLACE_EXISTING);
+            } catch (WindowsException x) {
+                if (x.lastError() == ERROR_NOT_SAME_DEVICE) {
+                    throw new AtomicMoveNotSupportedException(
+                        source.getPathForExceptionMessage(),
+                        target.getPathForExceptionMessage(),
+                        x.errorString());
+                }
+                x.rethrowAsIOException(source, target);
+            }
+            return;
+        }
+
+        // get attributes of source file
+        // attempt to get attributes of target file
+        // if both files are the same there is nothing to do
+        // if target exists and !replace then throw exception
+
+        WindowsFileAttributes sourceAttrs = null;
+        WindowsFileAttributes targetAttrs = null;
+
+        long sourceHandle = 0L;
+        try {
+            sourceHandle = source.openForReadAttributeAccess(false);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(source);
+        }
+        try {
+            // source attributes
+            try {
+                sourceAttrs = WindowsFileAttributes.readAttributes(sourceHandle);
+            } catch (WindowsException x) {
+                x.rethrowAsIOException(source);
+            }
+
+            // open target (don't follow links)
+            long targetHandle = 0L;
+            try {
+                targetHandle = target.openForReadAttributeAccess(false);
+                try {
+                    targetAttrs = WindowsFileAttributes.readAttributes(targetHandle);
+
+                    // if both files are the same then nothing to do
+                    if (WindowsFileAttributes.isSameFile(sourceAttrs, targetAttrs)) {
+                        return;
+                    }
+
+                    // can't replace file
+                    if (!replaceExisting) {
+                        throw new FileAlreadyExistsException(
+                            target.getPathForExceptionMessage());
+                    }
+
+                } finally {
+                    CloseHandle(targetHandle);
+                }
+            } catch (WindowsException x) {
+                // ignore
+            }
+
+        } finally {
+            CloseHandle(sourceHandle);
+        }
+
+        // if target exists then delete it.
+        if (targetAttrs != null) {
+            try {
+                if (targetAttrs.isDirectory() || targetAttrs.isDirectoryLink()) {
+                    RemoveDirectory(targetPath);
+                } else {
+                    DeleteFile(targetPath);
+                }
+            } catch (WindowsException x) {
+                if (targetAttrs.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 FileAlreadyExistsException(
+                            target.getPathForExceptionMessage());
+                    }
+                }
+                x.rethrowAsIOException(target);
+            }
+        }
+
+        // first try MoveFileEx (no options). If target is on same volume then
+        // all attributes (including security attributes) are preserved.
+        try {
+            MoveFileEx(sourcePath, targetPath, 0);
+            return;
+        } catch (WindowsException x) {
+            if (x.lastError() != ERROR_NOT_SAME_DEVICE)
+                x.rethrowAsIOException(source, target);
+        }
+
+        // target is on different volume so use MoveFileEx with copy option
+        if (!sourceAttrs.isDirectory() && !sourceAttrs.isDirectoryLink()) {
+            try {
+                MoveFileEx(sourcePath, targetPath, MOVEFILE_COPY_ALLOWED);
+            } catch (WindowsException x) {
+                x.rethrowAsIOException(source, target);
+            }
+            // MoveFileEx does not copy security attributes when moving
+            // across volumes.
+            try {
+                copySecurityAttributes(source, target, false);
+            } catch (IOException x) {
+                // ignore
+            }
+            return;
+        }
+
+        // moving directory or directory-link to another file system
+        assert sourceAttrs.isDirectory() || sourceAttrs.isDirectoryLink();
+
+        // create new directory or directory junction
+        try {
+            if (sourceAttrs.isDirectory()) {
+                CreateDirectory(targetPath, 0L);
+            } else {
+                String linkTarget = WindowsLinkSupport.readLink(source);
+                CreateSymbolicLink(targetPath,
+                                   addPrefixIfNeeded(linkTarget),
+                                   SYMBOLIC_LINK_FLAG_DIRECTORY);
+            }
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(target);
+        }
+
+        // copy timestamps/DOS attributes
+        WindowsFileAttributeViews.Dos view =
+                WindowsFileAttributeViews.createDosView(target, false);
+        try {
+            view.setAttributes(sourceAttrs);
+        } catch (IOException x) {
+            // rollback
+            try {
+                RemoveDirectory(targetPath);
+            } catch (WindowsException ignore) { }
+            throw x;
+        }
+
+        // copy security attributes. If this fails it doesn't cause the move
+        // to fail.
+        try {
+            copySecurityAttributes(source, target, false);
+        } catch (IOException ignore) { }
+
+        // delete source
+        try {
+            RemoveDirectory(sourcePath);
+        } catch (WindowsException x) {
+            // rollback
+            try {
+                RemoveDirectory(targetPath);
+            } catch (WindowsException ignore) { }
+            // 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(
+                    target.getPathForExceptionMessage());
+            }
+            x.rethrowAsIOException(source);
+        }
+    }
+
+
+    private static String asWin32Path(WindowsPath path) throws IOException {
+        try {
+            return path.getPathForWin32Calls();
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(path);
+            return null;
+        }
+    }
+
+    /**
+     * Copy DACL/owner/group from source to target
+     */
+    private static void copySecurityAttributes(WindowsPath source,
+                                               WindowsPath target,
+                                               boolean followLinks)
+        throws IOException
+    {
+        String path = WindowsLinkSupport.getFinalPath(source, followLinks);
+
+        // may need SeRestorePrivilege to set file owner
+        WindowsSecurity.Privilege priv =
+            WindowsSecurity.enablePrivilege("SeRestorePrivilege");
+        try {
+            int request = (DACL_SECURITY_INFORMATION |
+                OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION);
+            NativeBuffer buffer =
+                WindowsAclFileAttributeView.getFileSecurity(path, request);
+            try {
+                try {
+                    SetFileSecurity(target.getPathForWin32Calls(), request,
+                        buffer.address());
+                } catch (WindowsException x) {
+                    x.rethrowAsIOException(target);
+                }
+            } finally {
+                buffer.release();
+            }
+        } finally {
+            priv.drop();
+        }
+    }
+
+    /**
+     * Add long path prefix to path if required
+     */
+    private static String addPrefixIfNeeded(String path) {
+        if (path.length() > 248) {
+            if (path.startsWith("\\\\")) {
+                path = "\\\\?\\UNC" + path.substring(1, path.length());
+            } else {
+                path = "\\\\?\\" + path;
+            }
+        }
+        return path;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.io.IOException;
+
+import static sun.nio.fs.WindowsConstants.*;
+import static sun.nio.fs.WindowsNativeDispatcher.*;
+
+/**
+ * Windows implementation of FileStore.
+ */
+
+class WindowsFileStore
+    extends FileStore
+{
+    private final String root;
+    private final VolumeInformation volInfo;
+    private final int volType;
+    private final String displayName;   // returned by toString
+
+    private WindowsFileStore(String root) throws WindowsException {
+        assert root.charAt(root.length()-1) == '\\';
+        this.root = root;
+        this.volInfo = GetVolumeInformation(root);
+        this.volType = GetDriveType(root);
+
+        // file store "display name" is the volume name if available
+        String vol = volInfo.volumeName();
+        if (vol.length() > 0) {
+            this.displayName = vol;
+        } else {
+            // TBD - should we map all types? Does this need to be localized?
+            this.displayName = (volType == DRIVE_REMOVABLE) ? "Removable Disk" : "";
+        }
+    }
+
+    static WindowsFileStore create(String root, boolean ignoreNotReady)
+        throws IOException
+    {
+        try {
+            return new WindowsFileStore(root);
+        } catch (WindowsException x) {
+            if (ignoreNotReady && x.lastError() == ERROR_NOT_READY)
+                return null;
+            x.rethrowAsIOException(root);
+            return null; // keep compiler happy
+        }
+    }
+
+    static WindowsFileStore create(WindowsPath file) throws IOException {
+        try {
+            // if the file is a link then GetVolumePathName returns the
+            // volume that the link is on so we need to call it with the
+            // final target
+            String target;
+            if (file.getFileSystem().supportsLinks()) {
+                target = WindowsLinkSupport.getFinalPath(file, true);
+            } else {
+                // file must exist
+                WindowsFileAttributes.get(file, true);
+                target = file.getPathForWin32Calls();
+            }
+            String root = GetVolumePathName(target);
+            return new WindowsFileStore(root);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(file);
+            return null; // keep compiler happy
+        }
+    }
+
+    VolumeInformation volumeInformation() {
+        return volInfo;
+    }
+
+    int volumeType() {
+        return volType;
+    }
+
+    @Override
+    public String name() {
+        return volInfo.volumeName();   // "SYSTEM", "DVD-RW", ...
+    }
+
+    @Override
+    public String type() {
+        return volInfo.fileSystemName();  // "FAT", "NTFS", ...
+    }
+
+    @Override
+    public boolean isReadOnly() {
+        return ((volInfo.flags() & FILE_READ_ONLY_VOLUME) != 0);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> view) {
+        if (view == FileStoreSpaceAttributeView.class)
+            return (V) new WindowsFileStoreAttributeView(this);
+        return (V) null;
+    }
+
+    @Override
+    public FileStoreAttributeView getFileStoreAttributeView(String name) {
+        if (name.equals("space"))
+            return new WindowsFileStoreAttributeView(this);
+        if (name.equals("volume"))
+            return new VolumeFileStoreAttributeView(this);
+        return null;
+    }
+
+    @Override
+    public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
+        if (type == BasicFileAttributeView.class)
+            return true;
+        if (type == AclFileAttributeView.class || type == FileOwnerAttributeView.class)
+            return ((volInfo.flags() & FILE_PERSISTENT_ACLS) != 0);
+        if (type == UserDefinedFileAttributeView.class)
+            return ((volInfo.flags() & FILE_NAMED_STREAMS) != 0);
+        return false;
+    }
+
+    @Override
+    public boolean supportsFileAttributeView(String name) {
+        if (name.equals("basic") || name.equals("dos"))
+            return true;
+        if (name.equals("acl"))
+            return supportsFileAttributeView(AclFileAttributeView.class);
+        if (name.equals("owner"))
+            return supportsFileAttributeView(FileOwnerAttributeView.class);
+        if (name.equals("xattr"))
+            return supportsFileAttributeView(UserDefinedFileAttributeView.class);
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object ob) {
+        if (ob == this)
+            return true;
+        if (!(ob instanceof WindowsFileStore))
+            return false;
+        WindowsFileStore other = (WindowsFileStore)ob;
+        return this.volInfo.volumeSerialNumber() == other.volInfo.volumeSerialNumber();
+    }
+
+    @Override
+    public int hashCode() {
+        // reveals VSN without permission check - okay?
+        return volInfo.volumeSerialNumber();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(displayName);
+        if (sb.length() > 0)
+            sb.append(" ");
+        sb.append("(");
+        // drop trailing slash
+        sb.append(root.subSequence(0, root.length()-1));
+        sb.append(")");
+        return sb.toString();
+    }
+
+    static class WindowsFileStoreAttributeView
+        extends AbstractFileStoreSpaceAttributeView
+    {
+        private final WindowsFileStore fs;
+
+        WindowsFileStoreAttributeView(WindowsFileStore fs) {
+            this.fs = fs;
+        }
+
+        @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();
+                }
+            };
+        }
+    }
+
+    /**
+     * Windows-specific attribute view to allow access to volume information.
+     */
+    static class VolumeFileStoreAttributeView
+        implements FileStoreAttributeView
+    {
+        private static final String VSN_NAME = "vsn";
+        private static final String COMPRESSED_NAME = "compressed";
+        private static final String REMOVABLE_NAME = "removable";
+        private static final String CDROM_NAME = "cdrom";
+
+        private final WindowsFileStore fs;
+
+        VolumeFileStoreAttributeView(WindowsFileStore fs) {
+            this.fs = fs;
+        }
+
+        @Override
+        public String name() {
+            return "volume";
+        }
+
+        private int vsn() {
+            return fs.volumeInformation().volumeSerialNumber();
+        }
+
+        private boolean isCompressed() {
+            return (fs.volumeInformation().flags() &
+                    FILE_VOLUME_IS_COMPRESSED) > 0;
+        }
+
+        private boolean isRemovable() {
+            return fs.volumeType() == DRIVE_REMOVABLE;
+        }
+
+        private boolean isCdrom() {
+            return fs.volumeType() == DRIVE_CDROM;
+        }
+
+        @Override
+        public Object getAttribute(String attribute) throws IOException {
+            if (attribute.equals(VSN_NAME))
+                return vsn();
+            if (attribute.equals(COMPRESSED_NAME))
+                return isCompressed();
+            if (attribute.equals(REMOVABLE_NAME))
+                return isRemovable();
+            if (attribute.equals(CDROM_NAME))
+                return isCdrom();
+            return null;
+        }
+
+        @Override
+        public void setAttribute(String attribute, Object value)
+            throws IOException
+        {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Map<String,?> readAttributes(String first, String... rest)
+            throws IOException
+        {
+            boolean all = false;
+            boolean vsn = false;
+            boolean compressed = false;
+            boolean removable = false;
+            boolean cdrom = false;
+
+            if (first.equals(VSN_NAME)) vsn = true;
+            else if (first.equals(COMPRESSED_NAME)) compressed = true;
+            else if (first.equals(REMOVABLE_NAME)) removable = true;
+            else if (first.equals(CDROM_NAME)) cdrom = true;
+            else if (first.equals("*")) all = true;
+
+            if (!all) {
+                for (String attribute: rest) {
+                    if (attribute.equals("*")) {
+                        all = true;
+                        break;
+                    }
+                    if (attribute.equals(VSN_NAME)) {
+                        vsn = true;
+                        continue;
+                    }
+                    if (attribute.equals(COMPRESSED_NAME)) {
+                        compressed = true;
+                        continue;
+                    }
+                    if (attribute.equals(REMOVABLE_NAME)) {
+                        removable = true;
+                        continue;
+                    }
+                }
+            }
+
+            Map<String,Object> result = new HashMap<String,Object>();
+            if (all || vsn)
+                result.put(VSN_NAME, vsn());
+            if (all || compressed)
+                result.put(COMPRESSED_NAME, isCompressed());
+            if (all || removable)
+                result.put(REMOVABLE_NAME, isRemovable());
+            if (all || cdrom)
+                result.put(CDROM_NAME, isCdrom());
+            return result;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystem.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.nio.file.spi.*;
+import java.util.*;
+import java.util.regex.Pattern;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.security.action.GetPropertyAction;
+
+class WindowsFileSystem
+    extends FileSystem
+{
+    private final WindowsFileSystemProvider provider;
+
+    // default directory (is absolute), and default root
+    private final String defaultDirectory;
+    private final String defaultRoot;
+
+    private final boolean supportsLinks;
+    private final boolean supportsStreamEnumeration;
+
+    // package-private
+    WindowsFileSystem(WindowsFileSystemProvider provider,
+                      String dir)
+    {
+        this.provider = provider;
+
+        // parse default directory and check it is absolute
+        WindowsPathParser.Result result = WindowsPathParser.parse(dir);
+
+        if (result.type() != WindowsPathType.ABSOLUTE)
+            throw new AssertionError("Default directory must be absolute/non-UNC");
+        this.defaultDirectory = result.path();
+        this.defaultRoot = result.root();
+
+        PrivilegedAction<String> pa = new GetPropertyAction("os.version");
+        String osversion = AccessController.doPrivileged(pa);
+        String[] vers = osversion.split("\\.", 0);
+        int major = Integer.parseInt(vers[0]);
+        int minor = Integer.parseInt(vers[1]);
+
+        // symbolic links available on Vista and newer
+        supportsLinks = (major >= 6);
+
+        // enumeration of data streams available on Windows Server 2003 and newer
+        supportsStreamEnumeration = (major >= 6) || (major == 5 && minor >= 2);
+    }
+
+    // package-private
+    String defaultDirectory() {
+        return defaultDirectory;
+    }
+
+    String defaultRoot() {
+        return defaultRoot;
+    }
+
+    boolean supportsLinks() {
+        return supportsLinks;
+    }
+
+    boolean supportsStreamEnumeration() {
+        return supportsStreamEnumeration;
+    }
+
+    @Override
+    public FileSystemProvider provider() {
+        return provider;
+    }
+
+    @Override
+    public String getSeparator() {
+        return "\\";
+    }
+
+    @Override
+    public boolean isOpen() {
+        return true;
+    }
+
+    @Override
+    public boolean isReadOnly() {
+        return false;
+    }
+
+    @Override
+    public void close() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Iterable<Path> getRootDirectories() {
+        int drives = 0;
+        try {
+            drives = WindowsNativeDispatcher.GetLogicalDrives();
+        } catch (WindowsException x) {
+            // shouldn't happen
+            throw new AssertionError(x.getMessage());
+        }
+
+        // iterate over roots, ignoring those that the security manager denies
+        ArrayList<Path> result = new ArrayList<Path>();
+        SecurityManager sm = System.getSecurityManager();
+        for (int i = 0; i <= 25; i++) {  // 0->A, 1->B, 2->C...
+            if ((drives & (1 << i)) != 0) {
+                StringBuilder sb = new StringBuilder(3);
+                sb.append((char)('A' + i));
+                sb.append(":\\");
+                String root = sb.toString();
+                if (sm != null) {
+                    try {
+                        sm.checkRead(root);
+                    } catch (SecurityException x) {
+                        continue;
+                    }
+                }
+                result.add(WindowsPath.createFromNormalizedPath(this, root));
+            }
+        }
+        return Collections.unmodifiableList(result);
+    }
+
+    /**
+     * Iterator returned by getFileStores method.
+     */
+    private class FileStoreIterator implements Iterator<FileStore> {
+        private final Iterator<Path> roots;
+        private FileStore next;
+
+        FileStoreIterator() {
+            this.roots = getRootDirectories().iterator();
+        }
+
+        private FileStore readNext() {
+            assert Thread.holdsLock(this);
+            for (;;) {
+                if (!roots.hasNext())
+                    return null;
+                WindowsPath root = (WindowsPath)roots.next();
+                // ignore if security manager denies access
+                try {
+                    root.checkRead();
+                } catch (SecurityException x) {
+                    continue;
+                }
+                try {
+                    FileStore fs = WindowsFileStore.create(root.toString(), true);
+                    if (fs != null)
+                        return fs;
+                } catch (IOException ioe) {
+                    // skip it
+                }
+            }
+        }
+
+        @Override
+        public synchronized boolean hasNext() {
+            if (next != null)
+                return true;
+            next = readNext();
+            return next != null;
+        }
+
+        @Override
+        public synchronized FileStore next() {
+            if (next == null)
+                next = readNext();
+            if (next == null) {
+                throw new NoSuchElementException();
+            } else {
+                FileStore result = next;
+                next = null;
+                return result;
+            }
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    @Override
+    public Iterable<FileStore> getFileStores() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            try {
+                sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));
+            } catch (SecurityException se) {
+                return Collections.emptyList();
+            }
+        }
+        return new Iterable<FileStore>() {
+            public Iterator<FileStore> iterator() {
+                return new FileStoreIterator();
+            }
+        };
+    }
+
+    // supported views
+    private static final Set<String> supportedFileAttributeViews = Collections
+        .unmodifiableSet(new HashSet<String>(Arrays.asList("basic", "dos", "acl", "owner", "xattr")));
+
+    @Override
+    public Set<String> supportedFileAttributeViews() {
+        return supportedFileAttributeViews;
+    }
+
+    @Override
+    public Path getPath(String path) {
+        WindowsPathParser.Result result = WindowsPathParser.parse(path);
+        return new WindowsPath(this, result.type(), result.root(), result.path());
+    }
+
+
+    @Override
+    public UserPrincipalLookupService getUserPrincipalLookupService() {
+        return theLookupService;
+    }
+
+    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;
+            }
+        };
+
+    @Override
+    public PathMatcher getPathMatcher(String syntaxAndInput) {
+        int pos = syntaxAndInput.indexOf(':');
+        if (pos <= 0 || pos == syntaxAndInput.length())
+            throw new IllegalArgumentException();
+        String syntax = syntaxAndInput.substring(0, pos);
+        String input = syntaxAndInput.substring(pos+1);
+
+        String expr;
+        if (syntax.equals(GLOB_SYNTAX)) {
+            expr = Globs.toWindowsRegexPattern(input);
+        } else {
+            if (syntax.equals(REGEX_SYNTAX)) {
+                expr = input;
+            } else {
+                throw new UnsupportedOperationException("Syntax '" + syntax +
+                    "' not recognized");
+            }
+        }
+
+        // match in uppercase
+        StringBuilder sb = new StringBuilder(expr.length());
+        for (int i=0; i<expr.length(); i++) {
+            sb.append(Character.toUpperCase(expr.charAt(i)));
+        }
+        expr = sb.toString();
+
+        // return matcher
+        final Pattern pattern = Pattern.compile(expr);
+        return new PathMatcher() {
+            @Override
+            public boolean matches(Path path) {
+                // match in uppercase
+                String s = path.toString();
+                StringBuilder sb = new StringBuilder(s.length());
+                for (int i=0; i<s.length(); i++) {
+                    sb.append( Character.toUpperCase(s.charAt(i)) );
+                }
+                return pattern.matcher(sb).matches();
+            }
+        };
+    }
+    private static final String GLOB_SYNTAX = "glob";
+    private static final String REGEX_SYNTAX = "regex";
+
+    @Override
+    public WatchService newWatchService()
+        throws IOException
+    {
+        return new WindowsWatchService(this);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+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.util.*;
+
+import sun.nio.ch.ThreadPool;
+
+public class WindowsFileSystemProvider
+    extends FileSystemProvider
+{
+    private static final String USER_DIR = "user.dir";
+    private final WindowsFileSystem theFileSystem;
+
+    public WindowsFileSystemProvider() {
+        theFileSystem = new WindowsFileSystem(this, System.getProperty(USER_DIR));
+    }
+
+    @Override
+    public String getScheme() {
+        return "file";
+    }
+
+    private void checkUri(URI uri) {
+        if (!uri.getScheme().equalsIgnoreCase(getScheme()))
+            throw new IllegalArgumentException("URI does not match this provider");
+        if (uri.getAuthority() != null)
+            throw new IllegalArgumentException("Authority component present");
+        if (uri.getPath() == null)
+            throw new IllegalArgumentException("Path component is undefined");
+        if (!uri.getPath().equals("/"))
+            throw new IllegalArgumentException("Path component should be '/'");
+        if (uri.getQuery() != null)
+            throw new IllegalArgumentException("Query component present");
+        if (uri.getFragment() != null)
+            throw new IllegalArgumentException("Fragment component present");
+    }
+
+    @Override
+    public FileSystem newFileSystem(URI uri, Map<String,?> env)
+        throws IOException
+    {
+        checkUri(uri);
+        throw new FileSystemAlreadyExistsException();
+    }
+
+    @Override
+    public final FileSystem getFileSystem(URI uri) {
+        checkUri(uri);
+        return theFileSystem;
+    }
+
+    @Override
+    public Path getPath(URI uri) {
+        return WindowsUriSupport.fromUri(theFileSystem, uri);
+    }
+
+    @Override
+    public FileChannel newFileChannel(Path path,
+                                      Set<? extends OpenOption> options,
+                                      FileAttribute<?>... attrs)
+        throws IOException
+    {
+        if (path == null)
+            throw new NullPointerException();
+        if (!(path instanceof WindowsPath))
+            throw new ProviderMismatchException();
+        WindowsPath file = (WindowsPath)path;
+
+        WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.fromAttribute(attrs);
+        try {
+            return WindowsChannelFactory
+                .newFileChannel(file.getPathForWin32Calls(),
+                                file.getPathForPermissionCheck(),
+                                options,
+                                sd.address());
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(file);
+            return null;
+        } finally {
+            if (sd != null)
+                sd.release();
+        }
+    }
+
+    @Override
+    public AsynchronousFileChannel newAsynchronousFileChannel(Path path,
+                                                              Set<? extends OpenOption> options,
+                                                              ExecutorService executor,
+                                                              FileAttribute<?>... attrs)
+        throws IOException
+    {
+        if (path == null)
+            throw new NullPointerException();
+        if (!(path instanceof WindowsPath))
+            throw new ProviderMismatchException();
+        WindowsPath file = (WindowsPath)path;
+        ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0);
+        WindowsSecurityDescriptor sd =
+            WindowsSecurityDescriptor.fromAttribute(attrs);
+        try {
+            return WindowsChannelFactory
+                .newAsynchronousFileChannel(file.getPathForWin32Calls(),
+                                            file.getPathForPermissionCheck(),
+                                            options,
+                                            sd.address(),
+                                            pool);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(file);
+            return null;
+        } finally {
+            if (sd != null)
+                sd.release();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,446 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.io.IOException;
+import java.io.IOError;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.misc.Unsafe;
+
+import static sun.nio.fs.WindowsNativeDispatcher.*;
+import static sun.nio.fs.WindowsConstants.*;
+
+/**
+ * Utility methods for symbolic link support on Windows Vista and newer.
+ */
+
+class WindowsLinkSupport {
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    private WindowsLinkSupport() {
+    }
+
+    /**
+     * Returns the target of a symbolic link
+     */
+    static String readLink(WindowsPath path) throws IOException {
+        long handle = 0L;
+        try {
+            handle = path.openForReadAttributeAccess(false); // don't follow links
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(path);
+        }
+        try {
+            return readLinkImpl(handle);
+        } finally {
+            CloseHandle(handle);
+        }
+    }
+
+    /**
+     * Returns the final path of a given path as a String. This should be used
+     * prior to calling Win32 system calls that do not follow links.
+     */
+    static String getFinalPath(WindowsPath input, boolean followLinks)
+        throws IOException
+    {
+        WindowsFileSystem fs = input.getFileSystem();
+
+        try {
+            // if not following links then don't need final path
+            if (!followLinks || !fs.supportsLinks())
+                return input.getPathForWin32Calls();
+
+            // if file is a sym link then don't need final path
+            if (!WindowsFileAttributes.get(input, false).isSymbolicLink()) {
+                return input.getPathForWin32Calls();
+            }
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(input);
+        }
+
+        // The file is a symbolic link so we open it and try to get the
+        // normalized path. This should succeed on NTFS but may fail if there
+        // is a link to a non-NFTS file system.
+        long h = 0;
+        try {
+            h = input.openForReadAttributeAccess(true);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(input);
+        }
+        try {
+            return stripPrefix(GetFinalPathNameByHandle(h));
+        } catch (WindowsException x) {
+            // ERROR_INVALID_LEVEL is the error returned when not supported by
+            // the file system
+            if (x.lastError() != ERROR_INVALID_LEVEL)
+                x.rethrowAsIOException(input);
+        } finally {
+            CloseHandle(h);
+        }
+
+        // Fallback: read target of link, resolve against parent, and repeat
+        // until file is not a link.
+        WindowsPath target = input;
+        int linkCount = 0;
+        do {
+            try {
+                WindowsFileAttributes attrs =
+                    WindowsFileAttributes.get(target, false);
+                // non a link so we are done
+                if (!attrs.isSymbolicLink()) {
+                    return target.getPathForWin32Calls();
+                }
+            } catch (WindowsException x) {
+                x.rethrowAsIOException(target);
+            }
+            WindowsPath link = WindowsPath
+                .createFromNormalizedPath(fs, readLink(target));
+            WindowsPath parent = target.getParent();
+            if (parent == null) {
+                // no parent so use parent of absolute path
+                final WindowsPath t = target;
+                target = AccessController
+                    .doPrivileged(new PrivilegedAction<WindowsPath>() {
+                        @Override
+                        public WindowsPath run() {
+                            return t.toAbsolutePath();
+                        }});
+                parent = target.getParent();
+            }
+            target = parent.resolve(link);
+
+        } while (++linkCount < 32);
+
+        throw new FileSystemException(input.getPathForExceptionMessage(), null,
+            "Too many links");
+    }
+
+    /**
+     * Returns the actual path of a file, optionally resolving all symbolic
+     * links.
+     */
+    static String getRealPath(WindowsPath input, boolean resolveLinks)
+        throws IOException
+    {
+        WindowsFileSystem fs = input.getFileSystem();
+        if (!fs.supportsLinks())
+            resolveLinks = false;
+
+        // On Vista use GetFinalPathNameByHandle. This should succeed on NTFS
+        // but may fail if there is a link to a non-NFTS file system.
+        if (resolveLinks) {
+            long h = 0;
+            try {
+                h = input.openForReadAttributeAccess(true);
+            } catch (WindowsException x) {
+                x.rethrowAsIOException(input);
+            }
+            try {
+                return stripPrefix(GetFinalPathNameByHandle(h));
+            } catch (WindowsException x) {
+                if (x.lastError() != ERROR_INVALID_LEVEL)
+                    x.rethrowAsIOException(input);
+            } finally {
+                CloseHandle(h);
+            }
+        }
+
+        // Not resolving links or we are on Windows Vista (or newer) with a
+        // link to non-NFTS file system.
+
+        // Start with absolute path
+        String path = null;
+        try {
+            path = input.toAbsolutePath().toString();
+        } catch (IOError x) {
+            throw (IOException)(x.getCause());
+        }
+
+        // Collapse "." and ".."
+        try {
+            path = GetFullPathName(path);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(input);
+        }
+
+        // eliminate all symbolic links
+        if (resolveLinks) {
+            path = resolveAllLinks(WindowsPath.createFromNormalizedPath(fs, path));
+        }
+
+        // string builder to build up components of path
+        StringBuilder sb = new StringBuilder(path.length());
+
+        // Copy root component
+        int start;
+        char c0 = path.charAt(0);
+        char c1 = path.charAt(1);
+        if ((c0 <= 'z' && c0 >= 'a' || c0 <= 'Z' && c0 >= 'A') &&
+            c1 == ':' && path.charAt(2) == '\\') {
+            // Driver specifier
+            sb.append(Character.toUpperCase(c0));
+            sb.append(":\\");
+            start = 3;
+        } else if (c0 == '\\' && c1 == '\\') {
+            // UNC pathname, begins with "\\\\host\\share"
+            int last = path.length() - 1;
+            int pos = path.indexOf('\\', 2);
+            // skip both server and share names
+            if (pos == -1 || (pos == last)) {
+                // The UNC does not have a share name (collapsed by GetFullPathName)
+                throw new FileSystemException(input.getPathForExceptionMessage(),
+                    null, "UNC has invalid share");
+            }
+            pos = path.indexOf('\\', pos+1);
+            if (pos < 0) {
+                pos = last;
+                sb.append(path).append("\\");
+            } else {
+                sb.append(path, 0, pos+1);
+            }
+            start = pos + 1;
+        } else {
+            throw new AssertionError("path type not recognized");
+        }
+
+        // check root directory exists
+        try {
+            FirstFile fileData = FindFirstFile(sb.toString() + "*");
+            FindClose(fileData.handle());
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(path);
+        }
+
+        // iterate through each component to get its actual name in the
+        // directory
+        int curr = start;
+        while (curr < path.length()) {
+            int next = path.indexOf('\\', curr);
+            int end = (next == -1) ? path.length() : next;
+            String search = sb.toString() + path.substring(curr, end);
+            try {
+                FirstFile fileData = FindFirstFile(addLongPathPrefixIfNeeded(search));
+                try {
+                    sb.append(fileData.name());
+                    if (next != -1) {
+                        sb.append('\\');
+                    }
+                } finally {
+                    FindClose(fileData.handle());
+                }
+            } catch (WindowsException e) {
+                e.rethrowAsIOException(path);
+            }
+            curr = end + 1;
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Returns target of a symbolic link given the handle of an open file
+     * (that should be a link).
+     */
+    private static String readLinkImpl(long handle) throws IOException {
+        int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
+        NativeBuffer buffer = NativeBuffers.getNativeBuffer(size);
+        try {
+            try {
+                DeviceIoControlGetReparsePoint(handle, buffer.address(), size);
+            } catch (WindowsException x) {
+                // FIXME: exception doesn't have file name
+                if (x.lastError() == ERROR_NOT_A_REPARSE_POINT)
+                    throw new NotLinkException(null, null, x.errorString());
+                x.rethrowAsIOException((String)null);
+            }
+
+            /*
+             * typedef struct _REPARSE_DATA_BUFFER {
+             *     ULONG  ReparseTag;
+             *     USHORT  ReparseDataLength;
+             *     USHORT  Reserved;
+             *     union {
+             *         struct {
+             *             USHORT  SubstituteNameOffset;
+             *             USHORT  SubstituteNameLength;
+             *             USHORT  PrintNameOffset;
+             *             USHORT  PrintNameLength;
+             *             WCHAR  PathBuffer[1];
+             *         } SymbolicLinkReparseBuffer;
+             *         struct {
+             *             USHORT  SubstituteNameOffset;
+             *             USHORT  SubstituteNameLength;
+             *             USHORT  PrintNameOffset;
+             *             USHORT  PrintNameLength;
+             *             WCHAR  PathBuffer[1];
+             *         } MountPointReparseBuffer;
+             *         struct {
+             *             UCHAR  DataBuffer[1];
+             *         } GenericReparseBuffer;
+             *     };
+             * } REPARSE_DATA_BUFFER
+             */
+            final short OFFSETOF_REPARSETAG = 0;
+            final short OFFSETOF_PATHOFFSET = 8;
+            final short OFFSETOF_PATHLENGTH = 10;
+            final short OFFSETOF_PATHBUFFER = 16 + 4;   // check this
+
+            int tag = (int)unsafe.getLong(buffer.address() + OFFSETOF_REPARSETAG);
+            if (tag != IO_REPARSE_TAG_SYMLINK) {
+                // FIXME: exception doesn't have file name
+                throw new NotLinkException(null, null, "Reparse point is not a symbolic link");
+            }
+
+            // get offset and length of target
+            short nameOffset = unsafe.getShort(buffer.address() + OFFSETOF_PATHOFFSET);
+            short nameLengthInBytes = unsafe.getShort(buffer.address() + OFFSETOF_PATHLENGTH);
+            if ((nameLengthInBytes % 2) != 0)
+                throw new FileSystemException(null, null, "Symbolic link corrupted");
+
+            // copy into char array
+            char[] name = new char[nameLengthInBytes/2];
+            unsafe.copyMemory(null, buffer.address() + OFFSETOF_PATHBUFFER + nameOffset,
+                name, Unsafe.ARRAY_CHAR_BASE_OFFSET, nameLengthInBytes);
+
+            // remove special prefix
+            String target = stripPrefix(new String(name));
+            if (target.length() == 0) {
+                throw new IOException("Symbolic link target is invalid");
+            }
+            return target;
+        } finally {
+            buffer.release();
+        }
+    }
+
+    /**
+     * Resolve all symbolic-links in a given absolute and normalized path
+     */
+    private static String resolveAllLinks(WindowsPath path)
+        throws IOException
+    {
+        assert path.isAbsolute();
+        WindowsFileSystem fs = path.getFileSystem();
+
+        // iterate through each name element of the path, resolving links as
+        // we go.
+        int linkCount = 0;
+        int elem = 0;
+        while (elem < path.getNameCount()) {
+            WindowsPath current = path.getRoot().resolve(path.subpath(0, elem+1));
+
+            WindowsFileAttributes attrs = null;
+            try {
+                attrs = WindowsFileAttributes.get(current, false);
+            } catch (WindowsException x) {
+                x.rethrowAsIOException(current);
+            }
+
+            /**
+             * If a symbolic link then we resolve it against the parent
+             * of the current name element. We then resolve any remaining
+             * part of the path against the result. The target of the link
+             * may have "." and ".." components so re-normalize and restart
+             * the process from the first element.
+             */
+            if (attrs.isSymbolicLink()) {
+                linkCount++;
+                if (linkCount > 32)
+                    throw new IOException("Too many links");
+                WindowsPath target = WindowsPath
+                    .createFromNormalizedPath(fs, readLink(current));
+                WindowsPath remainder = null;
+                int count = path.getNameCount();
+                if ((elem+1) < count) {
+                    remainder = path.subpath(elem+1, count);
+                }
+                path = current.getParent().resolve(target);
+                try {
+                    String full = GetFullPathName(path.toString());
+                    if (!full.equals(path.toString())) {
+                        path = WindowsPath.createFromNormalizedPath(fs, full);
+                    }
+                } catch (WindowsException x) {
+                    x.rethrowAsIOException(path);
+                }
+                if (remainder != null) {
+                    path = path.resolve(remainder);
+                }
+
+                // reset
+                elem = 0;
+            } else {
+                // not a link
+                elem++;
+            }
+        }
+
+        return path.toString();
+    }
+
+    /**
+     * Add long path prefix to path if required.
+     */
+    private static String addLongPathPrefixIfNeeded(String path) {
+        if (path.length() > 248) {
+            if (path.startsWith("\\\\")) {
+                path = "\\\\?\\UNC" + path.substring(1, path.length());
+            } else {
+                path = "\\\\?\\" + path;
+            }
+        }
+        return path;
+    }
+
+    /**
+     * Strip long path or symbolic link prefix from path
+     */
+    private static String stripPrefix(String path) {
+        // prefix for resolved/long path
+        if (path.startsWith("\\\\?\\")) {
+            if (path.startsWith("\\\\?\\UNC\\")) {
+                path = "\\" + path.substring(7);
+            } else {
+                path = path.substring(4);
+            }
+            return path;
+        }
+
+        // prefix for target of symbolic link
+        if (path.startsWith("\\??\\")) {
+            if (path.startsWith("\\??\\UNC\\")) {
+                path = "\\" + path.substring(7);
+            } else {
+                path = path.substring(4);
+            }
+            return path;
+        }
+        return path;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,1133 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.misc.Unsafe;
+
+/**
+ * Win32 and library calls.
+ */
+
+class WindowsNativeDispatcher {
+    private WindowsNativeDispatcher() { }
+
+    /**
+     * HANDLE CreateFile(
+     *   LPCTSTR lpFileName,
+     *   DWORD dwDesiredAccess,
+     *   DWORD dwShareMode,
+     *   LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+     *   DWORD dwCreationDisposition,
+     *   DWORD dwFlagsAndAttributes,
+     *   HANDLE hTemplateFile
+     * )
+     */
+    static long CreateFile(String path,
+                           int dwDesiredAccess,
+                           int dwShareMode,
+                           long lpSecurityAttributes,
+                           int dwCreationDisposition,
+                           int dwFlagsAndAttributes)
+        throws WindowsException
+    {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            return CreateFile0(buffer.address(),
+                               dwDesiredAccess,
+                               dwShareMode,
+                               lpSecurityAttributes,
+                               dwCreationDisposition,
+                               dwFlagsAndAttributes);
+        } finally {
+            buffer.release();
+        }
+    }
+    static long CreateFile(String path,
+                           int dwDesiredAccess,
+                           int dwShareMode,
+                           int dwCreationDisposition,
+                           int dwFlagsAndAttributes)
+        throws WindowsException
+    {
+        return CreateFile(path, dwDesiredAccess, dwShareMode, 0L,
+                          dwCreationDisposition, dwFlagsAndAttributes);
+    }
+    private static native long CreateFile0(long lpFileName,
+                                           int dwDesiredAccess,
+                                           int dwShareMode,
+                                           long lpSecurityAttributes,
+                                           int dwCreationDisposition,
+                                           int dwFlagsAndAttributes)
+        throws WindowsException;
+
+    /**
+     * CloseHandle(
+     *   HANDLE hObject
+     * )
+     */
+    static native void CloseHandle(long handle);
+
+    /**
+     * DeleteFile(
+     *   LPCTSTR lpFileName
+     * )
+     */
+    static void DeleteFile(String path) throws WindowsException {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            DeleteFile0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void DeleteFile0(long lpFileName)
+        throws WindowsException;
+
+    /**
+     * CreateDirectory(
+     *   LPCTSTR lpPathName,
+     *   LPSECURITY_ATTRIBUTES lpSecurityAttributes
+     * )
+     */
+    static void CreateDirectory(String path, long lpSecurityAttributes) throws WindowsException {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            CreateDirectory0(buffer.address(), lpSecurityAttributes);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void CreateDirectory0(long lpFileName, long lpSecurityAttributes)
+        throws WindowsException;
+
+    /**
+     * RemoveDirectory(
+     *   LPCTSTR lpPathName
+     * )
+     */
+    static void RemoveDirectory(String path) throws WindowsException {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            RemoveDirectory0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void RemoveDirectory0(long lpFileName)
+        throws WindowsException;
+
+    /**
+     * Marks a file as a sparse file.
+     *
+     * DeviceIoControl(
+     *   FSCTL_SET_SPARSE
+     * )
+     */
+    static native void DeviceIoControlSetSparse(long handle)
+        throws WindowsException;
+
+    /**
+     * Retrieves the reparse point data associated with the file or directory.
+     *
+     * DeviceIoControl(
+     *   FSCTL_GET_REPARSE_POINT
+     * )
+     */
+    static native void DeviceIoControlGetReparsePoint(long handle,
+        long bufferAddress, int bufferSize) throws WindowsException;
+
+    /**
+     * HANDLE FindFirstFile(
+     *   LPCTSTR lpFileName,
+     *   LPWIN32_FIND_DATA lpFindFileData
+     * )
+     */
+    static FirstFile FindFirstFile(String path) throws WindowsException {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            FirstFile data = new FirstFile();
+            FindFirstFile0(buffer.address(), data);
+            return data;
+        } finally {
+            buffer.release();
+        }
+    }
+    static class FirstFile {
+        private long handle;
+        private String name;
+
+        private FirstFile() { }
+        public long handle()    { return handle; }
+        public String name()    { return name; }
+    }
+    private static native void FindFirstFile0(long lpFileName, FirstFile obj)
+        throws WindowsException;
+
+    /**
+     * HANDLE FindFirstFile(
+     *   LPCTSTR lpFileName,
+     *   LPWIN32_FIND_DATA lpFindFileData
+     * )
+     */
+    static long FindFirstFile(String path, long address) throws WindowsException {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            return FindFirstFile1(buffer.address(), address);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native long FindFirstFile1(long lpFileName, long address)
+        throws WindowsException;
+
+    /**
+     * FindNextFile(
+     *   HANDLE hFindFile,
+     *   LPWIN32_FIND_DATA lpFindFileData
+     * )
+     *
+     * @return  lpFindFileData->cFileName
+     */
+    static native String FindNextFile(long handle) throws WindowsException;
+
+    /**
+     * HANDLE FindFirstStreamW(
+     *   LPCWSTR lpFileName,
+     *   STREAM_INFO_LEVELS InfoLevel,
+     *   LPVOID lpFindStreamData,
+     *   DWORD dwFlags
+     * )
+     */
+    static FirstStream FindFirstStream(String path) throws WindowsException {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            FirstStream data = new FirstStream();
+            FindFirstStream0(buffer.address(), data);
+            if (data.handle() == WindowsConstants.INVALID_HANDLE_VALUE)
+                return null;
+            return data;
+        } finally {
+            buffer.release();
+        }
+    }
+    static class FirstStream {
+        private long handle;
+        private String name;
+
+        private FirstStream() { }
+        public long handle()    { return handle; }
+        public String name()    { return name; }
+    }
+    private static native void FindFirstStream0(long lpFileName, FirstStream obj)
+        throws WindowsException;
+
+    /*
+     * FindNextStreamW(
+     *   HANDLE hFindStream,
+     *   LPVOID lpFindStreamData
+     * )
+     */
+    static native String FindNextStream(long handle) throws WindowsException;
+
+    /**
+     * FindClose(
+     *   HANDLE hFindFile
+     * )
+     */
+    static native void FindClose(long handle) throws WindowsException;
+
+    /**
+     * GetFileInformationByHandle(
+     *   HANDLE hFile,
+     *   LPBY_HANDLE_FILE_INFORMATION lpFileInformation
+     * )
+     */
+    static native void GetFileInformationByHandle(long handle, long address)
+        throws WindowsException;
+
+    /**
+     * CopyFileEx(
+     *   LPCWSTR lpExistingFileName
+     *   LPCWSTR lpNewFileName,
+     *   LPPROGRESS_ROUTINE lpProgressRoutine
+     *   LPVOID lpData,
+     *   LPBOOL pbCancel,
+     *   DWORD dwCopyFlags
+     * )
+     */
+    static void CopyFileEx(String source, String target, int flags,
+                           long addressToPollForCancel)
+        throws WindowsException
+    {
+        NativeBuffer sourceBuffer = asNativeBuffer(source);
+        NativeBuffer targetBuffer = asNativeBuffer(target);
+        try {
+            CopyFileEx0(sourceBuffer.address(), targetBuffer.address(), flags,
+                        addressToPollForCancel);
+        } finally {
+            targetBuffer.release();
+            sourceBuffer.release();
+        }
+    }
+    private static native void CopyFileEx0(long existingAddress, long newAddress,
+        int flags, long addressToPollForCancel) throws WindowsException;
+
+    /**
+     * MoveFileEx(
+     *   LPCTSTR lpExistingFileName,
+     *   LPCTSTR lpNewFileName,
+     *   DWORD dwFlags
+     * )
+     */
+    static void MoveFileEx(String source, String target, int flags)
+        throws WindowsException
+    {
+        NativeBuffer sourceBuffer = asNativeBuffer(source);
+        NativeBuffer targetBuffer = asNativeBuffer(target);
+        try {
+            MoveFileEx0(sourceBuffer.address(), targetBuffer.address(), flags);
+        } finally {
+            targetBuffer.release();
+            sourceBuffer.release();
+        }
+    }
+    private static native void MoveFileEx0(long existingAddress, long newAddress,
+        int flags) throws WindowsException;
+
+    /**
+     * DWORD GetFileAttributes(
+     *   LPCTSTR lpFileName
+     * )
+     */
+    static int GetFileAttributes(String path) throws WindowsException {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            return GetFileAttributes0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native int GetFileAttributes0(long lpFileName)
+        throws WindowsException;
+
+    /**
+     * SetFileAttributes(
+     *   LPCTSTR lpFileName,
+     *   DWORD dwFileAttributes
+     */
+    static void SetFileAttributes(String path, int dwFileAttributes)
+        throws WindowsException
+    {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            SetFileAttributes0(buffer.address(), dwFileAttributes);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void SetFileAttributes0(long lpFileName,
+        int dwFileAttributes) throws WindowsException;
+
+    /**
+     * GetFileAttributesEx(
+     *   LPCTSTR lpFileName,
+     *   GET_FILEEX_INFO_LEVELS fInfoLevelId,
+     *   LPVOID lpFileInformation
+     * );
+     */
+    static void GetFileAttributesEx(String path, long address) throws WindowsException {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            GetFileAttributesEx0(buffer.address(), address);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native void GetFileAttributesEx0(long lpFileName, long address)
+        throws WindowsException;
+    /**
+     * SetFileTime(
+     *   HANDLE hFile,
+     *   CONST FILETIME *lpCreationTime,
+     *   CONST FILETIME *lpLastAccessTime,
+     *   CONST FILETIME *lpLastWriteTime
+     * )
+     */
+    static native void SetFileTime(long handle, long createTime,
+        long lastAccessTime, long lastWriteTime) throws WindowsException;
+
+    /**
+     * SetEndOfFile(
+     *   HANDLE hFile
+     * )
+     */
+    static native void SetEndOfFile(long handle) throws WindowsException;
+
+    /**
+     * DWORD GetLogicalDrives(VOID)
+     */
+    static native int GetLogicalDrives() throws WindowsException;
+
+    /**
+     * GetVolumeInformation(
+     *   LPCTSTR lpRootPathName,
+     *   LPTSTR lpVolumeNameBuffer,
+     *   DWORD nVolumeNameSize,
+     *   LPDWORD lpVolumeSerialNumber,
+     *   LPDWORD lpMaximumComponentLength,
+     *   LPDWORD lpFileSystemFlags,
+     *   LPTSTR lpFileSystemNameBuffer,
+     *   DWORD nFileSystemNameSize
+     * )
+     */
+    static VolumeInformation GetVolumeInformation(String root)
+        throws WindowsException
+    {
+        NativeBuffer buffer = asNativeBuffer(root);
+        try {
+            VolumeInformation info = new VolumeInformation();
+            GetVolumeInformation0(buffer.address(), info);
+            return info;
+        } finally {
+            buffer.release();
+        }
+    }
+    static class VolumeInformation {
+        private String fileSystemName;
+        private String volumeName;
+        private int volumeSerialNumber;
+        private int flags;
+        private VolumeInformation() { }
+
+        public String fileSystemName()      { return fileSystemName; }
+        public String volumeName()          { return volumeName; }
+        public int volumeSerialNumber()     { return volumeSerialNumber; }
+        public int flags()                  { return flags; }
+    }
+    private static native void GetVolumeInformation0(long lpRoot,
+                                                     VolumeInformation obj)
+        throws WindowsException;
+
+    /**
+     * UINT GetDriveType(
+     *   LPCTSTR lpRootPathName
+     * )
+     */
+    static int GetDriveType(String root) throws WindowsException {
+        NativeBuffer buffer = asNativeBuffer(root);
+        try {
+            return GetDriveType0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native int GetDriveType0(long lpRoot) throws WindowsException;
+
+    /**
+     * GetDiskFreeSpaceEx(
+     *   LPCTSTR lpDirectoryName,
+     *   PULARGE_INTEGER lpFreeBytesAvailableToCaller,
+     *   PULARGE_INTEGER lpTotalNumberOfBytes,
+     *   PULARGE_INTEGER lpTotalNumberOfFreeBytes
+     * )
+     */
+    static DiskFreeSpace GetDiskFreeSpaceEx(String path)
+        throws WindowsException
+    {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            DiskFreeSpace space = new DiskFreeSpace();
+            GetDiskFreeSpaceEx0(buffer.address(), space);
+            return space;
+        } finally {
+            buffer.release();
+        }
+    }
+    static class DiskFreeSpace {
+        private long freeBytesAvailable;
+        private long totalNumberOfBytes;
+        private long totalNumberOfFreeBytes;
+        private DiskFreeSpace() { }
+
+        public long freeBytesAvailable()      { return freeBytesAvailable; }
+        public long totalNumberOfBytes()      { return totalNumberOfBytes; }
+        public long totalNumberOfFreeBytes()  { return totalNumberOfFreeBytes; }
+    }
+    private static native void GetDiskFreeSpaceEx0(long lpDirectoryName,
+                                                   DiskFreeSpace obj)
+        throws WindowsException;
+
+
+    /**
+     * GetVolumePathName(
+     *   LPCTSTR lpszFileName,
+     *   LPTSTR lpszVolumePathName,
+     *   DWORD cchBufferLength
+     * )
+     *
+     * @return  lpFileName
+     */
+    static String GetVolumePathName(String path) throws WindowsException {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            return GetVolumePathName0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native String GetVolumePathName0(long lpFileName)
+        throws WindowsException;
+
+
+    /**
+     * InitializeSecurityDescriptor(
+     *   PSECURITY_DESCRIPTOR pSecurityDescriptor,
+     *   DWORD dwRevision
+     * )
+     */
+    static native void InitializeSecurityDescriptor(long sdAddress)
+        throws WindowsException;
+
+    /**
+     * InitializeAcl(
+     *   PACL pAcl,
+     *   DWORD nAclLength,
+     *   DWORD dwAclRevision
+     * )
+     */
+    static native void InitializeAcl(long aclAddress, int size)
+         throws WindowsException;
+
+    /**
+     * GetFileSecurity(
+     *   LPCTSTR lpFileName,
+     *   SECURITY_INFORMATION RequestedInformation,
+     *   PSECURITY_DESCRIPTOR pSecurityDescriptor,
+     *   DWORD nLength,
+     *   LPDWORD lpnLengthNeeded
+     * )
+     */
+    static int GetFileSecurity(String path,
+                               int requestedInformation,
+                               long pSecurityDescriptor,
+                               int nLength) throws WindowsException
+    {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            return GetFileSecurity0(buffer.address(), requestedInformation,
+                pSecurityDescriptor, nLength);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native int GetFileSecurity0(long lpFileName,
+                                               int requestedInformation,
+                                               long pSecurityDescriptor,
+                                               int nLength) throws WindowsException;
+
+    /**
+     * SetFileSecurity(
+     *   LPCTSTR lpFileName,
+     *   SECURITY_INFORMATION SecurityInformation,
+     *   PSECURITY_DESCRIPTOR pSecurityDescriptor
+     * )
+     */
+    static void SetFileSecurity(String path,
+                                int securityInformation,
+                                long pSecurityDescriptor)
+        throws WindowsException
+    {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            SetFileSecurity0(buffer.address(), securityInformation,
+                pSecurityDescriptor);
+        } finally {
+            buffer.release();
+        }
+    }
+    static native void SetFileSecurity0(long lpFileName, int securityInformation,
+        long pSecurityDescriptor) throws WindowsException;
+
+    /**
+     * GetSecurityDescriptorOwner(
+     *   PSECURITY_DESCRIPTOR pSecurityDescriptor
+     *   PSID *pOwner,
+     *   LPBOOL lpbOwnerDefaulted
+     * )
+     *
+     * @return  pOwner
+     */
+    static native long GetSecurityDescriptorOwner(long pSecurityDescriptor)
+        throws WindowsException;
+
+    /**
+     * SetSecurityDescriptorOwner(
+     *   PSECURITY_DESCRIPTOR pSecurityDescriptor,
+     *   PSID pOwner,
+     *   BOOL bOwnerDefaulted
+     * )
+     */
+    static native void SetSecurityDescriptorOwner(long pSecurityDescriptor,
+                                                  long pOwner)
+        throws WindowsException;
+
+    /**
+     * GetSecurityDescriptorDacl(
+     *   PSECURITY_DESCRIPTOR pSecurityDescriptor,
+     *   LPBOOL lpbDaclPresent,
+     *   PACL *pDacl,
+     *   LPBOOL lpbDaclDefaulted
+     * )
+     */
+    static native long GetSecurityDescriptorDacl(long pSecurityDescriptor);
+
+    /**
+     * SetSecurityDescriptorDacl(
+     *   PSECURITY_DESCRIPTOR pSecurityDescriptor,
+     *   BOOL bDaclPresent,
+     *   PACL pDacl,
+     *   BOOL bDaclDefaulted
+     * )
+     */
+    static native void SetSecurityDescriptorDacl(long pSecurityDescriptor, long pAcl)
+        throws WindowsException;
+
+
+    /**
+     * GetAclInformation(
+     *   PACL pAcl,
+     *   LPVOID pAclInformation,
+     *   DWORD nAclInformationLength,
+     *   ACL_INFORMATION_CLASS dwAclInformationClass
+     * )
+     */
+    static AclInformation GetAclInformation(long aclAddress) {
+        AclInformation info = new AclInformation();
+        GetAclInformation0(aclAddress, info);
+        return info;
+    }
+    static class AclInformation {
+        private int aceCount;
+        private AclInformation() { }
+
+        public int aceCount()   { return aceCount; }
+    }
+    private static native void GetAclInformation0(long aclAddress,
+        AclInformation obj);
+
+    /**
+     * GetAce(
+     *   PACL pAcl,
+     *   DWORD dwAceIndex,
+     *   LPVOID *pAce
+     * )
+     */
+    static native long GetAce(long aclAddress, int aceIndex);
+
+    /**
+     * AddAccessAllowedAceEx(
+     *   PACL pAcl,
+     *   DWORD dwAceRevision,
+     *   DWORD AceFlags,
+     *   DWORD AccessMask,
+     *   PSID pSid
+     * )
+     */
+    static native void AddAccessAllowedAceEx(long aclAddress, int flags,
+        int mask, long sidAddress) throws WindowsException;
+
+    /**
+     * AddAccessDeniedAceEx(
+     *   PACL pAcl,
+     *   DWORD dwAceRevision,
+     *   DWORD AceFlags,
+     *   DWORD AccessMask,
+     *   PSID pSid
+     * )
+     */
+    static native void AddAccessDeniedAceEx(long aclAddress, int flags,
+        int mask, long sidAddress) throws WindowsException;
+
+    /**
+     * LookupAccountSid(
+     *   LPCTSTR lpSystemName,
+     *   PSID Sid,
+     *   LPTSTR Name,
+     *   LPDWORD cbName,
+     *   LPTSTR ReferencedDomainName,
+     *   LPDWORD cbReferencedDomainName,
+     *   PSID_NAME_USE peUse
+     * )
+     */
+    static Account LookupAccountSid(long sidAddress) throws WindowsException {
+        Account acc = new Account();
+        LookupAccountSid0(sidAddress, acc);
+        return acc;
+    }
+    static class Account {
+        private String domain;
+        private String name;
+        private int use;
+        private Account() { }
+
+        public String domain()  { return domain; }
+        public String name()    { return name; }
+        public int use()        { return use; }
+    }
+    private static native void LookupAccountSid0(long sidAddress, Account obj)
+        throws WindowsException;
+
+    /**
+     * LookupAccountName(
+     *   LPCTSTR lpSystemName,
+     *   LPCTSTR lpAccountName,
+     *   PSID Sid,
+     *   LPDWORD cbSid,
+     *   LPTSTR ReferencedDomainName,
+     *   LPDWORD cbReferencedDomainName,
+     *   PSID_NAME_USE peUse
+     * )
+     *
+     * @return  cbSid
+     */
+    static int LookupAccountName(String accountName,
+                                 long pSid,
+                                 int cbSid) throws WindowsException
+    {
+        NativeBuffer buffer = asNativeBuffer(accountName);
+        try {
+            return LookupAccountName0(buffer.address(), pSid, cbSid);
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native int LookupAccountName0(long lpAccountName, long pSid,
+        int cbSid) throws WindowsException;
+
+    /**
+     * DWORD GetLengthSid(
+     *   PSID pSid
+     * )
+     */
+    static native int GetLengthSid(long sidAddress);
+
+    /**
+     * ConvertSidToStringSid(
+     *   PSID Sid,
+     *   LPTSTR* StringSid
+     * )
+     *
+     * @return  StringSid
+     */
+    static native String ConvertSidToStringSid(long sidAddress)
+        throws WindowsException;
+
+    /**
+     * ConvertStringSidToSid(
+     *   LPCTSTR StringSid,
+     *   PSID* pSid
+     * )
+     *
+     * @return  pSid
+     */
+    static long ConvertStringSidToSid(String sidString)
+        throws WindowsException
+    {
+        NativeBuffer buffer = asNativeBuffer(sidString);
+        try {
+            return ConvertStringSidToSid0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native long ConvertStringSidToSid0(long lpStringSid)
+        throws WindowsException;
+
+    /**
+     * HANDLE GetCurrentProcess(VOID)
+     */
+    static native long GetCurrentProcess();
+
+    /**
+     * HANDLE GetCurrentThread(VOID)
+     */
+    static native long GetCurrentThread();
+
+    /**
+     * OpenProcessToken(
+     *   HANDLE ProcessHandle,
+     *   DWORD DesiredAccess,
+     *   PHANDLE TokenHandle
+     * )
+     */
+    static native long OpenProcessToken(long hProcess, int desiredAccess)
+        throws WindowsException;
+
+    /**
+     * OpenThreadToken(
+     *   HANDLE ThreadHandle,
+     *   DWORD DesiredAccess,
+     *   BOOL OpenAsSelf,
+     *   PHANDLE TokenHandle
+     * )
+     */
+    static native long OpenThreadToken(long hThread, int desiredAccess,
+        boolean openAsSelf) throws WindowsException;
+
+    /**
+     */
+    static native long DuplicateTokenEx(long hThread, int desiredAccess)
+        throws WindowsException;
+
+    /**
+     * SetThreadToken(
+     *   PHANDLE Thread,
+     *   HANDLE Token
+     * )
+     */
+    static native void SetThreadToken(long thread, long hToken)
+        throws WindowsException;
+
+    /**
+     * GetTokenInformation(
+     *   HANDLE TokenHandle,
+     *   TOKEN_INFORMATION_CLASS TokenInformationClass,
+     *   LPVOID TokenInformation,
+     *   DWORD TokenInformationLength,
+     *   PDWORD ReturnLength
+     * )
+     */
+    static native int GetTokenInformation(long token, int tokenInfoClass,
+        long pTokenInfo, int tokenInfoLength) throws WindowsException;
+
+    /**
+     * AdjustTokenPrivileges(
+     *   HANDLE TokenHandle,
+     *   BOOL DisableAllPrivileges
+     *   PTOKEN_PRIVILEGES NewState
+     *   DWORD BufferLength
+     *   PTOKEN_PRIVILEGES
+     *   PDWORD ReturnLength
+     * )
+     */
+    static native void AdjustTokenPrivileges(long token, long luid, int attributes)
+        throws WindowsException;
+
+    /**
+     */
+    static long LookupPrivilegeValue(String name) throws WindowsException {
+        NativeBuffer buffer = asNativeBuffer(name);
+        try {
+            return LookupPrivilegeValue0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native long LookupPrivilegeValue0(long lpName)
+        throws WindowsException;
+
+    /**
+     * BuildTrusteeWithSid(
+     *   PTRUSTEE pTrustee,
+     *   PSID pSid
+     * )
+     *
+     * @return  pTrustee
+     */
+    static native long BuildTrusteeWithSid(long pSid);
+
+    /**
+     * GetEffectiveRightsFromAcl(
+     *   PACL pacl,
+     *   PTRUSTEE pTrustee,
+     *   PACCESS_MASK pAccessRights
+     * )
+     *
+     * @return  AccessRights
+     */
+    static native int GetEffectiveRightsFromAcl(long pAcl, long pTrustee)
+        throws WindowsException;
+
+    /**
+     * CreateSymbolicLink(
+     *   LPCWSTR lpSymlinkFileName,
+     *   LPCWSTR lpTargetFileName,
+     *   DWORD dwFlags
+     * )
+     */
+    static void CreateSymbolicLink(String link, String target, int flags)
+        throws WindowsException
+    {
+        NativeBuffer linkBuffer = asNativeBuffer(link);
+        NativeBuffer targetBuffer = asNativeBuffer(target);
+        try {
+            CreateSymbolicLink0(linkBuffer.address(), targetBuffer.address(),
+                                flags);
+        } finally {
+            targetBuffer.release();
+            linkBuffer.release();
+        }
+    }
+    private static native void CreateSymbolicLink0(long linkAddress,
+        long targetAddress, int flags) throws WindowsException;
+
+    /**
+     * CreateHardLink(
+     *    LPCTSTR lpFileName,
+     *    LPCTSTR lpExistingFileName,
+     *    LPSECURITY_ATTRIBUTES lpSecurityAttributes
+     * )
+     */
+    static void CreateHardLink(String newFile, String existingFile)
+        throws WindowsException
+    {
+        NativeBuffer newFileBuffer = asNativeBuffer(newFile);
+        NativeBuffer existingFileBuffer = asNativeBuffer(existingFile);
+        try {
+            CreateHardLink0(newFileBuffer.address(), existingFileBuffer.address());
+        } finally {
+            existingFileBuffer.release();
+            newFileBuffer.release();
+        }
+    }
+    private static native void CreateHardLink0(long newFileBuffer,
+        long existingFiletBuffer) throws WindowsException;
+
+    /**
+     * GetFullPathName(
+     *   LPCTSTR lpFileName,
+     *   DWORD nBufferLength,
+     *   LPTSTR lpBuffer,
+     *   LPTSTR *lpFilePart
+     * )
+     */
+    static String GetFullPathName(String path) throws WindowsException {
+        NativeBuffer buffer = asNativeBuffer(path);
+        try {
+            return GetFullPathName0(buffer.address());
+        } finally {
+            buffer.release();
+        }
+    }
+    private static native String GetFullPathName0(long pathAddress)
+        throws WindowsException;
+
+    /**
+     * GetFinalPathNameByHandle(
+     *   HANDLE hFile,
+     *   LPTSTR lpszFilePath,
+     *   DWORD cchFilePath,
+     *   DWORD dwFlags
+     * )
+     */
+    static native String GetFinalPathNameByHandle(long handle)
+        throws WindowsException;
+
+    /**
+     * FormatMessage(
+     *   DWORD dwFlags,
+     *   LPCVOID lpSource,
+     *   DWORD dwMessageId,
+     *   DWORD dwLanguageId,
+     *   LPTSTR lpBuffer,
+     *   DWORD nSize,
+     *   va_list *Arguments
+     * )
+     */
+    static native String FormatMessage(int errorCode);
+
+    /**
+     * LocalFree(
+     *   HLOCAL hMem
+     * )
+     */
+    static native void LocalFree(long address);
+
+    /**
+     * HANDLE CreateIoCompletionPort (
+     *   HANDLE FileHandle,
+     *   HANDLE ExistingCompletionPort,
+     *   DWORD CompletionKey,
+     *   DWORD NumberOfConcurrentThreads
+     * )
+     */
+    static native long CreateIoCompletionPort(long fileHandle, long existingPort,
+        int completionKey) throws WindowsException;
+
+
+    /**
+     * GetQueuedCompletionStatus(
+     *   HANDLE CompletionPort,
+     *   LPDWORD lpNumberOfBytesTransferred,
+     *   LPDWORD lpCompletionKey,
+     *   LPOVERLAPPED *lpOverlapped,
+     *   DWORD dwMilliseconds
+     */
+    static CompletionStatus GetQueuedCompletionStatus(long completionPort)
+        throws WindowsException
+    {
+        CompletionStatus status = new CompletionStatus();
+        GetQueuedCompletionStatus0(completionPort, status);
+        return status;
+    }
+    static class CompletionStatus {
+        private int error;
+        private int bytesTransferred;
+        private int completionKey;
+        private CompletionStatus() { }
+
+        int error() { return error; }
+        int bytesTransferred() { return bytesTransferred; }
+        int completionKey() { return completionKey; }
+    }
+    private static native void GetQueuedCompletionStatus0(long completionPort,
+        CompletionStatus status) throws WindowsException;
+
+    /**
+     * PostQueuedCompletionStatus(
+     *   HANDLE CompletionPort,
+     *   DWORD dwNumberOfBytesTransferred,
+     *   DWORD dwCompletionKey,
+     *   LPOVERLAPPED lpOverlapped
+     * )
+     */
+    static native void PostQueuedCompletionStatus(long completionPort,
+        int completionKey) throws WindowsException;
+
+    /**
+     * ReadDirectoryChangesW(
+     *   HANDLE hDirectory,
+     *   LPVOID lpBuffer,
+     *   DWORD nBufferLength,
+     *   BOOL bWatchSubtree,
+     *   DWORD dwNotifyFilter,
+     *   LPDWORD lpBytesReturned,
+     *   LPOVERLAPPED lpOverlapped,
+     *   LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
+     * )
+     */
+    static native void ReadDirectoryChangesW(long hDirectory,
+                                             long bufferAddress,
+                                             int bufferLength,
+                                             boolean watchSubTree,
+                                             int filter,
+                                             long bytesReturnedAddress,
+                                             long pOverlapped)
+        throws WindowsException;
+
+    /**
+     * BackupRead(
+     *   HANDLE hFile,
+     *   LPBYTE lpBuffer,
+     *   DWORD nNumberOfBytesToRead,
+     *   LPDWORD lpNumberOfBytesRead,
+     *   BOOL bAbort,
+     *   BOOL bProcessSecurity,
+     *   LPVOID* lpContext
+     * )
+     */
+    static BackupResult BackupRead(long hFile,
+                                   long bufferAddress,
+                                   int bufferSize,
+                                   boolean abort,
+                                   long context)
+        throws WindowsException
+    {
+        BackupResult result = new BackupResult();
+        BackupRead0(hFile, bufferAddress, bufferSize, abort, context, result);
+        return result;
+    }
+    static class BackupResult {
+        private int bytesTransferred;
+        private long context;
+        private BackupResult() { }
+
+        int bytesTransferred() { return bytesTransferred; }
+        long context() { return context; }
+    }
+    private static native void BackupRead0(long hFile, long bufferAddress,
+        int bufferSize, boolean abort, long context, BackupResult result)
+        throws WindowsException;
+
+    /**
+     * BackupSeek(
+     *   HANDLE hFile,
+     *   DWORD dwLowBytesToSeek,
+     *   DWORD dwHighBytesToSeek,
+     *   LPDWORD lpdwLowByteSeeked,
+     *   LPDWORD lpdwHighByteSeeked,
+     *   LPVOID* lpContext
+     * )
+     */
+    static native void BackupSeek(long hFile, long bytesToSeek, long context)
+        throws WindowsException;
+
+
+    // -- support for copying String with a NativeBuffer --
+
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    static NativeBuffer asNativeBuffer(String s) {
+        int stringLengthInBytes = s.length() << 1;
+        int sizeInBytes = stringLengthInBytes + 2;  // char terminator
+
+        // get a native buffer of sufficient size
+        NativeBuffer buffer = NativeBuffers.getNativeBufferFromCache(sizeInBytes);
+        if (buffer == null) {
+            buffer = NativeBuffers.allocNativeBuffer(sizeInBytes);
+        } else {
+            // buffer already contains the string contents
+            if (buffer.owner() == s)
+                return buffer;
+        }
+
+        // copy into buffer and zero terminate
+        char[] chars = s.toCharArray();
+        unsafe.copyMemory(chars, Unsafe.ARRAY_CHAR_BASE_OFFSET, null,
+            buffer.address(), (long)stringLengthInBytes);
+        unsafe.putChar(buffer.address() + stringLengthInBytes, (char)0);
+        buffer.setOwner(s);
+        return buffer;
+    }
+
+    // -- native library initialization --
+
+    private static native void initIDs();
+
+    static {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                // nio.dll has dependency on net.dll
+                System.loadLibrary("net");
+                System.loadLibrary("nio");
+                return null;
+        }});
+        initIDs();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,1316 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.nio.file.spi.AbstractPath;
+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.*;
+
+/**
+ * Windows implementation of Path
+ */
+
+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
+    // minus 12 minus 1 (to allow for the creation of a 8.3 file in the
+    // directory).
+    private static final int MAX_PATH = 247;
+
+    // Maximum extended-length path
+    private static final int MAX_LONG_PATH = 32000;
+
+    // FIXME - eliminate this reference to reduce space
+    private final WindowsFileSystem fs;
+
+    // path type
+    private final WindowsPathType type;
+    // root component (may be empty)
+    private final String root;
+    // normalized path
+    private final String path;
+
+    // the path to use in Win32 calls. This differs from path for relative
+    // paths and has a long path prefix for all paths longer than MAX_PATH.
+    private volatile WeakReference<String> pathForWin32Calls;
+
+    // offsets into name components (computed lazily)
+    private volatile Integer[] offsets;
+
+    // computed hash code (computed lazily, no need to be volatile)
+    private int hash;
+
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    WindowsPath(WindowsFileSystem fs,
+                WindowsPathType type,
+                String root,
+                String path)
+    {
+        this.fs = fs;
+        this.type = type;
+        this.root = root;
+        this.path = path;
+    }
+
+    /**
+     * Creates a WindowsPath by parsing the given path.
+     */
+    static WindowsPath parse(WindowsFileSystem fs, String path) {
+        WindowsPathParser.Result result = WindowsPathParser.parse(path);
+        return new WindowsPath(fs, result.type(), result.root(), result.path());
+    }
+
+    /**
+     * Creates a WindowsPath from a given path that is known to be normalized.
+     */
+    static WindowsPath createFromNormalizedPath(WindowsFileSystem fs, String path) {
+        try {
+            WindowsPathParser.Result result =
+                WindowsPathParser.parseNormalizedPath(path);
+            return new WindowsPath(fs, result.type(), result.root(), result.path());
+        } catch (InvalidPathException x) {
+            throw new AssertionError(x.getMessage());
+        }
+    }
+
+    // use this message when throwing exceptions
+    String getPathForExceptionMessage() {
+        return path;
+    }
+
+    // use this path for permission checks
+    String getPathForPermissionCheck() {
+        return path;
+    }
+
+    // use this path for Win32 calls
+    // This method will prefix long paths with \\?\ or \\?\UNC as required.
+    String getPathForWin32Calls() throws WindowsException {
+        // short absolute paths can be used directly
+        if (isAbsolute() && path.length() <= MAX_PATH)
+            return path;
+
+        // return cached values if available
+        WeakReference<String> ref = pathForWin32Calls;
+        String resolved = (ref != null) ? ref.get() : null;
+        if (resolved != null) {
+            // Win32 path already available
+            return resolved;
+        }
+
+        // resolve against default directory
+        resolved = getAbsolutePath();
+
+        // Long paths need to have "." and ".." removed and be prefixed with
+        // "\\?\". Note that it is okay to remove ".." even when it follows
+        // a link - for example, it is okay for foo/link/../bar to be changed
+        // to foo/bar. The reason is that Win32 APIs to access foo/link/../bar
+        // will access foo/bar anyway (which differs to Unix systems)
+        if (resolved.length() > MAX_PATH) {
+            if (resolved.length() > MAX_LONG_PATH) {
+                throw new WindowsException("Cannot access file with path exceeding "
+                    + MAX_LONG_PATH + " characters");
+            }
+            resolved = addPrefixIfNeeded(GetFullPathName(resolved));
+        }
+
+        // cache the resolved path (except drive relative paths as the working
+        // directory on removal media devices can change during the lifetime
+        // of the VM)
+        if (type != WindowsPathType.DRIVE_RELATIVE) {
+            synchronized (path) {
+                pathForWin32Calls = new WeakReference<String>(resolved);
+            }
+        }
+        return resolved;
+    }
+
+    // return this path resolved against the file system's default directory
+    private String getAbsolutePath() throws WindowsException {
+        if (isAbsolute())
+            return path;
+
+        // Relative path ("foo" for example)
+        if (type == WindowsPathType.RELATIVE) {
+            String defaultDirectory = getFileSystem().defaultDirectory();
+            if (defaultDirectory.endsWith("\\")) {
+                return defaultDirectory + path;
+            } else {
+                StringBuilder sb =
+                    new StringBuilder(defaultDirectory.length() + path.length() + 1);
+                return sb.append(defaultDirectory).append('\\').append(path).toString();
+            }
+        }
+
+        // Directory relative path ("\foo" for example)
+        if (type == WindowsPathType.DIRECTORY_RELATIVE) {
+            String defaultRoot = getFileSystem().defaultRoot();
+            return defaultRoot + path.substring(1);
+        }
+
+        // Drive relative path ("C:foo" for example).
+        if (isSameDrive(root, getFileSystem().defaultRoot())) {
+            // relative to default directory
+            String remaining = path.substring(root.length());
+            String defaultDirectory = getFileSystem().defaultDirectory();
+            String result;
+            if (defaultDirectory.endsWith("\\")) {
+                result = defaultDirectory + remaining;
+            } else {
+                result = defaultDirectory + "\\" + remaining;
+            }
+            return result;
+        } else {
+            // relative to some other drive
+            String wd;
+            try {
+                int dt = GetDriveType(root + "\\");
+                if (dt == DRIVE_UNKNOWN || dt == DRIVE_NO_ROOT_DIR)
+                    throw new WindowsException("");
+                wd = GetFullPathName(root + ".");
+            } catch (WindowsException x) {
+                throw new WindowsException("Unable to get working directory of drive '" +
+                    Character.toUpperCase(root.charAt(0)) + "'");
+            }
+            String result = wd;
+            if (wd.endsWith("\\")) {
+                result += path.substring(root.length());
+            } else {
+                if (path.length() > root.length())
+                    result += "\\" + path.substring(root.length());
+            }
+            return result;
+        }
+    }
+
+    // returns true if same drive letter
+    private static boolean isSameDrive(String root1, String root2) {
+        return Character.toUpperCase(root1.charAt(0)) ==
+               Character.toUpperCase(root2.charAt(0));
+    }
+
+    // Add long path prefix to path if required
+    private static String addPrefixIfNeeded(String path) {
+        if (path.length() > 248) {
+            if (path.startsWith("\\\\")) {
+                path = "\\\\?\\UNC" + path.substring(1, path.length());
+            } else {
+                path = "\\\\?\\" + path;
+            }
+        }
+        return path;
+    }
+
+    @Override
+    public WindowsFileSystem getFileSystem() {
+        return fs;
+    }
+
+    // -- Path operations --
+
+    @Override
+    public Path getName() {
+        // represents root component only
+        if (root.length() == path.length())
+            return null;
+        int off = path.lastIndexOf('\\');
+        if (off < root.length())
+            off = root.length();
+        else
+            off++;
+        return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", path.substring(off));
+    }
+
+    @Override
+    public WindowsPath getParent() {
+        // represents root component only
+        if (root.length() == path.length())
+            return null;
+        int off = path.lastIndexOf('\\');
+        if (off < root.length())
+            return getRoot();
+        else
+            return new WindowsPath(getFileSystem(),
+                                   type,
+                                   root,
+                                   path.substring(0, off));
+    }
+
+    @Override
+    public WindowsPath getRoot() {
+        if (root.length() == 0)
+            return null;
+        return new WindowsPath(getFileSystem(), type, root, root);
+    }
+
+    // package-private
+    boolean isUnc() {
+        return type == WindowsPathType.UNC;
+    }
+
+    @Override
+    public boolean isAbsolute() {
+        return type == WindowsPathType.ABSOLUTE || type == WindowsPathType.UNC;
+    }
+
+    private WindowsPath checkPath(FileRef path) {
+        if (path == null)
+            throw new NullPointerException();
+        if (!(path instanceof WindowsPath)) {
+            throw new ProviderMismatchException();
+        }
+        return (WindowsPath)path;
+    }
+
+    @Override
+    public WindowsPath relativize(Path obj) {
+        WindowsPath other = checkPath(obj);
+        if (this.equals(other))
+            return null;
+
+        // can only relativize paths of the same type
+        if (this.type != other.type)
+            throw new IllegalArgumentException("'other' is different type of Path");
+
+        // can only relativize paths if root component matches
+        if (!this.root.equalsIgnoreCase(other.root))
+            throw new IllegalArgumentException("'other' has different root");
+
+        int bn = this.getNameCount();
+        int cn = other.getNameCount();
+
+        // skip matching names
+        int n = (bn > cn) ? cn : bn;
+        int i = 0;
+        while (i < n) {
+            if (!this.getName(i).equals(other.getName(i)))
+                break;
+            i++;
+        }
+
+        // append ..\ for remaining names in the base
+        StringBuilder result = new StringBuilder();
+        for (int j=i; j<bn; j++) {
+            result.append("..\\");
+        }
+
+        // append remaining names in child
+        for (int j=i; j<cn; j++) {
+            result.append(other.getName(j).toString());
+            result.append("\\");
+        }
+
+        // drop trailing slash in result
+        result.setLength(result.length()-1);
+        return createFromNormalizedPath(getFileSystem(), result.toString());
+    }
+
+    @Override
+    public Path normalize() {
+        final int count = getNameCount();
+        if (count == 0)
+            return this;
+
+        boolean[] ignore = new boolean[count];      // true => ignore name
+        int remaining = count;                      // number of names remaining
+
+        // multiple passes to eliminate all occurences of "." and "name/.."
+        int prevRemaining;
+        do {
+            prevRemaining = remaining;
+            int prevName = -1;
+            for (int i=0; i<count; i++) {
+                if (ignore[i])
+                    continue;
+
+                String name = elementAsString(i);
+
+                // not "." or ".."
+                if (name.length() > 2) {
+                    prevName = i;
+                    continue;
+                }
+
+                // "." or something else
+                if (name.length() == 1) {
+                    // ignore "."
+                    if (name.charAt(0) == '.') {
+                        ignore[i] = true;
+                        remaining--;
+                    } else {
+                        prevName = i;
+                    }
+                    continue;
+                }
+
+                // not ".."
+                if (name.charAt(0) != '.' || name.charAt(1) != '.') {
+                    prevName = i;
+                    continue;
+                }
+
+                // ".." found
+                if (prevName >= 0) {
+                    // name/<ignored>/.. found so mark name and ".." to be
+                    // ignored
+                    ignore[prevName] = true;
+                    ignore[i] = true;
+                    remaining = remaining - 2;
+                    prevName = -1;
+                } else {
+                    // Cases:
+                    //    C:\<ignored>\..
+                    //    \\server\\share\<ignored>\..
+                    //    \<ignored>..
+                    if (isAbsolute() || type == WindowsPathType.DIRECTORY_RELATIVE) {
+                        boolean hasPrevious = false;
+                        for (int j=0; j<i; j++) {
+                            if (!ignore[j]) {
+                                hasPrevious = true;
+                                break;
+                            }
+                        }
+                        if (!hasPrevious) {
+                            // all proceeding names are ignored
+                            ignore[i] = true;
+                            remaining--;
+                        }
+                    }
+                }
+            }
+        } while (prevRemaining > remaining);
+
+        // no redundant names
+        if (remaining == count)
+            return this;
+
+        // corner case - all names removed
+        if (remaining == 0) {
+            return getRoot();
+        }
+
+        // re-constitute the path from the remaining names.
+        StringBuilder result = new StringBuilder();
+        if (root != null)
+            result.append(root);
+        for (int i=0; i<count; i++) {
+            if (!ignore[i]) {
+                result.append(getName(i).toString());
+                result.append("\\");
+            }
+        }
+
+        // drop trailing slash in result
+        result.setLength(result.length()-1);
+        return createFromNormalizedPath(getFileSystem(), result.toString());
+    }
+
+    @Override
+    public WindowsPath resolve(Path obj) {
+        if (obj == null)
+            return this;
+        WindowsPath other = checkPath(obj);
+        if (other.isAbsolute())
+            return other;
+
+        switch (other.type) {
+            case RELATIVE: {
+                String result;
+                if (path.endsWith("\\") || (root.length() == path.length())) {
+                    result = path + other.path;
+                } else {
+                    result = path + "\\" + other.path;
+                }
+                return new WindowsPath(getFileSystem(), type, root, result);
+            }
+
+            case DIRECTORY_RELATIVE: {
+                String result;
+                if (root.endsWith("\\")) {
+                    result = root + other.path.substring(1);
+                } else {
+                    result = root + other.path;
+                }
+                return createFromNormalizedPath(getFileSystem(), result);
+            }
+
+            case DRIVE_RELATIVE: {
+                if (!root.endsWith("\\"))
+                    return other;
+                // if different roots then return other
+                String thisRoot = root.substring(0, root.length()-1);
+                if (!thisRoot.equalsIgnoreCase(other.root))
+                    return other;
+                // same roots
+                String remaining = other.path.substring(other.root.length());
+                String result;
+                if (path.endsWith("\\")) {
+                    result = path + remaining;
+                } else {
+                    result = path + "\\" + remaining;
+                }
+                return createFromNormalizedPath(getFileSystem(), result);
+            }
+
+            default:
+                throw new AssertionError();
+        }
+    }
+
+    @Override
+    public WindowsPath resolve(String other) {
+        return resolve(getFileSystem().getPath(other));
+    }
+
+    // generate offset array
+    private void initOffsets() {
+        if (offsets == null) {
+            ArrayList<Integer> list = new ArrayList<Integer>();
+            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);
+            synchronized (this) {
+                if (offsets == null)
+                    offsets = list.toArray(new Integer[list.size()]);
+            }
+        }
+    }
+
+    @Override
+    public int getNameCount() {
+        initOffsets();
+        return offsets.length;
+    }
+
+    private String elementAsString(int i) {
+        initOffsets();
+        if (i == (offsets.length-1))
+            return path.substring(offsets[i]);
+        return path.substring(offsets[i], offsets[i+1]-1);
+    }
+
+    @Override
+    public WindowsPath getName(int index) {
+        initOffsets();
+        if (index < 0 || index >= offsets.length)
+            throw new IllegalArgumentException();
+        return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", elementAsString(index));
+    }
+
+    @Override
+    public WindowsPath subpath(int beginIndex, int endIndex) {
+        initOffsets();
+        if (beginIndex < 0)
+            throw new IllegalArgumentException();
+        if (beginIndex >= offsets.length)
+            throw new IllegalArgumentException();
+        if (endIndex > offsets.length)
+            throw new IllegalArgumentException();
+        if (beginIndex >= endIndex)
+            throw new IllegalArgumentException();
+
+        StringBuilder sb = new StringBuilder();
+        Integer[] nelems = new Integer[endIndex - beginIndex];
+        for (int i = beginIndex; i < endIndex; i++) {
+            nelems[i-beginIndex] = sb.length();
+            sb.append(elementAsString(i));
+            if (i != (endIndex-1))
+                sb.append("\\");
+        }
+        return new WindowsPath(getFileSystem(), WindowsPathType.RELATIVE, "", sb.toString());
+    }
+
+    @Override
+    public boolean startsWith(Path obj) {
+        WindowsPath other = checkPath(obj);
+
+        // if this path has a root component the given path's root must match
+        if (!this.root.equalsIgnoreCase(other.root))
+            return false;
+
+        // roots match so compare elements
+        int thisCount = getNameCount();
+        int otherCount = other.getNameCount();
+        if (otherCount <= thisCount) {
+            while (--otherCount >= 0) {
+                String thisElement = this.elementAsString(otherCount);
+                String otherElement = other.elementAsString(otherCount);
+                // FIXME: should compare in uppercase
+                if (!thisElement.equalsIgnoreCase(otherElement))
+                    return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean endsWith(Path obj) {
+        WindowsPath other = checkPath(obj);
+
+        // other path is longer
+        if (other.path.length() > path.length()) {
+            return false;
+        }
+
+        int thisCount = this.getNameCount();
+        int otherCount = other.getNameCount();
+
+        // given path has more elements that this path
+        if (otherCount > thisCount) {
+            return false;
+        }
+
+        // compare roots
+        if (other.root.length() > 0) {
+            if (otherCount < thisCount)
+                return false;
+            // FIXME: should compare in uppercase
+            if (!this.root.equalsIgnoreCase(other.root))
+                return false;
+        }
+
+        // match last 'otherCount' elements
+        int off = thisCount - otherCount;
+        while (--otherCount >= 0) {
+            String thisElement = this.elementAsString(off + otherCount);
+            String otherElement = other.elementAsString(otherCount);
+            // FIXME: should compare in uppercase
+            if (!thisElement.equalsIgnoreCase(otherElement))
+                return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int compareTo(Path obj) {
+        if (obj == null)
+            throw new NullPointerException();
+        String s1 = path;
+        String s2 = ((WindowsPath)obj).path;
+        int n1 = s1.length();
+        int n2 = s2.length();
+        int min = Math.min(n1, n2);
+        for (int i = 0; i < min; i++) {
+            char c1 = s1.charAt(i);
+            char c2 = s2.charAt(i);
+             if (c1 != c2) {
+                 c1 = Character.toUpperCase(c1);
+                 c2 = Character.toUpperCase(c2);
+                 if (c1 != c2) {
+                     return c1 - c2;
+                 }
+             }
+        }
+        return n1 - n2;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if ((obj != null) && (obj instanceof WindowsPath)) {
+            return compareTo((Path)obj) == 0;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        // OK if two or more threads compute hash
+        int h = hash;
+        if (h == 0) {
+            for (int i = 0; i< path.length(); i++) {
+                h = 31*h + Character.toUpperCase(path.charAt(i));
+            }
+            hash = h;
+        }
+        return h;
+    }
+
+    @Override
+    public String toString() {
+        return path;
+    }
+
+    @Override
+    public Iterator<Path> iterator() {
+        return new Iterator<Path>() {
+            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
+    long openForReadAttributeAccess(boolean followLinks)
+        throws WindowsException
+    {
+        int flags = FILE_FLAG_BACKUP_SEMANTICS;
+        if (!followLinks && getFileSystem().supportsLinks())
+            flags |= FILE_FLAG_OPEN_REPARSE_POINT;
+        return CreateFile(getPathForWin32Calls(),
+                          FILE_READ_ATTRIBUTES,
+                          (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
+                          0L,
+                          OPEN_EXISTING,
+                          flags);
+    }
+
+    void checkRead() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkRead(getPathForPermissionCheck());
+        }
+    }
+
+    void checkWrite() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkWrite(getPathForPermissionCheck());
+        }
+    }
+
+    void checkDelete() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkDelete(getPathForPermissionCheck());
+        }
+    }
+
+    @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
+    public void delete(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<Path> newDirectoryStream(DirectoryStream.Filter<? super Path> 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 extends FileAttributeView> V
+        getFileAttributeView(Class<V> 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 FileAttributeView 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("xattr"))
+            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 InputStream newInputStream()throws IOException {
+        try {
+            Set<OpenOption> options = Collections.emptySet();
+            FileChannel fc = WindowsChannelFactory
+                .newFileChannel(getPathForWin32Calls(),
+                                getPathForPermissionCheck(),
+                                options,
+                                0L);
+            return Channels.newInputStream(fc);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(this);
+            return null;  // keep compiler happy
+        }
+    }
+
+    @Override
+    public SeekableByteChannel newByteChannel(Set<? extends OpenOption> 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 OutputStream newOutputStream(Set<? extends OpenOption> options,
+                                        FileAttribute<?>... attrs)
+        throws IOException
+    {
+        // need to copy options to add WRITE
+        Set<OpenOption> opts = new HashSet<OpenOption>(options);
+        if (opts.contains(StandardOpenOption.READ))
+            throw new IllegalArgumentException("READ not allowed");
+        opts.add(StandardOpenOption.WRITE);
+
+        WindowsSecurityDescriptor sd =
+            WindowsSecurityDescriptor.fromAttribute(attrs);
+        FileChannel fc;
+        try {
+            fc = WindowsChannelFactory
+                .newFileChannel(getPathForWin32Calls(),
+                                getPathForPermissionCheck(),
+                                opts,
+                                sd.address());
+            return Channels.newOutputStream(fc);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(this);
+            return null;  // keep compiler happy
+        } finally {
+            sd.release();
+        }
+    }
+
+    @Override
+    public boolean isSameFile(FileRef 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 drive-relative target");
+        }
+
+        /*
+         * Windows treates symbolic links to directories differently than it
+         * does to other file types. For that reason we check if the exists and
+         * is a directory.
+         */
+        int flags = 0;
+        WindowsPath resolvedTarget =
+            WindowsPath.createFromNormalizedPath(getFileSystem(), resolve(target).path);
+        try {
+            if (WindowsFileAttributes.get(resolvedTarget, true).isDirectory())
+                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);
+    }
+
+    @Override
+    public WindowsPath toAbsolutePath() {
+        if (isAbsolute())
+            return this;
+
+        // permission check as per spec
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPropertyAccess("user.dir");
+        }
+
+        try {
+            return createFromNormalizedPath(getFileSystem(), getAbsolutePath());
+        } catch (WindowsException x) {
+            throw new IOError(new IOException(x.getMessage()));
+        }
+    }
+
+    @Override
+    public WindowsPath toRealPath(boolean resolveLinks) throws IOException {
+        checkRead();
+        String rp = WindowsLinkSupport.getRealPath(this, resolveLinks);
+        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,
+                             WatchEvent.Modifier... modifiers)
+        throws IOException
+    {
+        if (watcher == null)
+            throw new NullPointerException();
+        if (!(watcher instanceof WindowsWatchService))
+            throw new ProviderMismatchException();
+
+        // When a security manager is set then we need to make a defensive
+        // copy of the modifiers and check for the Windows specific FILE_TREE
+        // modifier. When the modifier is present then check that permission
+        // has been granted recursively.
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            boolean watchSubtree = false;
+            final int ml = modifiers.length;
+            if (ml > 0) {
+                modifiers = Arrays.copyOf(modifiers, ml);
+                int i=0;
+                while (i < ml) {
+                    if (modifiers[i++] == ExtendedWatchEventModifier.FILE_TREE) {
+                        watchSubtree = true;
+                        break;
+                    }
+                }
+            }
+            String s = getPathForPermissionCheck();
+            sm.checkRead(s);
+            if (watchSubtree)
+                sm.checkRead(s + "\\-");
+        }
+
+        return ((WindowsWatchService)watcher).register(this, events, modifiers);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsPathParser.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.InvalidPathException;
+
+/**
+ * A parser of Windows path strings
+ */
+
+class WindowsPathParser {
+    private WindowsPathParser() { }
+
+    /**
+     * The result of a parse operation
+     */
+    static class Result {
+        private final WindowsPathType type;
+        private final String root;
+        private final String path;
+
+        Result(WindowsPathType type, String root, String path) {
+            this.type = type;
+            this.root = root;
+            this.path = path;
+        }
+
+        /**
+         * The path type
+         */
+        WindowsPathType type() {
+            return type;
+        }
+
+        /**
+         * The root component
+         */
+        String root() {
+            return root;
+        }
+
+        /**
+         * The normalized path (includes root)
+         */
+        String path() {
+            return path;
+        }
+    }
+
+    /**
+     * 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);
+    }
+
+    /**
+     * Parses the given input as a Windows path where it is known that the
+     * path is already normalized.
+     */
+    static Result parseNormalizedPath(String input) {
+        return parse(input, false);
+    }
+
+    /**
+     * Parses the given input as a Windows path.
+     *
+     * @param   requireToNormalize
+     *          Indicates if the path requires to be normalized
+     */
+    private static Result parse(String input, boolean requireToNormalize) {
+        String root = "";
+        WindowsPathType type = null;
+
+        int len = input.length();
+        int off = 0;
+        if (len > 1) {
+            char c0 = input.charAt(0);
+            char c1 = input.charAt(1);
+            char c = 0;
+            int next = 2;
+            if (isSlash(c0) && isSlash(c1)) {
+                // UNC: We keep the first two slash, collapse all the
+                // following, then take the hostname and share name out,
+                // meanwhile collapsing all the redundant slashes.
+                type = WindowsPathType.UNC;
+                off = nextNonSlash(input, next, len);
+                next = nextSlash(input, off, len);
+                if (off == next)
+                    throw new InvalidPathException(input, "UNC path is missing hostname");
+                String host = input.substring(off, next);  //host
+                off = nextNonSlash(input, next, len);
+                next = nextSlash(input, off, len);
+                if (off == next)
+                    throw new InvalidPathException(input, "UNC path is missing sharename");
+                root = "\\\\" + host + "\\" + input.substring(off, next) + "\\";
+                off = next;
+            } else {
+                if (isLetter(c0) && c1 == ':') {
+                    root = input.substring(0, 2);
+                    if (len > 2 && isSlash(input.charAt(2))) {
+                        off = 3;
+                        root += "\\";
+                        type = WindowsPathType.ABSOLUTE;
+                    } else {
+                        off = 2;
+                        type = WindowsPathType.DRIVE_RELATIVE;
+                    }
+                }
+            }
+        }
+        if (off == 0) {
+            if (isSlash(input.charAt(0))) {
+                type = WindowsPathType.DIRECTORY_RELATIVE;
+                root = "\\";
+            } else {
+                type = WindowsPathType.RELATIVE;
+            }
+        }
+
+        if (requireToNormalize) {
+            StringBuilder sb = new StringBuilder(input.length());
+            sb.append(root);
+            return new Result(type, root, normalize(sb, input, off));
+        } else {
+            return new Result(type, root, input);
+        }
+    }
+
+    /**
+     * Remove redundant slashes from the rest of the path, forcing all slashes
+     * into the preferred slash.
+    */
+    private static String normalize(StringBuilder sb, String path, int off) {
+        int len = path.length();
+        off = nextNonSlash(path, off, len);
+        int start = off;
+        char lastC = 0;
+        while (off < len) {
+            char c = path.charAt(off);
+            if (isSlash(c)) {
+                if (lastC == ' ')
+                    throw new InvalidPathException(path,
+                                                   "Trailing char <" + lastC + ">",
+                                                   off - 1);
+                sb.append(path, start, off);
+                off = nextNonSlash(path, off, len);
+                if (off != len)   //no slash at the end of normalized path
+                    sb.append('\\');
+                start = off;
+            } else {
+                if (isInvalidPathChar(c))
+                    throw new InvalidPathException(path,
+                                                   "Illegal char <" + c + ">",
+                                                   off);
+                lastC = c;
+                off++;
+            }
+        }
+        if (start != off) {
+            if (lastC == ' ')
+                throw new InvalidPathException(path,
+                                               "Trailing char <" + lastC + ">",
+                                               off - 1);
+            sb.append(path, start, off);
+        }
+        return sb.toString();
+    }
+
+    private static final boolean isSlash(char c) {
+        return (c == '\\') || (c == '/');
+    }
+
+    private static final int nextNonSlash(String path, int off, int end) {
+        while (off < end && isSlash(path.charAt(off))) { off++; }
+        return off;
+    }
+
+    private static final int nextSlash(String path, int off, int end) {
+        char c;
+        while (off < end && !isSlash(c=path.charAt(off))) {
+            if (isInvalidPathChar(c))
+                throw new InvalidPathException(path,
+                                               "Illegal character [" + c + "] in path",
+                                               off);
+            off++;
+        }
+        return off;
+    }
+
+    private static final boolean isLetter(char c) {
+        return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
+    }
+
+    // Reserved characters for window path name
+    private static final String reservedChars = "<>:\"|?*";
+    private static final boolean isInvalidPathChar(char ch) {
+        return ch < '\u0020' || reservedChars.indexOf(ch) != -1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsPathType.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+/**
+ * A type safe enum of Windows path types.
+ */
+
+enum WindowsPathType {
+    ABSOLUTE,                   //  C:\foo
+    UNC,                        //  \\server\share\foo
+    RELATIVE,                   //  foo
+    DIRECTORY_RELATIVE,         //  \foo
+    DRIVE_RELATIVE              //  C:foo
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsSecurity.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import static sun.nio.fs.WindowsNativeDispatcher.*;
+import static sun.nio.fs.WindowsConstants.*;
+
+/**
+ * Security related utility methods.
+ */
+
+class WindowsSecurity {
+    private WindowsSecurity() { }
+
+    // opens process token for given access
+    private static long openProcessToken(int access) {
+        try {
+            return OpenProcessToken(GetCurrentProcess(), access);
+        } catch (WindowsException x) {
+            return 0L;
+        }
+    }
+
+    /**
+     * Returns the access token for this process with TOKEN_DUPLICATE access
+     */
+    static final long processTokenWithDuplicateAccess =
+        openProcessToken(TOKEN_DUPLICATE);
+
+    /**
+     * Returns the access token for this process with TOKEN_QUERY access
+     */
+    static final long processTokenWithQueryAccess =
+        openProcessToken(TOKEN_QUERY);
+
+    /**
+     * Returned by enablePrivilege when code may require a given privilege.
+     * The drop method should be invoked after the operation completes so as
+     * to revert the privilege.
+     */
+    static interface Privilege {
+        void drop();
+    }
+
+    /**
+     * Attempts to enable the given privilege for this method.
+     */
+    static Privilege enablePrivilege(String priv) {
+        final long pLuid;
+        try {
+            pLuid = LookupPrivilegeValue(priv);
+        } catch (WindowsException x) {
+            // indicates bug in caller
+            throw new AssertionError(x);
+        }
+
+        long hToken = 0L;
+        boolean impersontating = false;
+        boolean elevated = false;
+        try {
+            hToken = OpenThreadToken(GetCurrentThread(),
+                                     TOKEN_ADJUST_PRIVILEGES, false);
+            if (hToken == 0L && processTokenWithDuplicateAccess != 0L) {
+                hToken = DuplicateTokenEx(processTokenWithDuplicateAccess,
+                    (TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE));
+                SetThreadToken(0L, hToken);
+                impersontating = true;
+            }
+
+            if (hToken != 0L) {
+                AdjustTokenPrivileges(hToken, pLuid, SE_PRIVILEGE_ENABLED);
+                elevated = true;
+            }
+        } catch (WindowsException x) {
+            // nothing to do, privilege not enabled
+        }
+
+        final long token = hToken;
+        final boolean stopImpersontating = impersontating;
+        final boolean needToRevert = elevated;
+
+        return new Privilege() {
+            @Override
+            public void drop() {
+                try {
+                    if (stopImpersontating) {
+                        SetThreadToken(0L, 0L);
+                    } else {
+                        if (needToRevert) {
+                            AdjustTokenPrivileges(token, pLuid, 0);
+                        }
+                    }
+                } catch (WindowsException x) {
+                    // should not happen
+                    throw new AssertionError(x);
+                }
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.ProviderMismatchException;
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.io.IOException;
+import sun.misc.Unsafe;
+
+import static sun.nio.fs.WindowsNativeDispatcher.*;
+import static sun.nio.fs.WindowsConstants.*;
+
+/**
+ * A SecurityDescriptor for use when setting a file's ACL or creating a file
+ * with an initial ACL.
+ */
+
+class WindowsSecurityDescriptor {
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    /**
+     * typedef struct _ACL {
+     *     BYTE  AclRevision;
+     *     BYTE  Sbz1;
+     *     WORD  AclSize;
+     *     WORD  AceCount;
+     *     WORD  Sbz2;
+     * } ACL;
+     *
+     * typedef struct _ACE_HEADER {
+     *     BYTE AceType;
+     *     BYTE AceFlags;
+     *     WORD AceSize;
+     * } ACE_HEADER;
+     *
+     * typedef struct _ACCESS_ALLOWED_ACE {
+     *     ACE_HEADER Header;
+     *     ACCESS_MASK Mask;
+     *     DWORD SidStart;
+     * } ACCESS_ALLOWED_ACE;
+     *
+     * typedef struct _ACCESS_DENIED_ACE {
+     *     ACE_HEADER Header;
+     *     ACCESS_MASK Mask;
+     *     DWORD SidStart;
+     * } ACCESS_DENIED_ACE;
+     *
+     * typedef struct _SECURITY_DESCRIPTOR {
+     *     BYTE  Revision;
+     *     BYTE  Sbz1;
+     *     SECURITY_DESCRIPTOR_CONTROL Control;
+     *     PSID Owner;
+     *     PSID Group;
+     *     PACL Sacl;
+     *     PACL Dacl;
+     * } SECURITY_DESCRIPTOR;
+     */
+    private static final short SIZEOF_ACL                   = 8;
+    private static final short SIZEOF_ACCESS_ALLOWED_ACE    = 12;
+    private static final short SIZEOF_ACCESS_DENIED_ACE     = 12;
+    private static final short SIZEOF_SECURITY_DESCRIPTOR   = 20;
+
+    private static final short OFFSETOF_TYPE                = 0;
+    private static final short OFFSETOF_FLAGS               = 1;
+    private static final short OFFSETOF_ACCESS_MASK         = 4;
+    private static final short OFFSETOF_SID                 = 8;
+
+    // null security descriptor
+    private static final WindowsSecurityDescriptor NULL_DESCRIPTOR =
+        new WindowsSecurityDescriptor();
+
+    // native resources
+    private final List<Long> sidList;
+    private final NativeBuffer aclBuffer, sdBuffer;
+
+    /**
+     * Creates the "null" SecurityDescriptor
+     */
+    private WindowsSecurityDescriptor() {
+        this.sidList = null;
+        this.aclBuffer = null;
+        this.sdBuffer = null;
+    }
+
+    /**
+     * Creates a SecurityDescriptor from the given ACL
+     */
+    private WindowsSecurityDescriptor(List<AclEntry> acl) throws IOException {
+        boolean initialized = false;
+
+        // SECURITY: need to copy list in case size changes during processing
+        acl = new ArrayList<AclEntry>(acl);
+
+        // list of SIDs
+        sidList = new ArrayList<Long>(acl.size());
+        try {
+            // initial size of ACL
+            int size = SIZEOF_ACL;
+
+            // get the SID for each entry
+            for (AclEntry entry: acl) {
+                UserPrincipal user = entry.principal();
+                if (!(user instanceof WindowsUserPrincipals.User))
+                    throw new ProviderMismatchException();
+                String sidString = ((WindowsUserPrincipals.User)user).sidString();
+                try {
+                    long pSid = ConvertStringSidToSid(sidString);
+                    sidList.add(pSid);
+
+                    // increase size to allow for entry
+                    size += GetLengthSid(pSid) +
+                        Math.max(SIZEOF_ACCESS_ALLOWED_ACE, SIZEOF_ACCESS_DENIED_ACE);
+
+                } catch (WindowsException x) {
+                    throw new IOException("Failed to get SID for " + user.getName()
+                        + ": " + x.errorString());
+                }
+            }
+
+            // allocate memory for the ACL
+            aclBuffer = NativeBuffers.getNativeBuffer(size);
+            sdBuffer = NativeBuffers.getNativeBuffer(SIZEOF_SECURITY_DESCRIPTOR);
+
+            InitializeAcl(aclBuffer.address(), size);
+
+            // Add entry ACE to the ACL
+            int i = 0;
+            while (i < acl.size()) {
+                AclEntry entry = acl.get(i);
+                long pSid = sidList.get(i);
+                try {
+                    encode(entry, pSid, aclBuffer.address());
+                } catch (WindowsException x) {
+                    throw new IOException("Failed to encode ACE: " +
+                        x.errorString());
+                }
+                i++;
+            }
+
+            // initialize security descriptor and set DACL
+            InitializeSecurityDescriptor(sdBuffer.address());
+            SetSecurityDescriptorDacl(sdBuffer.address(), aclBuffer.address());
+            initialized = true;
+        } catch (WindowsException x) {
+            throw new IOException(x.getMessage());
+        } finally {
+            // release resources if not completely initialized
+            if (!initialized)
+                release();
+        }
+    }
+
+    /**
+     * Releases memory associated with SecurityDescriptor
+     */
+    void release() {
+        if (sdBuffer != null)
+            sdBuffer.release();
+        if (aclBuffer != null)
+            aclBuffer.release();
+        if (sidList != null) {
+            // release memory for SIDs
+            for (Long sid: sidList) {
+                LocalFree(sid);
+            }
+        }
+    }
+
+    /**
+     * Returns address of SecurityDescriptor
+     */
+    long address() {
+        return (sdBuffer == null) ? 0L : sdBuffer.address();
+    }
+
+    // decode Windows ACE to NFSv4 AclEntry
+    private static AclEntry decode(long aceAddress)
+        throws IOException
+    {
+        // map type
+        byte aceType = unsafe.getByte(aceAddress + OFFSETOF_TYPE);
+        if (aceType != ACCESS_ALLOWED_ACE_TYPE && aceType != ACCESS_DENIED_ACE_TYPE)
+            return null;
+        AclEntryType type;
+        if (aceType == ACCESS_ALLOWED_ACE_TYPE) {
+            type = AclEntryType.ALLOW;
+        } else {
+            type = AclEntryType.DENY;
+        }
+
+        // map flags
+        byte aceFlags = unsafe.getByte(aceAddress + OFFSETOF_FLAGS);
+        Set<AclEntryFlag> flags = new HashSet<AclEntryFlag>();
+        if ((aceFlags & OBJECT_INHERIT_ACE) != 0)
+            flags.add(AclEntryFlag.FILE_INHERIT);
+        if ((aceFlags & CONTAINER_INHERIT_ACE) != 0)
+            flags.add(AclEntryFlag.DIRECTORY_INHERIT);
+        if ((aceFlags & NO_PROPAGATE_INHERIT_ACE) != 0)
+            flags.add(AclEntryFlag.NO_PROPAGATE_INHERIT);
+        if ((aceFlags & INHERIT_ONLY_ACE) != 0)
+            flags.add(AclEntryFlag.INHERIT_ONLY);
+
+        // map access mask
+        int mask = unsafe.getInt(aceAddress + OFFSETOF_ACCESS_MASK);
+        Set<AclEntryPermission> perms = new HashSet<AclEntryPermission>();
+        if ((mask & FILE_READ_DATA) > 0)
+            perms.add(AclEntryPermission.READ_DATA);
+        if ((mask & FILE_WRITE_DATA) > 0)
+            perms.add(AclEntryPermission.WRITE_DATA);
+        if ((mask & FILE_APPEND_DATA ) > 0)
+            perms.add(AclEntryPermission.APPEND_DATA);
+        if ((mask & FILE_READ_EA) > 0)
+            perms.add(AclEntryPermission.READ_NAMED_ATTRS);
+        if ((mask & FILE_WRITE_EA) > 0)
+            perms.add(AclEntryPermission.WRITE_NAMED_ATTRS);
+        if ((mask & FILE_EXECUTE) > 0)
+            perms.add(AclEntryPermission.EXECUTE);
+        if ((mask & FILE_DELETE_CHILD ) > 0)
+            perms.add(AclEntryPermission.DELETE_CHILD);
+        if ((mask & FILE_READ_ATTRIBUTES) > 0)
+            perms.add(AclEntryPermission.READ_ATTRIBUTES);
+        if ((mask & FILE_WRITE_ATTRIBUTES) > 0)
+            perms.add(AclEntryPermission.WRITE_ATTRIBUTES);
+        if ((mask & DELETE) > 0)
+            perms.add(AclEntryPermission.DELETE);
+        if ((mask & READ_CONTROL) > 0)
+            perms.add(AclEntryPermission.READ_ACL);
+        if ((mask & WRITE_DAC) > 0)
+            perms.add(AclEntryPermission.WRITE_ACL);
+        if ((mask & WRITE_OWNER) > 0)
+            perms.add(AclEntryPermission.WRITE_OWNER);
+        if ((mask & SYNCHRONIZE) > 0)
+            perms.add(AclEntryPermission.SYNCHRONIZE);
+
+        // lookup SID to create UserPrincipal
+        long sidAddress = aceAddress + OFFSETOF_SID;
+        UserPrincipal user = WindowsUserPrincipals.fromSid(sidAddress);
+
+        return AclEntry.newBuilder()
+            .setType(type)
+            .setPrincipal(user)
+            .setFlags(flags).setPermissions(perms).build();
+    }
+
+    // encode NFSv4 AclEntry as Windows ACE to given ACL
+    private static void encode(AclEntry ace, long sidAddress, long aclAddress)
+        throws WindowsException
+    {
+        // ignore non-allow/deny entries for now
+        if (ace.type() != AclEntryType.ALLOW && ace.type() != AclEntryType.DENY)
+            return;
+        boolean allow = (ace.type() == AclEntryType.ALLOW);
+
+        // map access mask
+        Set<AclEntryPermission> aceMask = ace.permissions();
+        int mask = 0;
+        if (aceMask.contains(AclEntryPermission.READ_DATA))
+            mask |= FILE_READ_DATA;
+        if (aceMask.contains(AclEntryPermission.WRITE_DATA))
+            mask |= FILE_WRITE_DATA;
+        if (aceMask.contains(AclEntryPermission.APPEND_DATA))
+            mask |= FILE_APPEND_DATA;
+        if (aceMask.contains(AclEntryPermission.READ_NAMED_ATTRS))
+            mask |= FILE_READ_EA;
+        if (aceMask.contains(AclEntryPermission.WRITE_NAMED_ATTRS))
+            mask |= FILE_WRITE_EA;
+        if (aceMask.contains(AclEntryPermission.EXECUTE))
+            mask |= FILE_EXECUTE;
+        if (aceMask.contains(AclEntryPermission.DELETE_CHILD))
+            mask |= FILE_DELETE_CHILD;
+        if (aceMask.contains(AclEntryPermission.READ_ATTRIBUTES))
+            mask |= FILE_READ_ATTRIBUTES;
+        if (aceMask.contains(AclEntryPermission.WRITE_ATTRIBUTES))
+            mask |= FILE_WRITE_ATTRIBUTES;
+        if (aceMask.contains(AclEntryPermission.DELETE))
+            mask |= DELETE;
+        if (aceMask.contains(AclEntryPermission.READ_ACL))
+            mask |= READ_CONTROL;
+        if (aceMask.contains(AclEntryPermission.WRITE_ACL))
+            mask |= WRITE_DAC;
+        if (aceMask.contains(AclEntryPermission.WRITE_OWNER))
+            mask |= WRITE_OWNER;
+        if (aceMask.contains(AclEntryPermission.SYNCHRONIZE))
+            mask |= SYNCHRONIZE;
+
+        // map flags
+        Set<AclEntryFlag> aceFlags = ace.flags();
+        byte flags = 0;
+        if (aceFlags.contains(AclEntryFlag.FILE_INHERIT))
+            flags |= OBJECT_INHERIT_ACE;
+        if (aceFlags.contains(AclEntryFlag.DIRECTORY_INHERIT))
+            flags |= CONTAINER_INHERIT_ACE;
+        if (aceFlags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT))
+            flags |= NO_PROPAGATE_INHERIT_ACE;
+        if (aceFlags.contains(AclEntryFlag.INHERIT_ONLY))
+            flags |= INHERIT_ONLY_ACE;
+
+        if (allow) {
+            AddAccessAllowedAceEx(aclAddress, flags, mask, sidAddress);
+        } else {
+            AddAccessDeniedAceEx(aclAddress, flags, mask, sidAddress);
+        }
+    }
+
+    /**
+     * Creates a security descriptor with a DACL representing the given ACL.
+     */
+    static WindowsSecurityDescriptor create(List<AclEntry> acl)
+        throws IOException
+    {
+        return new WindowsSecurityDescriptor(acl);
+    }
+
+    /**
+     * Processes the array of attributes looking for the attribute "acl:acl".
+     * Returns security descriptor representing the ACL or the "null" security
+     * descriptor if the attribute is not in the array.
+     */
+    @SuppressWarnings("unchecked")
+    static WindowsSecurityDescriptor fromAttribute(FileAttribute<?>... attrs)
+        throws IOException
+    {
+        WindowsSecurityDescriptor sd = NULL_DESCRIPTOR;
+        for (FileAttribute<?> attr: attrs) {
+            // if more than one ACL specified then last one wins
+            if (sd != NULL_DESCRIPTOR)
+                sd.release();
+            if (attr == null)
+                throw new NullPointerException();
+            if (attr.name().equals("acl:acl")) {
+                List<AclEntry> acl = (List<AclEntry>)attr.value();
+                sd = new WindowsSecurityDescriptor(acl);
+            } else {
+                throw new UnsupportedOperationException("'" + attr.name() +
+                   "' not supported as initial attribute");
+            }
+        }
+        return sd;
+    }
+
+    /**
+     * Extracts DACL from security descriptor.
+     */
+    static List<AclEntry> getAcl(long pSecurityDescriptor) throws IOException {
+        // get address of DACL
+        long aclAddress = GetSecurityDescriptorDacl(pSecurityDescriptor);
+
+        // get ACE count
+        int aceCount = 0;
+        if (aclAddress == 0L) {
+            // no ACEs
+            aceCount = 0;
+        } else {
+            AclInformation aclInfo = GetAclInformation(aclAddress);
+            aceCount = aclInfo.aceCount();
+        }
+        ArrayList<AclEntry> result = new ArrayList<AclEntry>(aceCount);
+
+        // decode each of the ACEs to AclEntry objects
+        for (int i=0; i<aceCount; i++) {
+            long aceAddress = GetAce(aclAddress, i);
+            AclEntry entry = decode(aceAddress);
+            if (entry != null)
+                result.add(entry);
+        }
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsUriSupport.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * Utility methods to convert between Path and URIs.
+ */
+
+class WindowsUriSupport {
+    private WindowsUriSupport() {
+    }
+
+    // suffix for IPv6 literal address
+    private static final String IPV6_LITERAL_SUFFIX = ".ipv6-literal.net";
+
+    /**
+     * Returns URI to represent the given (absolute) path
+     */
+    private static URI toUri(String path, boolean isUnc, boolean addSlash) {
+        String uriHost;
+        String uriPath;
+
+        if (isUnc) {
+            int slash = path.indexOf('\\', 2);
+            uriHost = path.substring(2, slash);
+            uriPath = path.substring(slash).replace('\\', '/');
+
+            // handle IPv6 literal addresses
+            // 1. drop .ivp6-literal.net
+            // 2. replace "-" with ":"
+            // 3. replace "s" with "%" (zone/scopeID delimiter)
+            if (uriHost.endsWith(IPV6_LITERAL_SUFFIX)) {
+                uriHost = uriHost
+                    .substring(0, uriHost.length() - IPV6_LITERAL_SUFFIX.length())
+                    .replace('-', ':')
+                    .replace('s', '%');
+            }
+        } else {
+            uriHost = "";
+            uriPath = "/" + path.replace('\\', '/');
+        }
+
+        // append slash if known to be directory
+        if (addSlash)
+            uriPath += "/";
+
+        // return file:///C:/My%20Documents or file://server/share/foo
+        try {
+            return new URI("file", uriHost, uriPath, null);
+        } catch (URISyntaxException x) {
+            if (!isUnc)
+                throw new AssertionError(x);
+        }
+
+        // if we get here it means we've got a UNC with reserved characters
+        // in the server name. The authority component cannot contain escaped
+        // octets so fallback to encoding the server name into the URI path
+        // component.
+        uriPath = "//" + path.replace('\\', '/');
+        if (addSlash)
+            uriPath += "/";
+        try {
+            return new URI("file", null, uriPath, null);
+        } catch (URISyntaxException x) {
+            throw new AssertionError(x);
+        }
+    }
+
+    /**
+     * Converts given Path to a URI
+     */
+    static URI toUri(WindowsPath path) {
+        path = path.toAbsolutePath();
+        String s = path.toString();
+
+        // trailing slash will be added if file is a directory. Skip check if
+        // already have trailing space
+        boolean addSlash = false;
+        if (!s.endsWith("\\")) {
+            try {
+                 addSlash = WindowsFileAttributes.get(path, true).isDirectory();
+            } catch (WindowsException x) {
+            }
+        }
+
+        return toUri(s, path.isUnc(), addSlash);
+    }
+
+    /**
+     * Converts given URI to a Path
+     */
+    static WindowsPath fromUri(WindowsFileSystem fs, URI uri) {
+        if (!uri.isAbsolute())
+            throw new IllegalArgumentException("URI is not absolute");
+        if (uri.isOpaque())
+            throw new IllegalArgumentException("URI is not hierarchical");
+        String scheme = uri.getScheme();
+        if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
+            throw new IllegalArgumentException("URI scheme is not \"file\"");
+        if (uri.getFragment() != null)
+            throw new IllegalArgumentException("URI has a fragment component");
+        if (uri.getQuery() != null)
+            throw new IllegalArgumentException("URI has a query component");
+        String path = uri.getPath();
+        if (path.equals(""))
+            throw new IllegalArgumentException("URI path component is empty");
+
+        // UNC
+        String auth = uri.getAuthority();
+        if (auth != null && !auth.equals("")) {
+            String host = uri.getHost();
+            if (host == null)
+                throw new IllegalArgumentException("URI authority component has undefined host");
+            if (uri.getUserInfo() != null)
+                throw new IllegalArgumentException("URI authority component has user-info");
+            if (uri.getPort() != -1)
+                throw new IllegalArgumentException("URI authority component has port number");
+
+            // IPv6 literal
+            // 1. drop enclosing brackets
+            // 2. replace ":" with "-"
+            // 3. replace "%" with "s" (zone/scopeID delimiter)
+            // 4. Append .ivp6-literal.net
+            if (host.startsWith("[")) {
+                host = host.substring(1, host.length()-1)
+                           .replace(':', '-')
+                           .replace('%', 's');
+                host += IPV6_LITERAL_SUFFIX;
+            }
+
+            // reconstitute the UNC
+            path = "\\\\" + host + path;
+        } else {
+            if ((path.length() > 2) && (path.charAt(2) == ':')) {
+                // "/c:/foo" --> "c:/foo"
+                path = path.substring(1);
+            }
+        }
+        return WindowsPath.parse(fs, path);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsUserDefinedFileAttributeView.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import static java.nio.file.StandardOpenOption.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.io.IOException;
+import java.util.*;
+import sun.misc.Unsafe;
+
+import static sun.nio.fs.WindowsNativeDispatcher.*;
+import static sun.nio.fs.WindowsConstants.*;
+
+/**
+ * Windows emulation of NamedAttributeView using Alternative Data Streams
+ */
+
+class WindowsUserDefinedFileAttributeView
+    extends AbstractUserDefinedFileAttributeView
+{
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    // syntax to address named streams
+    private String join(String file, String name) {
+        if (name == null)
+            throw new NullPointerException("'name' is null");
+        return file + ":" + name;
+    }
+    private String join(WindowsPath file, String name) throws WindowsException {
+        return join(file.getPathForWin32Calls(), name);
+    }
+
+    private final WindowsPath file;
+    private final boolean followLinks;
+
+    WindowsUserDefinedFileAttributeView(WindowsPath file, boolean followLinks) {
+        this.file = file;
+        this.followLinks = followLinks;
+    }
+
+    // enumerates the file streams using FindFirstStream/FindNextStream APIs.
+    private List<String> listUsingStreamEnumeration() throws IOException {
+        List<String> list = new ArrayList<String>();
+        try {
+            FirstStream first = FindFirstStream(file.getPathForWin32Calls());
+            if (first != null) {
+                long handle = first.handle();
+                try {
+                    // first stream is always ::$DATA for files
+                    String name = first.name();
+                    if (!name.equals("::$DATA")) {
+                        String[] segs = name.split(":");
+                        list.add(segs[1]);
+                    }
+                    while ((name = FindNextStream(handle)) != null) {
+                        String[] segs = name.split(":");
+                        list.add(segs[1]);
+                    }
+                } finally {
+                    FindClose(handle);
+                }
+            }
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(file);
+        }
+        return Collections.unmodifiableList(list);
+    }
+
+    // enumerates the file streams by reading the stream headers using
+    // BackupRead
+    private List<String> listUsingBackupRead() throws IOException {
+        long handle = -1L;
+        try {
+            int flags = FILE_FLAG_BACKUP_SEMANTICS;
+            if (!followLinks && file.getFileSystem().supportsLinks())
+                flags |= FILE_FLAG_OPEN_REPARSE_POINT;
+
+            handle = CreateFile(file.getPathForWin32Calls(),
+                                GENERIC_READ,
+                                FILE_SHARE_READ, // no write as we depend on file size
+                                OPEN_EXISTING,
+                                flags);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(file);
+        }
+
+        // buffer to read stream header and stream name.
+        final int BUFFER_SIZE = 4096;
+        NativeBuffer buffer = null;
+
+        // result with names of alternative data streams
+        final List<String> list = new ArrayList<String>();
+
+        try {
+            buffer = NativeBuffers.getNativeBuffer(BUFFER_SIZE);
+            long address = buffer.address();
+
+            /**
+             * typedef struct _WIN32_STREAM_ID {
+             *     DWORD dwStreamId;
+             *     DWORD dwStreamAttributes;
+             *     LARGE_INTEGER Size;
+             *     DWORD dwStreamNameSize;
+             *     WCHAR cStreamName[ANYSIZE_ARRAY];
+             * } WIN32_STREAM_ID;
+             */
+            final int SIZEOF_STREAM_HEADER      = 20;
+            final int OFFSETOF_STREAM_ID        = 0;
+            final int OFFSETOF_STREAM_SIZE      = 8;
+            final int OFFSETOF_STREAM_NAME_SIZE = 16;
+
+            long context = 0L;
+            try {
+                for (;;) {
+                    // read stream header
+                    BackupResult result = BackupRead(handle, address,
+                       SIZEOF_STREAM_HEADER, false, context);
+                    context = result.context();
+                    if (result.bytesTransferred() == 0)
+                        break;
+
+                    int streamId = unsafe.getInt(address + OFFSETOF_STREAM_ID);
+                    long streamSize = unsafe.getLong(address + OFFSETOF_STREAM_SIZE);
+                    int nameSize = unsafe.getInt(address + OFFSETOF_STREAM_NAME_SIZE);
+
+                    // read stream name
+                    if (nameSize > 0) {
+                        result = BackupRead(handle, address, nameSize, false, context);
+                        if (result.bytesTransferred() != nameSize)
+                            break;
+                    }
+
+                    // check for alternative data stream
+                    if (streamId == BACKUP_ALTERNATE_DATA) {
+                        char[] nameAsArray = new char[nameSize/2];
+                        unsafe.copyMemory(null, address, nameAsArray,
+                            Unsafe.ARRAY_CHAR_BASE_OFFSET, nameSize);
+
+                        String[] segs = new String(nameAsArray).split(":");
+                        if (segs.length == 3)
+                            list.add(segs[1]);
+                    }
+
+                    // sparse blocks not currently handled as documentation
+                    // is not sufficient on how the spase block can be skipped.
+                    if (streamId == BACKUP_SPARSE_BLOCK) {
+                        throw new IOException("Spare blocks not handled");
+                    }
+
+                    // seek to end of stream
+                    if (streamSize > 0L) {
+                        BackupSeek(handle, streamSize, context);
+                    }
+                }
+            } catch (WindowsException x) {
+                // failed to read or seek
+                throw new IOException(x.errorString());
+            } finally {
+                // release context
+                if (context != 0L) {
+                   try {
+                       BackupRead(handle, 0L, 0, true, context);
+                   } catch (WindowsException ignore) { }
+                }
+            }
+        } finally {
+            if (buffer != null)
+                buffer.release();
+            CloseHandle(handle);
+        }
+        return Collections.unmodifiableList(list);
+    }
+
+    @Override
+    public List<String> list() throws IOException  {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), true, false);
+        // use stream APIs on Windwos Server 2003 and newer
+        if (file.getFileSystem().supportsStreamEnumeration()) {
+            return listUsingStreamEnumeration();
+        } else {
+            return listUsingBackupRead();
+        }
+    }
+
+    @Override
+    public int size(String name) throws IOException  {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), true, false);
+
+        // wrap with channel
+        FileChannel fc = null;
+        try {
+            Set<OpenOption> opts = new HashSet<OpenOption>();
+            opts.add(READ);
+            if (!followLinks)
+                opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);
+            fc = WindowsChannelFactory
+                .newFileChannel(join(file, name), null, opts, 0L);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));
+        }
+        try {
+            long size = fc.size();
+            if (size > Integer.MAX_VALUE)
+                throw new ArithmeticException("Stream too large");
+            return (int)size;
+        } finally {
+            fc.close();
+        }
+    }
+
+    @Override
+    public int read(String name, ByteBuffer dst) throws IOException {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), true, false);
+
+        // wrap with channel
+        FileChannel fc = null;
+        try {
+            Set<OpenOption> opts = new HashSet<OpenOption>();
+            opts.add(READ);
+            if (!followLinks)
+                opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);
+            fc = WindowsChannelFactory
+                .newFileChannel(join(file, name), null, opts, 0L);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));
+        }
+
+        // read to EOF (nothing we can do if I/O error occurs)
+        try {
+            if (fc.size() > dst.remaining())
+                throw new IOException("Stream too large");
+            int total = 0;
+            while (dst.hasRemaining()) {
+                int n = fc.read(dst);
+                if (n < 0)
+                    break;
+                total += n;
+            }
+            return total;
+        } finally {
+            fc.close();
+        }
+    }
+
+    @Override
+    public int write(String name, ByteBuffer src) throws IOException {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), false, true);
+
+        /**
+         * Creating a named stream will cause the unnamed stream to be created
+         * if it doesn't already exist. To avoid this we open the unnamed stream
+         * for reading and hope it isn't deleted/moved while we create or
+         * replace the named stream. Opening the file without sharing options
+         * may cause sharing violations with other programs that are accessing
+         * the unnamed stream.
+         */
+        long handle = -1L;
+        try {
+            int flags = FILE_FLAG_BACKUP_SEMANTICS;
+            if (!followLinks)
+                flags |= FILE_FLAG_OPEN_REPARSE_POINT;
+
+            handle = CreateFile(file.getPathForWin32Calls(),
+                                GENERIC_READ,
+                                (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
+                                OPEN_EXISTING,
+                                flags);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(file);
+        }
+        try {
+            Set<OpenOption> opts = new HashSet<OpenOption>();
+            if (!followLinks)
+                opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);
+            opts.add(CREATE);
+            opts.add(WRITE);
+            opts.add(StandardOpenOption.TRUNCATE_EXISTING);
+            FileChannel named = null;
+            try {
+                named = WindowsChannelFactory
+                    .newFileChannel(join(file, name), null, opts, 0L);
+            } catch (WindowsException x) {
+                x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));
+            }
+            // write value (nothing we can do if I/O error occurs)
+            try {
+                int rem = src.remaining();
+                while (src.hasRemaining()) {
+                    named.write(src);
+                }
+                return rem;
+            } finally {
+                named.close();
+            }
+        } finally {
+            CloseHandle(handle);
+        }
+    }
+
+    @Override
+    public void delete(String name) throws IOException {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), false, true);
+
+        String path = WindowsLinkSupport.getFinalPath(file, followLinks);
+        String toDelete = join(path, name);
+        try {
+            DeleteFile(toDelete);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(toDelete);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsUserPrincipals.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.fs;
+
+import java.nio.file.attribute.*;
+import java.io.IOException;
+
+import static sun.nio.fs.WindowsConstants.*;
+import static sun.nio.fs.WindowsNativeDispatcher.*;
+
+class WindowsUserPrincipals {
+    private WindowsUserPrincipals() { }
+
+    static class User implements UserPrincipal {
+        // String representation of SID
+        private final String sidString;
+
+        // SID type
+        private final int sidType;
+
+        // Account name (if available) or SID
+        private final String accountName;
+
+        User(String sidString, int sidType, String accountName) {
+            this.sidString = sidString;
+            this.sidType = sidType;
+            this.accountName = accountName;
+        }
+
+        // package-private
+        String sidString() {
+            return sidString;
+        }
+
+        @Override
+        public String getName() {
+            return accountName;
+        }
+
+        @Override
+        public String toString() {
+            String type;
+            switch (sidType) {
+                case SidTypeUser : type = "User"; break;
+                case SidTypeGroup : type = "Group"; break;
+                case SidTypeDomain : type = "Domain"; break;
+                case SidTypeAlias : type = "Alias"; break;
+                case SidTypeWellKnownGroup : type = "Well-known group"; break;
+                case SidTypeDeletedAccount : type = "Deleted"; break;
+                case SidTypeInvalid : type = "Invalid"; break;
+                case SidTypeComputer : type = "Computer"; break;
+                default: type = "Unknown";
+            }
+            return accountName + " (" + type + ")";
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this)
+                return true;
+            if (!(obj instanceof WindowsUserPrincipals.User))
+                return false;
+            WindowsUserPrincipals.User other = (WindowsUserPrincipals.User)obj;
+            return this.sidString.equals(other.sidString);
+        }
+
+        @Override
+        public int hashCode() {
+            return sidString.hashCode();
+        }
+    }
+
+    static class Group extends User implements GroupPrincipal {
+        Group(String sidString, int sidType, String accountName) {
+            super(sidString, sidType, accountName);
+        }
+    }
+
+    static UserPrincipal fromSid(long sidAddress) throws IOException {
+        String sidString;
+        try {
+            sidString = ConvertSidToStringSid(sidAddress);
+            if (sidString == null) {
+                // pre-Windows XP system?
+                throw new AssertionError();
+            }
+        } catch (WindowsException x) {
+            throw new IOException("Unable to convert SID to String: " +
+                x.errorString());
+        }
+
+        // lookup account; if not available then use the SID as the name
+        Account account = null;
+        String name;
+        try {
+            account = LookupAccountSid(sidAddress);
+            name = account.domain() + "\\" + account.name();
+        } catch (WindowsException x) {
+            name = sidString;
+        }
+
+        int sidType = (account == null) ? SidTypeUnknown : account.use();
+        if ((sidType == SidTypeGroup) ||
+            (sidType == SidTypeWellKnownGroup) ||
+            (sidType == SidTypeAlias)) // alias for local group
+        {
+            return new Group(sidString, sidType, name);
+        } else {
+            return new User(sidString, sidType, name);
+        }
+    }
+
+    static UserPrincipal lookup(String name) throws IOException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("lookupUserInformation"));
+        }
+
+        // invoke LookupAccountName to get buffer size needed for SID
+        int size = 0;
+        try {
+            size = LookupAccountName(name, 0L, 0);
+        } catch (WindowsException x) {
+            if (x.lastError() == ERROR_NONE_MAPPED)
+                throw new UserPrincipalNotFoundException(name);
+            throw new IOException(name + ": " + x.errorString());
+        }
+        assert size > 0;
+
+        // allocate buffer and re-invoke LookupAccountName get SID
+        NativeBuffer sidBuffer = NativeBuffers.getNativeBuffer(size);
+        try {
+            int newSize = LookupAccountName(name, sidBuffer.address(), size);
+            if (newSize != size) {
+                // can this happen?
+                throw new AssertionError("SID change during lookup");
+            }
+
+            // return user principal
+            return fromSid(sidBuffer.address());
+        } catch (WindowsException x) {
+            throw new IOException(name + ": " + x.errorString());
+        } finally {
+            sidBuffer.release();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,582 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.io.IOException;
+import java.util.*;
+import com.sun.nio.file.ExtendedWatchEventModifier;
+import sun.misc.Unsafe;
+
+import static sun.nio.fs.WindowsNativeDispatcher.*;
+import static sun.nio.fs.WindowsConstants.*;
+
+/*
+ * Win32 implementation of WatchService based on ReadDirectoryChangesW.
+ */
+
+class WindowsWatchService
+    extends AbstractWatchService
+{
+    private final Unsafe unsafe = Unsafe.getUnsafe();
+
+    // background thread to service I/O completion port
+    private final Poller poller;
+
+    /**
+     * Creates an I/O completion port and a daemon thread to service it
+     */
+    WindowsWatchService(WindowsFileSystem fs) throws IOException {
+        // create I/O completion port
+        long port = 0L;
+        try {
+            port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0);
+        } catch (WindowsException x) {
+            throw new IOException(x.getMessage());
+        }
+
+        this.poller = new Poller(fs, this, port);
+        this.poller.start();
+    }
+
+    @Override
+    WatchKey register(Path path,
+                      WatchEvent.Kind<?>[] events,
+                      WatchEvent.Modifier... modifiers)
+         throws IOException
+    {
+        // delegate to poller
+        return poller.register(path, events, modifiers);
+    }
+
+    @Override
+    void implClose() throws IOException {
+        // delegate to poller
+        poller.close();
+    }
+
+    /**
+     * Windows implementation of WatchKey.
+     */
+    private class WindowsWatchKey extends AbstractWatchKey {
+        // file key (used to detect existing registrations)
+        private FileKey fileKey;
+
+        // handle to directory
+        private volatile long handle = INVALID_HANDLE_VALUE;
+
+        // interest events
+        private Set<? extends WatchEvent.Kind<?>> events;
+
+        // subtree
+        private boolean watchSubtree;
+
+        // buffer for change events
+        private NativeBuffer buffer;
+
+        // pointer to bytes returned (in buffer)
+        private long countAddress;
+
+        // pointer to overlapped structure (in buffer)
+        private long overlappedAddress;
+
+        // completion key (used to map I/O completion to WatchKey)
+        private int completionKey;
+
+        WindowsWatchKey(AbstractWatchService watcher, FileKey fileKey) {
+            super(watcher);
+            this.fileKey = fileKey;
+        }
+
+        WindowsWatchKey init(long handle,
+                             Set<? extends WatchEvent.Kind<?>> events,
+                             boolean watchSubtree,
+                             NativeBuffer buffer,
+                             long countAddress,
+                             long overlappedAddress,
+                             int completionKey)
+        {
+            this.handle = handle;
+            this.events = events;
+            this.watchSubtree = watchSubtree;
+            this.buffer = buffer;
+            this.countAddress = countAddress;
+            this.overlappedAddress = overlappedAddress;
+            this.completionKey = completionKey;
+            return this;
+        }
+
+        long handle() {
+            return handle;
+        }
+
+        Set<? extends WatchEvent.Kind<?>> events() {
+            return events;
+        }
+
+        void setEvents(Set<? extends WatchEvent.Kind<?>> events) {
+            this.events = events;
+        }
+
+        boolean watchSubtree() {
+            return watchSubtree;
+        }
+
+        NativeBuffer buffer() {
+            return buffer;
+        }
+
+        long countAddress() {
+            return countAddress;
+        }
+
+        long overlappedAddress() {
+            return overlappedAddress;
+        }
+
+        FileKey fileKey() {
+            return fileKey;
+        }
+
+        int completionKey() {
+            return completionKey;
+        }
+
+        // close directory and release buffer
+        void releaseResources() {
+            CloseHandle(handle);
+            buffer.cleaner().clean();
+        }
+
+        // Invalidate key by closing directory and releasing buffer
+        void invalidate() {
+            releaseResources();
+            handle = INVALID_HANDLE_VALUE;
+            buffer = null;
+            countAddress = 0;
+            overlappedAddress = 0;
+        }
+
+        @Override
+        public boolean isValid() {
+            return handle != INVALID_HANDLE_VALUE;
+        }
+
+        @Override
+        public void cancel() {
+            if (isValid()) {
+                // delegate to poller
+                poller.cancel(this);
+            }
+        }
+    }
+
+    // file key to unique identify (open) directory
+    private static class FileKey {
+        private final int volSerialNumber;
+        private final int fileIndexHigh;
+        private final int fileIndexLow;
+
+        FileKey(int volSerialNumber, int fileIndexHigh, int fileIndexLow) {
+            this.volSerialNumber = volSerialNumber;
+            this.fileIndexHigh = fileIndexHigh;
+            this.fileIndexLow = fileIndexLow;
+        }
+
+        @Override
+        public int hashCode() {
+            return volSerialNumber ^ fileIndexHigh ^ fileIndexLow;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this)
+                return true;
+            if (!(obj instanceof FileKey))
+                return false;
+            FileKey other = (FileKey)obj;
+            if (this.volSerialNumber != other.volSerialNumber) return false;
+            if (this.fileIndexHigh != other.fileIndexHigh) return false;
+            if (this.fileIndexLow != other.fileIndexLow) return false;
+            return true;
+        }
+    }
+
+    // all change events
+    private static final int ALL_FILE_NOTIFY_EVENTS =
+        FILE_NOTIFY_CHANGE_FILE_NAME |
+        FILE_NOTIFY_CHANGE_DIR_NAME |
+        FILE_NOTIFY_CHANGE_ATTRIBUTES  |
+        FILE_NOTIFY_CHANGE_SIZE |
+        FILE_NOTIFY_CHANGE_LAST_WRITE |
+        FILE_NOTIFY_CHANGE_CREATION |
+        FILE_NOTIFY_CHANGE_SECURITY;
+
+    /**
+     * Background thread to service I/O completion port.
+     */
+    private class Poller extends AbstractPoller {
+        /*
+         * typedef struct _OVERLAPPED {
+         *     DWORD  Internal;
+         *     DWORD  InternalHigh;
+         *     DWORD  Offset;
+         *     DWORD  OffsetHigh;
+         *     HANDLE hEvent;
+         * } OVERLAPPED;
+         */
+        private static final short SIZEOF_DWORD         = 4;
+        private static final short SIZEOF_OVERLAPPED    = 32; // 20 on 32-bit
+
+        /*
+         * typedef struct _FILE_NOTIFY_INFORMATION {
+         *     DWORD NextEntryOffset;
+         *     DWORD Action;
+         *     DWORD FileNameLength;
+         *     WCHAR FileName[1];
+         * } FileNameLength;
+         */
+        private static final short OFFSETOF_NEXTENTRYOFFSET = 0;
+        private static final short OFFSETOF_ACTION          = 4;
+        private static final short OFFSETOF_FILENAMELENGTH  = 8;
+        private static final short OFFSETOF_FILENAME        = 12;
+
+        // size of per-directory buffer for events (FIXME - make this configurable)
+        private static final int CHANGES_BUFFER_SIZE    = 16 * 1024;
+
+        private final WindowsFileSystem fs;
+        private final WindowsWatchService watcher;
+        private final long port;
+
+        // maps completion key to WatchKey
+        private final Map<Integer,WindowsWatchKey> int2key;
+
+        // maps file key to WatchKey
+        private final Map<FileKey,WindowsWatchKey> fk2key;
+
+        // unique completion key for each directory
+        private int lastCompletionKey;
+
+        Poller(WindowsFileSystem fs, WindowsWatchService watcher, long port) {
+            this.fs = fs;
+            this.watcher = watcher;
+            this.port = port;
+            this.int2key = new HashMap<Integer,WindowsWatchKey>();
+            this.fk2key = new HashMap<FileKey,WindowsWatchKey>();
+            this.lastCompletionKey = 0;
+        }
+
+        @Override
+        void wakeup() throws IOException {
+            try {
+                PostQueuedCompletionStatus(port, 0);
+            } catch (WindowsException x) {
+                throw new IOException(x.getMessage());
+            }
+        }
+
+        /**
+         * Register a directory for changes as follows:
+         *
+         * 1. Open directory
+         * 2. Read its attributes (and check it really is a directory)
+         * 3. Assign completion key and associated handle with completion port
+         * 4. Call ReadDirectoryChangesW to start (async) read of changes
+         * 5. Create or return existing key representing registration
+         */
+        @Override
+        Object implRegister(Path obj,
+                            Set<? extends WatchEvent.Kind<?>> events,
+                            WatchEvent.Modifier... modifiers)
+        {
+            WindowsPath dir = (WindowsPath)obj;
+            boolean watchSubtree = false;
+
+            // FILE_TREE modifier allowed
+            for (WatchEvent.Modifier modifier: modifiers) {
+                if (modifier == ExtendedWatchEventModifier.FILE_TREE) {
+                    watchSubtree = true;
+                    continue;
+                } else {
+                    if (modifier == null)
+                        return new NullPointerException();
+                    if (modifier instanceof com.sun.nio.file.SensitivityWatchEventModifier)
+                        continue; // ignore
+                    return new UnsupportedOperationException("Modifier not supported");
+                }
+            }
+
+            // open directory
+            long handle = -1L;
+            try {
+                handle = CreateFile(dir.getPathForWin32Calls(),
+                                    FILE_LIST_DIRECTORY,
+                                    (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
+                                    OPEN_EXISTING,
+                                    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED);
+            } catch (WindowsException x) {
+                return x.asIOException(dir);
+            }
+
+            boolean registered = false;
+            try {
+                // read attributes and check file is a directory
+                WindowsFileAttributes attrs = null;
+                try {
+                    attrs = WindowsFileAttributes.readAttributes(handle);
+                } catch (WindowsException x) {
+                    return x.asIOException(dir);
+                }
+                if (!attrs.isDirectory()) {
+                    return new NotDirectoryException(dir.getPathForExceptionMessage());
+                }
+
+                // check if this directory is already registered
+                FileKey fk = new FileKey(attrs.volSerialNumber(),
+                                         attrs.fileIndexHigh(),
+                                         attrs.fileIndexLow());
+                WindowsWatchKey existing = fk2key.get(fk);
+
+                // if already registered and we're not changing the subtree
+                // modifier then simply update the event and return the key.
+                if (existing != null && watchSubtree == existing.watchSubtree()) {
+                    existing.setEvents(events);
+                    return existing;
+                }
+
+                // unique completion key (skip 0)
+                int completionKey = ++lastCompletionKey;
+                if (completionKey == 0)
+                    completionKey = ++lastCompletionKey;
+
+                // associate handle with completion port
+                try {
+                    CreateIoCompletionPort(handle, port, completionKey);
+                } catch (WindowsException x) {
+                    return new IOException(x.getMessage());
+                }
+
+                // allocate memory for events, including space for other structures
+                // needed to do overlapped I/O
+                int size = CHANGES_BUFFER_SIZE + SIZEOF_DWORD + SIZEOF_OVERLAPPED;
+                NativeBuffer buffer = NativeBuffers.getNativeBuffer(size);
+
+                long bufferAddress = buffer.address();
+                long overlappedAddress = bufferAddress + size - SIZEOF_OVERLAPPED;
+                long countAddress = overlappedAddress - SIZEOF_DWORD;
+
+                // start async read of changes to directory
+                try {
+                    ReadDirectoryChangesW(handle,
+                                          bufferAddress,
+                                          CHANGES_BUFFER_SIZE,
+                                          watchSubtree,
+                                          ALL_FILE_NOTIFY_EVENTS,
+                                          countAddress,
+                                          overlappedAddress);
+                } catch (WindowsException x) {
+                    buffer.release();
+                    return new IOException(x.getMessage());
+                }
+
+                WindowsWatchKey watchKey;
+                if (existing == null) {
+                    // not registered so create new watch key
+                    watchKey = new WindowsWatchKey(watcher, fk)
+                        .init(handle, events, watchSubtree, buffer, countAddress,
+                              overlappedAddress, completionKey);
+                    // map file key to watch key
+                    fk2key.put(fk, watchKey);
+                } else {
+                    // directory already registered so need to:
+                    // 1. remove mapping from old completion key to existing watch key
+                    // 2. release existing key's resources (handle/buffer)
+                    // 3. re-initialize key with new handle/buffer
+                    int2key.remove(existing.completionKey());
+                    existing.releaseResources();
+                    watchKey = existing.init(handle, events, watchSubtree, buffer,
+                        countAddress, overlappedAddress, completionKey);
+                }
+                // map completion map to watch key
+                int2key.put(completionKey, watchKey);
+
+                registered = true;
+                return watchKey;
+
+            } finally {
+                if (!registered) CloseHandle(handle);
+            }
+        }
+
+        // cancel single key
+        @Override
+        void implCancelKey(WatchKey obj) {
+            WindowsWatchKey key = (WindowsWatchKey)obj;
+            if (key.isValid()) {
+                fk2key.remove(key.fileKey());
+                int2key.remove(key.completionKey());
+                key.invalidate();
+            }
+        }
+
+        // close watch service
+        @Override
+        void implCloseAll() {
+            // cancel all keys
+            for (Map.Entry<Integer,WindowsWatchKey> entry: int2key.entrySet()) {
+                entry.getValue().invalidate();
+            }
+            fk2key.clear();
+            int2key.clear();
+
+            // close I/O completion port
+            CloseHandle(port);
+        }
+
+        // Translate file change action into watch event
+        private WatchEvent.Kind<?> translateActionToEvent(int action)
+        {
+            switch (action) {
+                case FILE_ACTION_MODIFIED :
+                    return StandardWatchEventKind.ENTRY_MODIFY;
+
+                case FILE_ACTION_ADDED :
+                case FILE_ACTION_RENAMED_NEW_NAME :
+                    return StandardWatchEventKind.ENTRY_CREATE;
+
+                case FILE_ACTION_REMOVED :
+                case FILE_ACTION_RENAMED_OLD_NAME :
+                    return StandardWatchEventKind.ENTRY_DELETE;
+
+                default :
+                    return null;  // action not recognized
+            }
+        }
+
+        // process events (list of FILE_NOTIFY_INFORMATION structures)
+        private void processEvents(WindowsWatchKey key, int size) {
+            long address = key.buffer().address();
+
+            int nextOffset;
+            do {
+                int action = unsafe.getInt(address + OFFSETOF_ACTION);
+
+                // map action to event
+                WatchEvent.Kind<?> kind = translateActionToEvent(action);
+                if (key.events().contains(kind)) {
+                    // copy the name
+                    int nameLengthInBytes = unsafe.getInt(address + OFFSETOF_FILENAMELENGTH);
+                    if ((nameLengthInBytes % 2) != 0) {
+                        throw new AssertionError("FileNameLength.FileNameLength is not a multiple of 2");
+                    }
+                    char[] nameAsArray = new char[nameLengthInBytes/2];
+                    unsafe.copyMemory(null, address + OFFSETOF_FILENAME, nameAsArray,
+                        Unsafe.ARRAY_CHAR_BASE_OFFSET, nameLengthInBytes);
+
+                    // create FileName and queue event
+                    WindowsPath name = WindowsPath
+                        .createFromNormalizedPath(fs, new String(nameAsArray));
+                    key.signalEvent(kind, name);
+                }
+
+                // next event
+                nextOffset = unsafe.getInt(address + OFFSETOF_NEXTENTRYOFFSET);
+                address += (long)nextOffset;
+            } while (nextOffset != 0);
+        }
+
+        /**
+         * Poller main loop
+         */
+        @Override
+        public void run() {
+            for (;;) {
+                CompletionStatus info = null;
+                try {
+                    info = GetQueuedCompletionStatus(port);
+                } catch (WindowsException x) {
+                    // this should not happen
+                    x.printStackTrace();
+                    return;
+                }
+
+                // wakeup
+                if (info.completionKey() == 0) {
+                    boolean shutdown = processRequests();
+                    if (shutdown) {
+                        return;
+                    }
+                    continue;
+                }
+
+                // map completionKey to get WatchKey
+                WindowsWatchKey key = int2key.get(info.completionKey());
+                if (key == null) {
+                    // We get here when a registration is changed. In that case
+                    // the directory is closed which causes an event with the
+                    // old completion key.
+                    continue;
+                }
+
+                // ReadDirectoryChangesW failed
+                if (info.error() != 0) {
+                    // buffer overflow
+                    if (info.error() == ERROR_NOTIFY_ENUM_DIR) {
+                        key.signalEvent(StandardWatchEventKind.OVERFLOW, null);
+                    } else {
+                        // other error so cancel key
+                        implCancelKey(key);
+                        key.signal();
+                    }
+                    continue;
+                }
+
+                // process the events
+                if (info.bytesTransferred() > 0) {
+                    processEvents(key, info.bytesTransferred());
+                } else {
+                    // insufficient buffer size
+                    key.signalEvent(StandardWatchEventKind.OVERFLOW, null);
+                }
+
+                // start read for next batch of changes
+                try {
+                    ReadDirectoryChangesW(key.handle(),
+                                          key.buffer().address(),
+                                          CHANGES_BUFFER_SIZE,
+                                          key.watchSubtree(),
+                                          ALL_FILE_NOTIFY_EVENTS,
+                                          key.countAddress(),
+                                          key.overlappedAddress());
+                } catch (WindowsException x) {
+                    // no choice but to cancel key
+                    implCancelKey(key);
+                    key.signal();
+                }
+            }
+        }
+    }
+}
--- a/jdk/src/windows/native/sun/nio/ch/FileChannelImpl.c	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/src/windows/native/sun/nio/ch/FileChannelImpl.c	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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
@@ -34,10 +34,6 @@
 
 static jfieldID chan_fd; /* id for jobject 'fd' in java.io.FileChannel */
 
-
-/* false for 95/98/ME, true for NT/W2K */
-static jboolean onNT = JNI_FALSE;
-
 /**************************************************************
  * static method to store field ID's in initializers
  * and retrieve the allocation granularity
@@ -47,15 +43,9 @@
 {
     SYSTEM_INFO si;
     jint align;
-    OSVERSIONINFO ver;
     GetSystemInfo(&si);
     align = si.dwAllocationGranularity;
     chan_fd = (*env)->GetFieldID(env, clazz, "fd", "Ljava/io/FileDescriptor;");
-    ver.dwOSVersionInfoSize = sizeof(ver);
-    GetVersionEx(&ver);
-    if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
-        onNT = JNI_TRUE;
-    }
     return align;
 }
 
@@ -146,56 +136,6 @@
     return 0;
 }
 
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_FileChannelImpl_truncate0(JNIEnv *env, jobject this,
-                                    jobject fdo, jlong size)
-{
-    DWORD lowPos = 0;
-    long highPos = 0;
-    BOOL result = 0;
-    HANDLE h = (HANDLE)(handleval(env, fdo));
-
-    lowPos = (DWORD)size;
-    highPos = (long)(size >> 32);
-    lowPos = SetFilePointer(h, lowPos, &highPos, FILE_BEGIN);
-    if (lowPos == ((DWORD)-1)) {
-        if (GetLastError() != ERROR_SUCCESS) {
-            JNU_ThrowIOExceptionWithLastError(env, "Truncation failed");
-            return IOS_THROWN;
-        }
-    }
-    result = SetEndOfFile(h);
-    if (result == 0) {
-        JNU_ThrowIOExceptionWithLastError(env, "Truncation failed");
-        return IOS_THROWN;
-    }
-    return 0;
-}
-
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_FileChannelImpl_force0(JNIEnv *env, jobject this,
-                                    jobject fdo, jboolean md)
-{
-    int result = 0;
-    HANDLE h = (HANDLE)(handleval(env, fdo));
-
-    if (h != INVALID_HANDLE_VALUE) {
-        result = FlushFileBuffers(h);
-        if (result == 0) {
-            int error = GetLastError();
-            if (error != ERROR_ACCESS_DENIED) {
-                JNU_ThrowIOExceptionWithLastError(env, "Force failed");
-                return IOS_THROWN;
-            }
-        }
-    } else {
-        JNU_ThrowIOExceptionWithLastError(env, "Force failed");
-        return IOS_THROWN;
-    }
-    return 0;
-}
-
 JNIEXPORT jlong JNICALL
 Java_sun_nio_ch_FileChannelImpl_position0(JNIEnv *env, jobject this,
                                           jobject fdo, jlong offset)
@@ -220,23 +160,6 @@
     return (((jlong)highPos) << 32) | lowPos;
 }
 
-JNIEXPORT jlong JNICALL
-Java_sun_nio_ch_FileChannelImpl_size0(JNIEnv *env, jobject this, jobject fdo)
-{
-    DWORD sizeLow = 0;
-    DWORD sizeHigh = 0;
-    HANDLE h = (HANDLE)(handleval(env, fdo));
-
-    sizeLow = GetFileSize(h, &sizeHigh);
-    if (sizeLow == ((DWORD)-1)) {
-        if (GetLastError() != ERROR_SUCCESS) {
-            JNU_ThrowIOExceptionWithLastError(env, "Size failed");
-            return IOS_THROWN;
-        }
-    }
-    return (((jlong)sizeHigh) << 32) | sizeLow;
-}
-
 JNIEXPORT void JNICALL
 Java_sun_nio_ch_FileChannelImpl_close0(JNIEnv *env, jobject this, jobject fdo)
 {
@@ -257,99 +180,3 @@
 {
     return IOS_UNSUPPORTED;
 }
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_FileChannelImpl_lock0(JNIEnv *env, jobject this, jobject fdo,
-                                      jboolean block, jlong pos, jlong size,
-                                      jboolean shared)
-{
-    HANDLE h = (HANDLE)(handleval(env, fdo));
-    DWORD lowPos = (DWORD)pos;
-    long highPos = (long)(pos >> 32);
-    DWORD lowNumBytes = (DWORD)size;
-    DWORD highNumBytes = (DWORD)(size >> 32);
-    jint result = 0;
-    if (onNT) {
-        DWORD flags = 0;
-        OVERLAPPED o;
-        o.hEvent = 0;
-        o.Offset = lowPos;
-        o.OffsetHigh = highPos;
-        if (block == JNI_FALSE) {
-            flags |= LOCKFILE_FAIL_IMMEDIATELY;
-        }
-        if (shared == JNI_FALSE) {
-            flags |= LOCKFILE_EXCLUSIVE_LOCK;
-        }
-        result = LockFileEx(h, flags, 0, lowNumBytes, highNumBytes, &o);
-        if (result == 0) {
-            int error = GetLastError();
-            if (error != ERROR_LOCK_VIOLATION) {
-                JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
-                return sun_nio_ch_FileChannelImpl_NO_LOCK;
-            }
-            if (flags & LOCKFILE_FAIL_IMMEDIATELY) {
-                return sun_nio_ch_FileChannelImpl_NO_LOCK;
-            }
-            JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
-            return sun_nio_ch_FileChannelImpl_NO_LOCK;
-        }
-        return sun_nio_ch_FileChannelImpl_LOCKED;
-    } else {
-        for(;;) {
-            if (size > 0x7fffffff) {
-                size = 0x7fffffff;
-            }
-            lowNumBytes = (DWORD)size;
-            highNumBytes = 0;
-            result = LockFile(h, lowPos, highPos, lowNumBytes, highNumBytes);
-            if (result != 0) {
-                if (shared == JNI_TRUE) {
-                    return sun_nio_ch_FileChannelImpl_RET_EX_LOCK;
-                } else {
-                    return sun_nio_ch_FileChannelImpl_LOCKED;
-                }
-            } else {
-                int error = GetLastError();
-                if (error != ERROR_LOCK_VIOLATION) {
-                    JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
-                    return sun_nio_ch_FileChannelImpl_NO_LOCK;
-                }
-                if (block == JNI_FALSE) {
-                    return sun_nio_ch_FileChannelImpl_NO_LOCK;
-                }
-            }
-            Sleep(100);
-        }
-    }
-    return sun_nio_ch_FileChannelImpl_NO_LOCK;
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_FileChannelImpl_release0(JNIEnv *env, jobject this,
-                                        jobject fdo, jlong pos, jlong size)
-{
-    HANDLE h = (HANDLE)(handleval(env, fdo));
-    DWORD lowPos = (DWORD)pos;
-    long highPos = (long)(pos >> 32);
-    DWORD lowNumBytes = (DWORD)size;
-    DWORD highNumBytes = (DWORD)(size >> 32);
-    jint result = 0;
-    if (onNT) {
-        OVERLAPPED o;
-        o.hEvent = 0;
-        o.Offset = lowPos;
-        o.OffsetHigh = highPos;
-        result = UnlockFileEx(h, 0, lowNumBytes, highNumBytes, &o);
-    } else {
-        if (size > 0x7fffffff) {
-            size = 0x7fffffff;
-        }
-        lowNumBytes = (DWORD)size;
-        highNumBytes = 0;
-        result = UnlockFile(h, lowPos, highPos, lowNumBytes, highNumBytes);
-    }
-    if (result == 0) {
-        JNU_ThrowIOExceptionWithLastError(env, "Release failed");
-    }
-}
--- a/jdk/src/windows/native/sun/nio/ch/FileDispatcher.c	Wed Feb 11 13:16:53 2009 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,319 +0,0 @@
-/*
- * Copyright 2000-2003 Sun Microsystems, Inc.  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.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-#include <windows.h>
-#include "jni.h"
-#include "jni_util.h"
-#include "jvm.h"
-#include "jlong.h"
-#include "sun_nio_ch_FileDispatcher.h"
-#include <io.h>
-#include "nio.h"
-#include "nio_util.h"
-
-
-/**************************************************************
- * FileDispatcher.c
- */
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_FileDispatcher_read0(JNIEnv *env, jclass clazz, jobject fdo,
-                                      jlong address, jint len)
-{
-    DWORD read = 0;
-    BOOL result = 0;
-    HANDLE h = (HANDLE)(handleval(env, fdo));
-
-    if (h == INVALID_HANDLE_VALUE) {
-        JNU_ThrowIOExceptionWithLastError(env, "Invalid handle");
-        return IOS_THROWN;
-    }
-    result = ReadFile(h,          /* File handle to read */
-                      (LPVOID)address,    /* address to put data */
-                      len,        /* number of bytes to read */
-                      &read,      /* number of bytes read */
-                      NULL);      /* no overlapped struct */
-    if (result == 0) {
-        int error = GetLastError();
-        if (error == ERROR_BROKEN_PIPE) {
-            return IOS_EOF;
-        }
-        if (error == ERROR_NO_DATA) {
-            return IOS_UNAVAILABLE;
-        }
-        JNU_ThrowIOExceptionWithLastError(env, "Read failed");
-        return IOS_THROWN;
-    }
-    return convertReturnVal(env, (jint)read, JNI_TRUE);
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_nio_ch_FileDispatcher_readv0(JNIEnv *env, jclass clazz, jobject fdo,
-                                       jlong address, jint len)
-{
-    DWORD read = 0;
-    BOOL result = 0;
-    jlong totalRead = 0;
-    LPVOID loc;
-    int i = 0;
-    DWORD num = 0;
-    struct iovec *iovecp = (struct iovec *)jlong_to_ptr(address);
-    HANDLE h = (HANDLE)(handleval(env, fdo));
-
-    if (h == INVALID_HANDLE_VALUE) {
-        JNU_ThrowIOExceptionWithLastError(env, "Invalid handle");
-        return IOS_THROWN;
-    }
-
-    for(i=0; i<len; i++) {
-        loc = (LPVOID)jlong_to_ptr(iovecp[i].iov_base);
-        num = iovecp[i].iov_len;
-        result = ReadFile(h,                /* File handle to read */
-                          loc,              /* address to put data */
-                          num,              /* number of bytes to read */
-                          &read,            /* number of bytes read */
-                          NULL);            /* no overlapped struct */
-        if (read > 0) {
-            totalRead += read;
-        }
-        if (read < num) {
-            break;
-        }
-    }
-
-    if (result == 0) {
-        int error = GetLastError();
-        if (error == ERROR_BROKEN_PIPE) {
-            return IOS_EOF;
-        }
-        if (error == ERROR_NO_DATA) {
-            return IOS_UNAVAILABLE;
-        }
-        JNU_ThrowIOExceptionWithLastError(env, "Read failed");
-        return IOS_THROWN;
-    }
-
-    return convertLongReturnVal(env, totalRead, JNI_TRUE);
-}
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_FileDispatcher_pread0(JNIEnv *env, jclass clazz, jobject fdo,
-                            jlong address, jint len, jlong offset)
-{
-    DWORD read = 0;
-    BOOL result = 0;
-    HANDLE h = (HANDLE)(handleval(env, fdo));
-    DWORD lowPos = 0;
-    long highPos = 0;
-    DWORD lowOffset = 0;
-    long highOffset = 0;
-
-    if (h == INVALID_HANDLE_VALUE) {
-        JNU_ThrowIOExceptionWithLastError(env, "Invalid handle");
-        return IOS_THROWN;
-    }
-
-    lowPos = SetFilePointer(h, 0, &highPos, FILE_CURRENT);
-    if (lowPos == ((DWORD)-1)) {
-        if (GetLastError() != ERROR_SUCCESS) {
-            JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
-            return IOS_THROWN;
-        }
-    }
-
-    lowOffset = (DWORD)offset;
-    highOffset = (DWORD)(offset >> 32);
-    lowOffset = SetFilePointer(h, lowOffset, &highOffset, FILE_BEGIN);
-    if (lowOffset == ((DWORD)-1)) {
-        if (GetLastError() != ERROR_SUCCESS) {
-            JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
-            return IOS_THROWN;
-        }
-    }
-
-    result = ReadFile(h,                /* File handle to read */
-                      (LPVOID)address,  /* address to put data */
-                      len,              /* number of bytes to read */
-                      &read,            /* number of bytes read */
-                      NULL);              /* struct with offset */
-
-    if (result == 0) {
-        int error = GetLastError();
-        if (error == ERROR_BROKEN_PIPE) {
-            return IOS_EOF;
-        }
-        if (error == ERROR_NO_DATA) {
-            return IOS_UNAVAILABLE;
-        }
-        JNU_ThrowIOExceptionWithLastError(env, "Read failed");
-        return IOS_THROWN;
-    }
-
-    lowPos = SetFilePointer(h, lowPos, &highPos, FILE_BEGIN);
-    if (lowPos == ((DWORD)-1)) {
-        if (GetLastError() != ERROR_SUCCESS) {
-            JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
-            return IOS_THROWN;
-        }
-    }
-    return convertReturnVal(env, (jint)read, JNI_TRUE);
-}
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_FileDispatcher_write0(JNIEnv *env, jclass clazz, jobject fdo,
-                                       jlong address, jint len)
-{
-    BOOL result = 0;
-    DWORD written = 0;
-    HANDLE h = (HANDLE)(handleval(env, fdo));
-
-    if (h != INVALID_HANDLE_VALUE) {
-        result = WriteFile(h,           /* File handle to write */
-                      (LPCVOID)address, /* pointers to the buffers */
-                      len,              /* number of bytes to write */
-                      &written,         /* receives number of bytes written */
-                      NULL);            /* no overlapped struct */
-    }
-
-    if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
-        JNU_ThrowIOExceptionWithLastError(env, "Write failed");
-    }
-
-    return convertReturnVal(env, (jint)written, JNI_FALSE);
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_nio_ch_FileDispatcher_writev0(JNIEnv *env, jclass clazz, jobject fdo,
-                                       jlong address, jint len)
-{
-    BOOL result = 0;
-    DWORD written = 0;
-    HANDLE h = (HANDLE)(handleval(env, fdo));
-    jlong totalWritten = 0;
-
-    if (h != INVALID_HANDLE_VALUE) {
-        LPVOID loc;
-        int i = 0;
-        DWORD num = 0;
-        struct iovec *iovecp = (struct iovec *)jlong_to_ptr(address);
-
-        for(i=0; i<len; i++) {
-            loc = (LPVOID)jlong_to_ptr(iovecp[i].iov_base);
-            num = iovecp[i].iov_len;
-            result = WriteFile(h,       /* File handle to write */
-                               loc,     /* pointers to the buffers */
-                               num,     /* number of bytes to write */
-                               &written,/* receives number of bytes written */
-                               NULL);   /* no overlapped struct */
-            if (written > 0) {
-                totalWritten += written;
-            }
-            if (written < num) {
-                break;
-            }
-        }
-    }
-
-    if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
-        JNU_ThrowIOExceptionWithLastError(env, "Write failed");
-    }
-
-    return convertLongReturnVal(env, totalWritten, JNI_FALSE);
-}
-
-JNIEXPORT jint JNICALL
-Java_sun_nio_ch_FileDispatcher_pwrite0(JNIEnv *env, jclass clazz, jobject fdo,
-                            jlong address, jint len, jlong offset)
-{
-    BOOL result = 0;
-    DWORD written = 0;
-    HANDLE h = (HANDLE)(handleval(env, fdo));
-    DWORD lowPos = 0;
-    long highPos = 0;
-    DWORD lowOffset = 0;
-    long highOffset = 0;
-
-    lowPos = SetFilePointer(h, 0, &highPos, FILE_CURRENT);
-    if (lowPos == ((DWORD)-1)) {
-        if (GetLastError() != ERROR_SUCCESS) {
-            JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
-            return IOS_THROWN;
-        }
-    }
-
-    lowOffset = (DWORD)offset;
-    highOffset = (DWORD)(offset >> 32);
-    lowOffset = SetFilePointer(h, lowOffset, &highOffset, FILE_BEGIN);
-    if (lowOffset == ((DWORD)-1)) {
-        if (GetLastError() != ERROR_SUCCESS) {
-            JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
-            return IOS_THROWN;
-        }
-    }
-
-    result = WriteFile(h,               /* File handle to write */
-                      (LPCVOID)address, /* pointers to the buffers */
-                      len,              /* number of bytes to write */
-                      &written,         /* receives number of bytes written */
-                      NULL);            /* no overlapped struct */
-
-    if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
-        JNU_ThrowIOExceptionWithLastError(env, "Write failed");
-        return IOS_THROWN;
-    }
-
-    lowPos = SetFilePointer(h, lowPos, &highPos, FILE_BEGIN);
-    if (lowPos == ((DWORD)-1)) {
-        if (GetLastError() != ERROR_SUCCESS) {
-            JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
-            return IOS_THROWN;
-        }
-    }
-
-    return convertReturnVal(env, (jint)written, JNI_FALSE);
-}
-
-static void closeFile(JNIEnv *env, jlong fd) {
-    HANDLE h = (HANDLE)fd;
-    if (h != INVALID_HANDLE_VALUE) {
-        int result = CloseHandle(h);
-        if (result < 0)
-            JNU_ThrowIOExceptionWithLastError(env, "Close failed");
-    }
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_FileDispatcher_close0(JNIEnv *env, jclass clazz, jobject fdo)
-{
-    jlong fd = handleval(env, fdo);
-    closeFile(env, fd);
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_FileDispatcher_closeByHandle(JNIEnv *env, jclass clazz,
-                                             jlong fd)
-{
-    closeFile(env, fd);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/native/sun/nio/ch/FileDispatcherImpl.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,443 @@
+/*
+ * Copyright 2000-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <windows.h>
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+#include "sun_nio_ch_FileDispatcherImpl.h"
+#include <io.h>
+#include "nio.h"
+#include "nio_util.h"
+
+
+/**************************************************************
+ * FileDispatcherImpl.c
+ */
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_read0(JNIEnv *env, jclass clazz, jobject fdo,
+                                      jlong address, jint len)
+{
+    DWORD read = 0;
+    BOOL result = 0;
+    HANDLE h = (HANDLE)(handleval(env, fdo));
+
+    if (h == INVALID_HANDLE_VALUE) {
+        JNU_ThrowIOExceptionWithLastError(env, "Invalid handle");
+        return IOS_THROWN;
+    }
+    result = ReadFile(h,          /* File handle to read */
+                      (LPVOID)address,    /* address to put data */
+                      len,        /* number of bytes to read */
+                      &read,      /* number of bytes read */
+                      NULL);      /* no overlapped struct */
+    if (result == 0) {
+        int error = GetLastError();
+        if (error == ERROR_BROKEN_PIPE) {
+            return IOS_EOF;
+        }
+        if (error == ERROR_NO_DATA) {
+            return IOS_UNAVAILABLE;
+        }
+        JNU_ThrowIOExceptionWithLastError(env, "Read failed");
+        return IOS_THROWN;
+    }
+    return convertReturnVal(env, (jint)read, JNI_TRUE);
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_readv0(JNIEnv *env, jclass clazz, jobject fdo,
+                                       jlong address, jint len)
+{
+    DWORD read = 0;
+    BOOL result = 0;
+    jlong totalRead = 0;
+    LPVOID loc;
+    int i = 0;
+    DWORD num = 0;
+    struct iovec *iovecp = (struct iovec *)jlong_to_ptr(address);
+    HANDLE h = (HANDLE)(handleval(env, fdo));
+
+    if (h == INVALID_HANDLE_VALUE) {
+        JNU_ThrowIOExceptionWithLastError(env, "Invalid handle");
+        return IOS_THROWN;
+    }
+
+    for(i=0; i<len; i++) {
+        loc = (LPVOID)jlong_to_ptr(iovecp[i].iov_base);
+        num = iovecp[i].iov_len;
+        result = ReadFile(h,                /* File handle to read */
+                          loc,              /* address to put data */
+                          num,              /* number of bytes to read */
+                          &read,            /* number of bytes read */
+                          NULL);            /* no overlapped struct */
+        if (read > 0) {
+            totalRead += read;
+        }
+        if (read < num) {
+            break;
+        }
+    }
+
+    if (result == 0) {
+        int error = GetLastError();
+        if (error == ERROR_BROKEN_PIPE) {
+            return IOS_EOF;
+        }
+        if (error == ERROR_NO_DATA) {
+            return IOS_UNAVAILABLE;
+        }
+        JNU_ThrowIOExceptionWithLastError(env, "Read failed");
+        return IOS_THROWN;
+    }
+
+    return convertLongReturnVal(env, totalRead, JNI_TRUE);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_pread0(JNIEnv *env, jclass clazz, jobject fdo,
+                            jlong address, jint len, jlong offset)
+{
+    DWORD read = 0;
+    BOOL result = 0;
+    HANDLE h = (HANDLE)(handleval(env, fdo));
+    DWORD lowPos = 0;
+    long highPos = 0;
+    DWORD lowOffset = 0;
+    long highOffset = 0;
+
+    if (h == INVALID_HANDLE_VALUE) {
+        JNU_ThrowIOExceptionWithLastError(env, "Invalid handle");
+        return IOS_THROWN;
+    }
+
+    lowPos = SetFilePointer(h, 0, &highPos, FILE_CURRENT);
+    if (lowPos == ((DWORD)-1)) {
+        if (GetLastError() != ERROR_SUCCESS) {
+            JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
+            return IOS_THROWN;
+        }
+    }
+
+    lowOffset = (DWORD)offset;
+    highOffset = (DWORD)(offset >> 32);
+    lowOffset = SetFilePointer(h, lowOffset, &highOffset, FILE_BEGIN);
+    if (lowOffset == ((DWORD)-1)) {
+        if (GetLastError() != ERROR_SUCCESS) {
+            JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
+            return IOS_THROWN;
+        }
+    }
+
+    result = ReadFile(h,                /* File handle to read */
+                      (LPVOID)address,  /* address to put data */
+                      len,              /* number of bytes to read */
+                      &read,            /* number of bytes read */
+                      NULL);              /* struct with offset */
+
+    if (result == 0) {
+        int error = GetLastError();
+        if (error == ERROR_BROKEN_PIPE) {
+            return IOS_EOF;
+        }
+        if (error == ERROR_NO_DATA) {
+            return IOS_UNAVAILABLE;
+        }
+        JNU_ThrowIOExceptionWithLastError(env, "Read failed");
+        return IOS_THROWN;
+    }
+
+    lowPos = SetFilePointer(h, lowPos, &highPos, FILE_BEGIN);
+    if (lowPos == ((DWORD)-1)) {
+        if (GetLastError() != ERROR_SUCCESS) {
+            JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
+            return IOS_THROWN;
+        }
+    }
+    return convertReturnVal(env, (jint)read, JNI_TRUE);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_write0(JNIEnv *env, jclass clazz, jobject fdo,
+                                       jlong address, jint len)
+{
+    BOOL result = 0;
+    DWORD written = 0;
+    HANDLE h = (HANDLE)(handleval(env, fdo));
+
+    if (h != INVALID_HANDLE_VALUE) {
+        result = WriteFile(h,           /* File handle to write */
+                      (LPCVOID)address, /* pointers to the buffers */
+                      len,              /* number of bytes to write */
+                      &written,         /* receives number of bytes written */
+                      NULL);            /* no overlapped struct */
+    }
+
+    if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
+        JNU_ThrowIOExceptionWithLastError(env, "Write failed");
+    }
+
+    return convertReturnVal(env, (jint)written, JNI_FALSE);
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_writev0(JNIEnv *env, jclass clazz, jobject fdo,
+                                       jlong address, jint len)
+{
+    BOOL result = 0;
+    DWORD written = 0;
+    HANDLE h = (HANDLE)(handleval(env, fdo));
+    jlong totalWritten = 0;
+
+    if (h != INVALID_HANDLE_VALUE) {
+        LPVOID loc;
+        int i = 0;
+        DWORD num = 0;
+        struct iovec *iovecp = (struct iovec *)jlong_to_ptr(address);
+
+        for(i=0; i<len; i++) {
+            loc = (LPVOID)jlong_to_ptr(iovecp[i].iov_base);
+            num = iovecp[i].iov_len;
+            result = WriteFile(h,       /* File handle to write */
+                               loc,     /* pointers to the buffers */
+                               num,     /* number of bytes to write */
+                               &written,/* receives number of bytes written */
+                               NULL);   /* no overlapped struct */
+            if (written > 0) {
+                totalWritten += written;
+            }
+            if (written < num) {
+                break;
+            }
+        }
+    }
+
+    if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
+        JNU_ThrowIOExceptionWithLastError(env, "Write failed");
+    }
+
+    return convertLongReturnVal(env, totalWritten, JNI_FALSE);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_pwrite0(JNIEnv *env, jclass clazz, jobject fdo,
+                            jlong address, jint len, jlong offset)
+{
+    BOOL result = 0;
+    DWORD written = 0;
+    HANDLE h = (HANDLE)(handleval(env, fdo));
+    DWORD lowPos = 0;
+    long highPos = 0;
+    DWORD lowOffset = 0;
+    long highOffset = 0;
+
+    lowPos = SetFilePointer(h, 0, &highPos, FILE_CURRENT);
+    if (lowPos == ((DWORD)-1)) {
+        if (GetLastError() != ERROR_SUCCESS) {
+            JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
+            return IOS_THROWN;
+        }
+    }
+
+    lowOffset = (DWORD)offset;
+    highOffset = (DWORD)(offset >> 32);
+    lowOffset = SetFilePointer(h, lowOffset, &highOffset, FILE_BEGIN);
+    if (lowOffset == ((DWORD)-1)) {
+        if (GetLastError() != ERROR_SUCCESS) {
+            JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
+            return IOS_THROWN;
+        }
+    }
+
+    result = WriteFile(h,               /* File handle to write */
+                      (LPCVOID)address, /* pointers to the buffers */
+                      len,              /* number of bytes to write */
+                      &written,         /* receives number of bytes written */
+                      NULL);            /* no overlapped struct */
+
+    if ((h == INVALID_HANDLE_VALUE) || (result == 0)) {
+        JNU_ThrowIOExceptionWithLastError(env, "Write failed");
+        return IOS_THROWN;
+    }
+
+    lowPos = SetFilePointer(h, lowPos, &highPos, FILE_BEGIN);
+    if (lowPos == ((DWORD)-1)) {
+        if (GetLastError() != ERROR_SUCCESS) {
+            JNU_ThrowIOExceptionWithLastError(env, "Seek failed");
+            return IOS_THROWN;
+        }
+    }
+
+    return convertReturnVal(env, (jint)written, JNI_FALSE);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_force0(JNIEnv *env, jobject this,
+                                          jobject fdo, jboolean md)
+{
+    int result = 0;
+    HANDLE h = (HANDLE)(handleval(env, fdo));
+
+    if (h != INVALID_HANDLE_VALUE) {
+        result = FlushFileBuffers(h);
+        if (result == 0) {
+            int error = GetLastError();
+            if (error != ERROR_ACCESS_DENIED) {
+                JNU_ThrowIOExceptionWithLastError(env, "Force failed");
+                return IOS_THROWN;
+            }
+        }
+    } else {
+        JNU_ThrowIOExceptionWithLastError(env, "Force failed");
+        return IOS_THROWN;
+    }
+    return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_truncate0(JNIEnv *env, jobject this,
+                                             jobject fdo, jlong size)
+{
+    DWORD lowPos = 0;
+    long highPos = 0;
+    BOOL result = 0;
+    HANDLE h = (HANDLE)(handleval(env, fdo));
+
+    lowPos = (DWORD)size;
+    highPos = (long)(size >> 32);
+    lowPos = SetFilePointer(h, lowPos, &highPos, FILE_BEGIN);
+    if (lowPos == ((DWORD)-1)) {
+        if (GetLastError() != ERROR_SUCCESS) {
+            JNU_ThrowIOExceptionWithLastError(env, "Truncation failed");
+            return IOS_THROWN;
+        }
+    }
+    result = SetEndOfFile(h);
+    if (result == 0) {
+        JNU_ThrowIOExceptionWithLastError(env, "Truncation failed");
+        return IOS_THROWN;
+    }
+    return 0;
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_size0(JNIEnv *env, jobject this, jobject fdo)
+{
+    DWORD sizeLow = 0;
+    DWORD sizeHigh = 0;
+    HANDLE h = (HANDLE)(handleval(env, fdo));
+
+    sizeLow = GetFileSize(h, &sizeHigh);
+    if (sizeLow == ((DWORD)-1)) {
+        if (GetLastError() != ERROR_SUCCESS) {
+            JNU_ThrowIOExceptionWithLastError(env, "Size failed");
+            return IOS_THROWN;
+        }
+    }
+    return (((jlong)sizeHigh) << 32) | sizeLow;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_lock0(JNIEnv *env, jobject this, jobject fdo,
+                                      jboolean block, jlong pos, jlong size,
+                                      jboolean shared)
+{
+    HANDLE h = (HANDLE)(handleval(env, fdo));
+    DWORD lowPos = (DWORD)pos;
+    long highPos = (long)(pos >> 32);
+    DWORD lowNumBytes = (DWORD)size;
+    DWORD highNumBytes = (DWORD)(size >> 32);
+    BOOL result;
+    DWORD flags = 0;
+    OVERLAPPED o;
+    o.hEvent = 0;
+    o.Offset = lowPos;
+    o.OffsetHigh = highPos;
+    if (block == JNI_FALSE) {
+        flags |= LOCKFILE_FAIL_IMMEDIATELY;
+    }
+    if (shared == JNI_FALSE) {
+        flags |= LOCKFILE_EXCLUSIVE_LOCK;
+    }
+    result = LockFileEx(h, flags, 0, lowNumBytes, highNumBytes, &o);
+    if (result == 0) {
+        int error = GetLastError();
+        if (error != ERROR_LOCK_VIOLATION) {
+            JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
+            return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
+        }
+        if (flags & LOCKFILE_FAIL_IMMEDIATELY) {
+            return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
+        }
+        JNU_ThrowIOExceptionWithLastError(env, "Lock failed");
+        return sun_nio_ch_FileDispatcherImpl_NO_LOCK;
+    }
+    return sun_nio_ch_FileDispatcherImpl_LOCKED;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_release0(JNIEnv *env, jobject this,
+                                        jobject fdo, jlong pos, jlong size)
+{
+    HANDLE h = (HANDLE)(handleval(env, fdo));
+    DWORD lowPos = (DWORD)pos;
+    long highPos = (long)(pos >> 32);
+    DWORD lowNumBytes = (DWORD)size;
+    DWORD highNumBytes = (DWORD)(size >> 32);
+    jint result = 0;
+    OVERLAPPED o;
+    o.hEvent = 0;
+    o.Offset = lowPos;
+    o.OffsetHigh = highPos;
+    result = UnlockFileEx(h, 0, lowNumBytes, highNumBytes, &o);
+    if (result == 0) {
+        JNU_ThrowIOExceptionWithLastError(env, "Release failed");
+    }
+}
+
+static void closeFile(JNIEnv *env, jlong fd) {
+    HANDLE h = (HANDLE)fd;
+    if (h != INVALID_HANDLE_VALUE) {
+        int result = CloseHandle(h);
+        if (result < 0)
+            JNU_ThrowIOExceptionWithLastError(env, "Close failed");
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_close0(JNIEnv *env, jclass clazz, jobject fdo)
+{
+    jlong fd = handleval(env, fdo);
+    closeFile(env, fd);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_FileDispatcherImpl_closeByHandle(JNIEnv *env, jclass clazz,
+                                             jlong fd)
+{
+    closeFile(env, fd);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/native/sun/nio/ch/Iocp.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <windows.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jlong.h"
+#include "nio.h"
+#include "nio_util.h"
+
+#include "sun_nio_ch_Iocp.h"
+
+
+static jfieldID completionStatus_error;
+static jfieldID completionStatus_bytesTransferred;
+static jfieldID completionStatus_completionKey;
+static jfieldID completionStatus_overlapped;
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Iocp_initIDs(JNIEnv* env, jclass this)
+{
+    jclass clazz;
+
+    clazz = (*env)->FindClass(env, "sun/nio/ch/Iocp$CompletionStatus");
+    if (clazz == NULL) {
+        return;
+    }
+    completionStatus_error = (*env)->GetFieldID(env, clazz, "error", "I");
+    if (completionStatus_error == NULL) return;
+    completionStatus_bytesTransferred = (*env)->GetFieldID(env, clazz, "bytesTransferred", "I");
+    if (completionStatus_bytesTransferred == NULL) return;
+    completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "I");
+    if (completionStatus_completionKey == NULL) return;
+    completionStatus_overlapped = (*env)->GetFieldID(env, clazz, "overlapped", "J");
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_ch_Iocp_createIoCompletionPort(JNIEnv* env, jclass this,
+    jlong handle, jlong existingPort, jint completionKey, jint concurrency)
+{
+    HANDLE port = CreateIoCompletionPort((HANDLE)jlong_to_ptr(handle),
+                                         (HANDLE)jlong_to_ptr(existingPort),
+                                         (DWORD)completionKey,
+                                         (DWORD)concurrency);
+    if (port == NULL) {
+        JNU_ThrowIOExceptionWithLastError(env, "CreateIoCompletionPort failed");
+    }
+    return ptr_to_jlong(port);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Iocp_close0(JNIEnv* env, jclass this,
+    jlong handle)
+{
+    HANDLE h = (HANDLE)jlong_to_ptr(handle);
+    CloseHandle(h);
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Iocp_getQueuedCompletionStatus(JNIEnv* env, jclass this,
+    jlong completionPort, jobject obj)
+{
+    DWORD bytesTransferred;
+    DWORD completionKey;
+    OVERLAPPED *lpOverlapped;
+    BOOL res;
+
+    res = GetQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort),
+                                  &bytesTransferred,
+                                  &completionKey,
+                                  &lpOverlapped,
+                                  INFINITE);
+    if (res == 0 && lpOverlapped == NULL) {
+        JNU_ThrowIOExceptionWithLastError(env, "GetQueuedCompletionStatus failed");
+    } else {
+        DWORD ioResult = (res == 0) ? GetLastError() : 0;
+        (*env)->SetIntField(env, obj, completionStatus_error, ioResult);
+        (*env)->SetIntField(env, obj, completionStatus_bytesTransferred,
+            (jint)bytesTransferred);
+        (*env)->SetIntField(env, obj, completionStatus_completionKey,
+            (jint)completionKey);
+        (*env)->SetLongField(env, obj, completionStatus_overlapped,
+            ptr_to_jlong(lpOverlapped));
+
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_Iocp_postQueuedCompletionStatus(JNIEnv* env, jclass this,
+    jlong completionPort, jint completionKey)
+{
+    BOOL res;
+
+    res = PostQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort),
+                                     (DWORD)0,
+                                     (DWORD)completionKey,
+                                     NULL);
+    if (res == 0) {
+        JNU_ThrowIOExceptionWithLastError(env, "PostQueuedCompletionStatus");
+    }
+}
+
+JNIEXPORT jstring JNICALL
+Java_sun_nio_ch_Iocp_getErrorMessage(JNIEnv* env, jclass this, jint errorCode)
+{
+    WCHAR message[255];
+
+    DWORD len = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
+                               NULL,
+                               (DWORD)errorCode,
+                               0,
+                               &message[0],
+                               255,
+                               NULL);
+
+
+    if (len == 0) {
+        return NULL;
+    } else {
+        return (*env)->NewString(env, (const jchar *)message, (jsize)wcslen(message));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousFileChannelImpl.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <windows.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jlong.h"
+#include "nio.h"
+#include "nio_util.h"
+
+#include "sun_nio_ch_WindowsAsynchronousFileChannelImpl.h"
+
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_readFile(JNIEnv* env, jclass this,
+    jlong handle, jlong address, jint len, jlong offset, jlong ov)
+{
+    BOOL res;
+    DWORD nread = 0;
+
+    OVERLAPPED* lpOverlapped = (OVERLAPPED*)jlong_to_ptr(ov);
+    lpOverlapped->Offset = (DWORD)offset;
+    lpOverlapped->OffsetHigh = (DWORD)((long)(offset >> 32));
+    lpOverlapped->hEvent = NULL;
+
+    res = ReadFile((HANDLE) jlong_to_ptr(handle),
+                   (LPVOID) jlong_to_ptr(address),
+                   (DWORD)len,
+                   &nread,
+                   lpOverlapped);
+
+    if (res == 0) {
+        int error = GetLastError();
+        if (error == ERROR_IO_PENDING)
+            return IOS_UNAVAILABLE;
+        if (error == ERROR_HANDLE_EOF)
+            return IOS_EOF;
+        JNU_ThrowIOExceptionWithLastError(env, "ReadFile failed");
+        return IOS_THROWN;
+    }
+
+    return (jint)nread;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_writeFile(JNIEnv* env, jclass this,
+    jlong handle, jlong address, jint len, jlong offset, jlong ov)
+{
+    BOOL res;
+    DWORD nwritten = 0;
+
+    OVERLAPPED* lpOverlapped = (OVERLAPPED*)jlong_to_ptr(ov);
+    lpOverlapped->Offset = (DWORD)offset;
+    lpOverlapped->OffsetHigh = (DWORD)((long)(offset >> 32));
+    lpOverlapped->hEvent = NULL;
+
+    res = WriteFile((HANDLE)jlong_to_ptr(handle),
+                   (LPVOID) jlong_to_ptr(address),
+                   (DWORD)len,
+                   &nwritten,
+                   lpOverlapped);
+
+    if (res == 0) {
+        int error = GetLastError();
+        if (error == ERROR_IO_PENDING) {
+            return IOS_UNAVAILABLE;
+        }
+        JNU_ThrowIOExceptionWithLastError(env, "WriteFile failed");
+        return IOS_THROWN;
+    }
+    return (jint)nwritten;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_lockFile(JNIEnv *env, jobject this, jlong handle,
+                                                            jlong pos, jlong size, jboolean shared, jlong ov)
+{
+    BOOL res;
+    HANDLE h = jlong_to_ptr(handle);
+    DWORD lowPos = (DWORD)pos;
+    long highPos = (long)(pos >> 32);
+    DWORD lowNumBytes = (DWORD)size;
+    DWORD highNumBytes = (DWORD)(size >> 32);
+    DWORD flags = (shared == JNI_TRUE) ? 0 : LOCKFILE_EXCLUSIVE_LOCK;
+    OVERLAPPED* lpOverlapped = (OVERLAPPED*)jlong_to_ptr(ov);
+
+    lpOverlapped->Offset = lowPos;
+    lpOverlapped->OffsetHigh = highPos;
+    lpOverlapped->hEvent = NULL;
+
+    res = LockFileEx(h, flags, 0, lowNumBytes, highNumBytes, lpOverlapped);
+    if (res == 0) {
+        int error = GetLastError();
+        if (error == ERROR_IO_PENDING) {
+            return IOS_UNAVAILABLE;
+        }
+        JNU_ThrowIOExceptionWithLastError(env, "WriteFile failed");
+        return IOS_THROWN;
+    }
+    return 0;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_WindowsAsynchronousFileChannelImpl_close0(JNIEnv* env, jclass this,
+    jlong handle)
+{
+    HANDLE h = (HANDLE)jlong_to_ptr(handle);
+    CloseHandle(h);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <windows.h>
+#include <winsock2.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jlong.h"
+#include "nio.h"
+#include "nio_util.h"
+#include "net_util.h"
+
+#include "sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl.h"
+
+
+#ifndef WSAID_ACCEPTEX
+#define WSAID_ACCEPTEX {0xb5367df1,0xcbac,0x11cf,{0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92}}
+#endif
+
+#ifndef SO_UPDATE_ACCEPT_CONTEXT
+#define SO_UPDATE_ACCEPT_CONTEXT 0x700B
+#endif
+
+
+typedef BOOL (*AcceptEx_t)
+(
+    SOCKET sListenSocket,
+    SOCKET sAcceptSocket,
+    PVOID lpOutputBuffer,
+    DWORD dwReceiveDataLength,
+    DWORD dwLocalAddressLength,
+    DWORD dwRemoteAddressLength,
+    LPDWORD lpdwBytesReceived,
+    LPOVERLAPPED lpOverlapped
+);
+
+
+static AcceptEx_t AcceptEx_func;
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl_initIDs(JNIEnv* env, jclass this) {
+    GUID GuidAcceptEx = WSAID_ACCEPTEX;
+    SOCKET s;
+    int rv;
+    DWORD dwBytes;
+
+    s = socket(AF_INET, SOCK_STREAM, 0);
+    if (s == INVALID_SOCKET) {
+        JNU_ThrowIOExceptionWithLastError(env, "socket failed");
+        return;
+    }
+    rv = WSAIoctl(s,
+                  SIO_GET_EXTENSION_FUNCTION_POINTER,
+                  (LPVOID)&GuidAcceptEx,
+                  sizeof(GuidAcceptEx),
+                  &AcceptEx_func,
+                  sizeof(AcceptEx_func),
+                  &dwBytes,
+                  NULL,
+                  NULL);
+    if (rv != 0)
+        JNU_ThrowIOExceptionWithLastError(env, "WSAIoctl failed");
+    closesocket(s);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl_accept0(JNIEnv* env, jclass this,
+    jlong listenSocket, jlong acceptSocket, jlong ov, jlong buf)
+{
+    BOOL res;
+    SOCKET s1 = (SOCKET)jlong_to_ptr(listenSocket);
+    SOCKET s2 = (SOCKET)jlong_to_ptr(acceptSocket);
+    PVOID outputBuffer = (PVOID)jlong_to_ptr(buf);
+
+    DWORD nread = 0;
+    OVERLAPPED* lpOverlapped = (OVERLAPPED*)jlong_to_ptr(ov);
+    ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED));
+
+    res = (*AcceptEx_func)(s1,
+                           s2,
+                           outputBuffer,
+                           0,
+                           sizeof(SOCKETADDRESS)+16,
+                           sizeof(SOCKETADDRESS)+16,
+                           &nread,
+                           lpOverlapped);
+    if (res == 0) {
+        int error = WSAGetLastError();
+        if (error == ERROR_IO_PENDING) {
+            return IOS_UNAVAILABLE;
+        }
+        JNU_ThrowIOExceptionWithLastError(env, "AcceptEx failed");
+        return IOS_THROWN;
+    }
+
+    return 0;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl_updateAcceptContext(JNIEnv* env, jclass this,
+    jlong listenSocket, jlong acceptSocket)
+{
+    SOCKET s1 = (SOCKET)jlong_to_ptr(listenSocket);
+    SOCKET s2 = (SOCKET)jlong_to_ptr(acceptSocket);
+
+    setsockopt(s2, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&s1, sizeof(s1));
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_WindowsAsynchronousServerSocketChannelImpl_closesocket0(JNIEnv* env, jclass this,
+    jlong socket)
+{
+    SOCKET s = (SOCKET)jlong_to_ptr(socket);
+
+    if (closesocket(s) == SOCKET_ERROR)
+        JNU_ThrowIOExceptionWithLastError(env, "closesocket failed");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <windows.h>
+#include <winsock2.h>
+#include <stddef.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jlong.h"
+#include "nio.h"
+#include "nio_util.h"
+#include "net_util.h"
+
+#include "sun_nio_ch_WindowsAsynchronousSocketChannelImpl.h"
+
+#ifndef WSAID_CONNECTEX
+#define WSAID_CONNECTEX {0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}}
+#endif
+
+#ifndef SO_UPDATE_CONNECT_CONTEXT
+#define SO_UPDATE_CONNECT_CONTEXT 0x7010
+#endif
+
+typedef BOOL (*ConnectEx_t)
+(
+    SOCKET s,
+    const struct sockaddr* name,
+    int namelen,
+    PVOID lpSendBuffer,
+    DWORD dwSendDataLength,
+    LPDWORD lpdwBytesSent,
+    LPOVERLAPPED lpOverlapped
+);
+
+static ConnectEx_t ConnectEx_func;
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_initIDs(JNIEnv* env, jclass this) {
+    GUID GuidConnectEx = WSAID_CONNECTEX;
+    SOCKET s;
+    int rv;
+    DWORD dwBytes;
+
+    s = socket(AF_INET, SOCK_STREAM, 0);
+    if (s == INVALID_SOCKET) {
+        JNU_ThrowIOExceptionWithLastError(env, "socket failed");
+        return;
+    }
+    rv = WSAIoctl(s,
+                  SIO_GET_EXTENSION_FUNCTION_POINTER,
+                  (LPVOID)&GuidConnectEx,
+                  sizeof(GuidConnectEx),
+                  &ConnectEx_func,
+                  sizeof(ConnectEx_func),
+                  &dwBytes,
+                  NULL,
+                  NULL);
+    if (rv != 0)
+        JNU_ThrowIOExceptionWithLastError(env, "WSAIoctl failed");
+    closesocket(s);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_connect0(JNIEnv* env, jclass this,
+    jlong socket, jboolean preferIPv6, jobject iao, jint port, jlong ov)
+{
+    SOCKET s = (SOCKET) jlong_to_ptr(socket);
+    OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov);
+
+    SOCKETADDRESS sa;
+    int sa_len;
+    BOOL res;
+
+    if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) {
+        return IOS_THROWN;
+    }
+
+    ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED));
+
+    res = (*ConnectEx_func)(s,
+                            (struct sockaddr *)&sa,
+                            sa_len,
+                            NULL,
+                            0,
+                            NULL,
+                            lpOverlapped);
+    if (res == 0) {
+        int error = GetLastError();
+        if (error == ERROR_IO_PENDING) {
+            return IOS_UNAVAILABLE;
+        }
+        JNU_ThrowIOExceptionWithLastError(env, "ConnectEx failed");
+        return IOS_THROWN;
+    }
+    return 0;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_updateConnectContext(JNIEnv* env, jclass this,
+    jlong socket)
+{
+    SOCKET s = (SOCKET)jlong_to_ptr(socket);
+    setsockopt(s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0);
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_shutdown0(JNIEnv *env, jclass cl,
+    jlong socket, jint how)
+{
+    SOCKET s =(SOCKET) jlong_to_ptr(socket);
+    if (shutdown(s, how) == SOCKET_ERROR) {
+        JNU_ThrowIOExceptionWithLastError(env, "shutdown failed");
+    }
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_closesocket0(JNIEnv* env, jclass this,
+    jlong socket)
+{
+    SOCKET s = (SOCKET)jlong_to_ptr(socket);
+    if (closesocket(s) == SOCKET_ERROR)
+        JNU_ThrowIOExceptionWithLastError(env, "closesocket failed");
+}
+
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_read0(JNIEnv* env, jclass this,
+    jlong socket, jint count, jlong address, jlong ov)
+{
+    SOCKET s = (SOCKET) jlong_to_ptr(socket);
+    WSABUF* lpWsaBuf = (WSABUF*) jlong_to_ptr(address);
+    OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov);
+    BOOL res;
+    DWORD nread = 0;
+    DWORD flags = 0;
+
+    ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED));
+    res = WSARecv(s,
+                  lpWsaBuf,
+                  (DWORD)count,
+                  &nread,
+                  &flags,
+                  lpOverlapped,
+                  NULL);
+
+    if (res == SOCKET_ERROR) {
+        int error = WSAGetLastError();
+        if (error == WSA_IO_PENDING) {
+            return IOS_UNAVAILABLE;
+        }
+        if (error == WSAESHUTDOWN) {
+            return 0;       // input shutdown
+        }
+        JNU_ThrowIOExceptionWithLastError(env, "WSARecv failed");
+        return IOS_THROWN;
+    }
+    if (nread == 0) {
+        // Handle graceful close or bytes not yet available cases
+        // via completion port notification.
+        return IOS_UNAVAILABLE;
+    }
+    return (jint)nread;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_write0(JNIEnv* env, jclass this,
+    jlong socket, jint count, jlong address, jlong ov)
+{
+    SOCKET s = (SOCKET) jlong_to_ptr(socket);
+    WSABUF* lpWsaBuf = (WSABUF*) jlong_to_ptr(address);
+    OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov);
+    BOOL res;
+    DWORD nwritten;
+
+    ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED));
+    res = WSASend(s,
+                  lpWsaBuf,
+                  (DWORD)count,
+                  &nwritten,
+                  0,
+                  lpOverlapped,
+                  NULL);
+
+    if (res == SOCKET_ERROR) {
+        int error = WSAGetLastError();
+        if (error == WSA_IO_PENDING) {
+            return IOS_UNAVAILABLE;
+        }
+        if (error == WSAESHUTDOWN) {
+            return IOS_EOF;     // output shutdown
+        }
+        JNU_ThrowIOExceptionWithLastError(env, "WSASend failed");
+        return IOS_THROWN;
+    }
+    return (jint)nwritten;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/native/sun/nio/fs/RegistryFileTypeDetector.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <windows.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jlong.h"
+
+#include "sun_nio_fs_RegistryFileTypeDetector.h"
+
+
+JNIEXPORT jstring JNICALL
+Java_sun_nio_fs_RegistryFileTypeDetector_queryStringValue(JNIEnv* env, jclass this,
+    jlong keyAddress, jlong nameAddress)
+{
+    LPCWSTR lpSubKey= (LPCWSTR)jlong_to_ptr(keyAddress);
+    LPWSTR lpValueName = (LPWSTR)jlong_to_ptr(nameAddress);
+    LONG res;
+    HKEY hKey;
+    jstring result = NULL;
+
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, lpSubKey, 0, KEY_READ, &hKey);
+    if (res == ERROR_SUCCESS) {
+        DWORD type;
+        BYTE data[255];
+        DWORD size = sizeof(data);
+
+        res = RegQueryValueExW(hKey, lpValueName, NULL, &type, (LPBYTE)&data, &size);
+        if (res == ERROR_SUCCESS) {
+            if (type == REG_SZ) {
+                jsize len = wcslen((WCHAR*)data);
+                result = (*env)->NewString(env, (const jchar*)&data, len);
+            }
+        }
+
+        RegCloseKey(hKey);
+    }
+    return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,1345 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <direct.h>
+#include <malloc.h>
+#include <io.h>
+#include <windows.h>
+#include <aclapi.h>
+#include <winioctl.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jlong.h"
+
+#include "sun_nio_fs_WindowsNativeDispatcher.h"
+
+/**
+ * jfieldIDs
+ */
+static jfieldID findFirst_handle;
+static jfieldID findFirst_name;
+
+static jfieldID findStream_handle;
+static jfieldID findStream_name;
+
+static jfieldID volumeInfo_fsName;
+static jfieldID volumeInfo_volName;
+static jfieldID volumeInfo_volSN;
+static jfieldID volumeInfo_flags;
+
+static jfieldID diskSpace_bytesAvailable;
+static jfieldID diskSpace_totalBytes;
+static jfieldID diskSpace_totalFree;
+
+static jfieldID account_domain;
+static jfieldID account_name;
+static jfieldID account_use;
+
+static jfieldID aclInfo_aceCount;
+
+static jfieldID completionStatus_error;
+static jfieldID completionStatus_bytesTransferred;
+static jfieldID completionStatus_completionKey;
+
+static jfieldID backupResult_bytesTransferred;
+static jfieldID backupResult_context;
+
+
+/**
+ * Win32 APIs not defined in Visual Studio 2003 header files
+ */
+
+typedef enum {
+  FindStreamInfoStandard
+} MY_STREAM_INFO_LEVELS;
+
+typedef struct _MY_WIN32_FIND_STREAM_DATA {
+  LARGE_INTEGER StreamSize;
+  WCHAR cStreamName[MAX_PATH + 36];
+} MY_WIN32_FIND_STREAM_DATA;
+
+typedef HANDLE (WINAPI* FindFirstStream_Proc)(LPCWSTR, MY_STREAM_INFO_LEVELS, LPVOID, DWORD);
+typedef BOOL (WINAPI* FindNextStream_Proc)(HANDLE, LPVOID);
+
+typedef BOOLEAN (WINAPI* CreateSymbolicLinkProc) (LPCWSTR, LPCWSTR, DWORD);
+typedef BOOL (WINAPI* CreateHardLinkProc) (LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
+typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD);
+
+typedef BOOL (WINAPI* ConvertSidToStringSidProc) (PSID, LPWSTR*);
+typedef BOOL (WINAPI* ConvertStringSidToSidProc) (LPWSTR, PSID*);
+typedef DWORD (WINAPI* GetLengthSidProc) (PSID);
+
+static FindFirstStream_Proc FindFirstStream_func;
+static FindNextStream_Proc FindNextStream_func;
+
+static CreateSymbolicLinkProc CreateSymbolicLink_func;
+static CreateHardLinkProc CreateHardLink_func;
+static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func;
+
+static ConvertSidToStringSidProc ConvertSidToStringSid_func;
+static ConvertStringSidToSidProc ConvertStringSidToSid_func;
+static GetLengthSidProc GetLengthSid_func;
+
+static void throwWindowsException(JNIEnv* env, DWORD lastError) {
+    jobject x = JNU_NewObjectByName(env, "sun/nio/fs/WindowsException",
+        "(I)V", lastError);
+    if (x != NULL) {
+        (*env)->Throw(env, x);
+    }
+}
+
+/**
+ * Initializes jfieldIDs and get address of Win32 calls that are located
+ * at runtime.
+ */
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this)
+{
+    jclass clazz;
+    HMODULE h;
+
+    clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstFile");
+    if (clazz == NULL) {
+        return;
+    }
+    findFirst_handle = (*env)->GetFieldID(env, clazz, "handle", "J");
+    findFirst_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;");
+
+    clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstStream");
+    if (clazz == NULL) {
+        return;
+    }
+    findStream_handle = (*env)->GetFieldID(env, clazz, "handle", "J");
+    findStream_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;");
+
+    clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$VolumeInformation");
+    if (clazz == NULL) {
+        return;
+    }
+    volumeInfo_fsName = (*env)->GetFieldID(env, clazz, "fileSystemName", "Ljava/lang/String;");
+    volumeInfo_volName = (*env)->GetFieldID(env, clazz, "volumeName", "Ljava/lang/String;");
+    volumeInfo_volSN = (*env)->GetFieldID(env, clazz, "volumeSerialNumber", "I");
+    volumeInfo_flags = (*env)->GetFieldID(env, clazz, "flags", "I");
+
+    clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$DiskFreeSpace");
+    if (clazz == NULL) {
+        return;
+    }
+    diskSpace_bytesAvailable = (*env)->GetFieldID(env, clazz, "freeBytesAvailable", "J");
+    diskSpace_totalBytes = (*env)->GetFieldID(env, clazz, "totalNumberOfBytes", "J");
+    diskSpace_totalFree = (*env)->GetFieldID(env, clazz, "totalNumberOfFreeBytes", "J");
+
+    clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$Account");
+    if (clazz == NULL) {
+        return;
+    }
+    account_domain = (*env)->GetFieldID(env, clazz, "domain", "Ljava/lang/String;");
+    account_name = (*env)->GetFieldID(env, clazz, "name", "Ljava/lang/String;");
+    account_use = (*env)->GetFieldID(env, clazz, "use", "I");
+
+    clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$AclInformation");
+    if (clazz == NULL) {
+        return;
+    }
+    aclInfo_aceCount = (*env)->GetFieldID(env, clazz, "aceCount", "I");
+
+    clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$CompletionStatus");
+    if (clazz == NULL) {
+        return;
+    }
+    completionStatus_error = (*env)->GetFieldID(env, clazz, "error", "I");
+    completionStatus_bytesTransferred = (*env)->GetFieldID(env, clazz, "bytesTransferred", "I");
+    completionStatus_completionKey = (*env)->GetFieldID(env, clazz, "completionKey", "I");
+
+    clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$BackupResult");
+    if (clazz == NULL) {
+        return;
+    }
+    backupResult_bytesTransferred = (*env)->GetFieldID(env, clazz, "bytesTransferred", "I");
+    backupResult_context = (*env)->GetFieldID(env, clazz, "context", "J");
+
+
+    h = LoadLibrary("kernel32");
+    if (h != INVALID_HANDLE_VALUE) {
+        FindFirstStream_func =
+            (FindFirstStream_Proc)GetProcAddress(h, "FindFirstStreamW");
+        FindNextStream_func =
+            (FindNextStream_Proc)GetProcAddress(h, "FindNextStreamW");
+        CreateSymbolicLink_func =
+            (CreateSymbolicLinkProc)GetProcAddress(h, "CreateSymbolicLinkW");
+        CreateHardLink_func =
+            (CreateHardLinkProc)GetProcAddress(h, "CreateHardLinkW");
+        GetFinalPathNameByHandle_func =
+            (GetFinalPathNameByHandleProc)GetProcAddress(h, "GetFinalPathNameByHandleW");
+        FreeLibrary(h);
+    }
+
+    h = LoadLibrary("advapi32");
+    if (h != INVALID_HANDLE_VALUE) {
+        ConvertSidToStringSid_func =
+            (ConvertSidToStringSidProc)GetProcAddress(h, "ConvertSidToStringSidW");
+        ConvertStringSidToSid_func =
+            (ConvertStringSidToSidProc)GetProcAddress(h, "ConvertStringSidToSidW");
+        GetLengthSid_func =
+            (GetLengthSidProc)GetProcAddress(h, "GetLengthSid");
+        FreeLibrary(h);
+    }
+
+}
+
+JNIEXPORT jstring JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_FormatMessage(JNIEnv* env, jclass this, jint errorCode) {
+    WCHAR message[255];
+
+    DWORD len = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
+                               NULL,
+                               (DWORD)errorCode,
+                               0,
+                               &message[0],
+                               255,
+                               NULL);
+
+
+    if (len == 0) {
+        return NULL;
+    } else {
+        return (*env)->NewString(env, (const jchar *)message, (jsize)wcslen(message));
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_LocalFree(JNIEnv* env, jclass this, jlong address)
+{
+    HLOCAL hMem = (HLOCAL)jlong_to_ptr(address);
+    LocalFree(hMem);
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_CreateFile0(JNIEnv* env, jclass this,
+    jlong address, jint dwDesiredAccess, jint dwShareMode, jlong sdAddress,
+    jint dwCreationDisposition, jint dwFlagsAndAttributes)
+{
+    HANDLE handle;
+    LPCWSTR lpFileName = jlong_to_ptr(address);
+
+    SECURITY_ATTRIBUTES securityAttributes;
+    LPSECURITY_ATTRIBUTES lpSecurityAttributes;
+    PSECURITY_DESCRIPTOR lpSecurityDescriptor = jlong_to_ptr(sdAddress);
+
+
+    if (lpSecurityDescriptor == NULL) {
+        lpSecurityAttributes = NULL;
+    } else {
+        securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+        securityAttributes.lpSecurityDescriptor = lpSecurityDescriptor;
+        securityAttributes.bInheritHandle = FALSE;
+        lpSecurityAttributes = &securityAttributes;
+    }
+
+    handle = CreateFileW(lpFileName,
+                        (DWORD)dwDesiredAccess,
+                        (DWORD)dwShareMode,
+                        lpSecurityAttributes,
+                        (DWORD)dwCreationDisposition,
+                        (DWORD)dwFlagsAndAttributes,
+                        NULL);
+    if (handle == INVALID_HANDLE_VALUE) {
+        throwWindowsException(env, GetLastError());
+    }
+    return ptr_to_jlong(handle);
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_DeviceIoControlSetSparse(JNIEnv* env, jclass this,
+    jlong handle)
+{
+    DWORD bytesReturned;
+    HANDLE h = (HANDLE)jlong_to_ptr(handle);
+    if (DeviceIoControl(h, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &bytesReturned, NULL) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_DeviceIoControlGetReparsePoint(JNIEnv* env, jclass this,
+    jlong handle, jlong bufferAddress, jint bufferSize)
+{
+    DWORD bytesReturned;
+    HANDLE h = (HANDLE)jlong_to_ptr(handle);
+    LPVOID outBuffer = (LPVOID)jlong_to_ptr(bufferAddress);
+
+    if (DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, outBuffer, (DWORD)bufferSize,
+                        &bytesReturned, NULL) == 0)
+    {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_DeleteFile0(JNIEnv* env, jclass this, jlong address)
+{
+    LPCWSTR lpFileName = jlong_to_ptr(address);
+    if (DeleteFileW(lpFileName) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_CreateDirectory0(JNIEnv* env, jclass this,
+    jlong address, jlong sdAddress)
+{
+    LPCWSTR lpFileName = jlong_to_ptr(address);
+
+    SECURITY_ATTRIBUTES securityAttributes;
+    LPSECURITY_ATTRIBUTES lpSecurityAttributes;
+    PSECURITY_DESCRIPTOR lpSecurityDescriptor = jlong_to_ptr(sdAddress);
+
+
+    if (lpSecurityDescriptor == NULL) {
+        lpSecurityAttributes = NULL;
+    } else {
+        securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+        securityAttributes.lpSecurityDescriptor = lpSecurityDescriptor;
+        securityAttributes.bInheritHandle = FALSE;
+        lpSecurityAttributes = &securityAttributes;
+    }
+
+    if (CreateDirectoryW(lpFileName, lpSecurityAttributes) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_RemoveDirectory0(JNIEnv* env, jclass this, jlong address)
+{
+    LPCWSTR lpFileName = jlong_to_ptr(address);
+    if (RemoveDirectoryW(lpFileName) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_CloseHandle(JNIEnv* env, jclass this,
+    jlong handle)
+{
+    HANDLE h = (HANDLE)jlong_to_ptr(handle);
+    CloseHandle(h);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile0(JNIEnv* env, jclass this,
+    jlong address, jobject obj)
+{
+    WIN32_FIND_DATAW data;
+    LPCWSTR lpFileName = jlong_to_ptr(address);
+
+    HANDLE handle = FindFirstFileW(lpFileName, &data);
+    if (handle != INVALID_HANDLE_VALUE) {
+        jstring name = (*env)->NewString(env, data.cFileName, wcslen(data.cFileName));
+        if (name == NULL)
+            return;
+        (*env)->SetLongField(env, obj, findFirst_handle, ptr_to_jlong(handle));
+        (*env)->SetObjectField(env, obj, findFirst_name, name);
+    } else {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstFile1(JNIEnv* env, jclass this,
+    jlong pathAddress, jlong dataAddress)
+{
+    LPCWSTR lpFileName = jlong_to_ptr(pathAddress);
+    WIN32_FIND_DATAW* data = (WIN32_FIND_DATAW*)jlong_to_ptr(dataAddress);
+
+    HANDLE handle = FindFirstFileW(lpFileName, data);
+    if (handle == INVALID_HANDLE_VALUE) {
+        throwWindowsException(env, GetLastError());
+    }
+        return ptr_to_jlong(handle);
+}
+
+JNIEXPORT jstring JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_FindNextFile(JNIEnv* env, jclass this,
+    jlong handle)
+{
+    WIN32_FIND_DATAW data;
+    HANDLE h = (HANDLE)jlong_to_ptr(handle);
+
+    if (FindNextFileW(h, &data) != 0) {
+        return (*env)->NewString(env, data.cFileName, wcslen(data.cFileName));
+    } else {
+        if (GetLastError() != ERROR_NO_MORE_FILES)
+            throwWindowsException(env, GetLastError());
+        return NULL;
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstStream0(JNIEnv* env, jclass this,
+    jlong address, jobject obj)
+{
+    MY_WIN32_FIND_STREAM_DATA data;
+    LPCWSTR lpFileName = jlong_to_ptr(address);
+    HANDLE handle;
+
+    if (FindFirstStream_func == NULL) {
+        JNU_ThrowInternalError(env, "Should not get here");
+        return;
+    }
+
+    handle = (*FindFirstStream_func)(lpFileName, FindStreamInfoStandard, &data, 0);
+    if (handle != INVALID_HANDLE_VALUE) {
+        jstring name = (*env)->NewString(env, data.cStreamName, wcslen(data.cStreamName));
+        if (name == NULL)
+            return;
+        (*env)->SetLongField(env, obj, findStream_handle, ptr_to_jlong(handle));
+        (*env)->SetObjectField(env, obj, findStream_name, name);
+    } else {
+        if (GetLastError() == ERROR_HANDLE_EOF) {
+             (*env)->SetLongField(env, obj, findStream_handle, ptr_to_jlong(handle));
+        } else {
+            throwWindowsException(env, GetLastError());
+        }
+    }
+
+}
+
+JNIEXPORT jstring JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_FindNextStream(JNIEnv* env, jclass this,
+    jlong handle)
+{
+    MY_WIN32_FIND_STREAM_DATA data;
+    HANDLE h = (HANDLE)jlong_to_ptr(handle);
+
+    if (FindNextStream_func == NULL) {
+        JNU_ThrowInternalError(env, "Should not get here");
+        return NULL;
+    }
+
+    if ((*FindNextStream_func)(h, &data) != 0) {
+        return (*env)->NewString(env, data.cStreamName, wcslen(data.cStreamName));
+    } else {
+        if (GetLastError() != ERROR_HANDLE_EOF)
+            throwWindowsException(env, GetLastError());
+        return NULL;
+    }
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_FindClose(JNIEnv* env, jclass this,
+    jlong handle)
+{
+    HANDLE h = (HANDLE)jlong_to_ptr(handle);
+    if (FindClose(h) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetFileInformationByHandle(JNIEnv* env, jclass this,
+    jlong handle, jlong address)
+{
+    HANDLE h = (HANDLE)jlong_to_ptr(handle);
+    BY_HANDLE_FILE_INFORMATION* info =
+        (BY_HANDLE_FILE_INFORMATION*)jlong_to_ptr(address);
+    if (GetFileInformationByHandle(h, info) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_CopyFileEx0(JNIEnv* env, jclass this,
+    jlong existingAddress, jlong newAddress, jint flags, jlong cancelAddress)
+{
+    LPCWSTR lpExistingFileName = jlong_to_ptr(existingAddress);
+    LPCWSTR lpNewFileName = jlong_to_ptr(newAddress);
+    LPBOOL cancel = (LPBOOL)jlong_to_ptr(cancelAddress);
+    if (CopyFileExW(lpExistingFileName, lpNewFileName, NULL, NULL, cancel,
+                    (DWORD)flags) == 0)
+    {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_MoveFileEx0(JNIEnv* env, jclass this,
+    jlong existingAddress, jlong newAddress, jint flags)
+{
+    LPCWSTR lpExistingFileName = jlong_to_ptr(existingAddress);
+    LPCWSTR lpNewFileName = jlong_to_ptr(newAddress);
+    if (MoveFileExW(lpExistingFileName, lpNewFileName, (DWORD)flags) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetLogicalDrives(JNIEnv* env, jclass this)
+{
+    DWORD res = GetLogicalDrives();
+    if (res == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+    return (jint)res;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetFileAttributes0(JNIEnv* env, jclass this,
+    jlong address)
+{
+    LPCWSTR lpFileName = jlong_to_ptr(address);
+    DWORD value = GetFileAttributesW(lpFileName);
+
+    if (value == INVALID_FILE_ATTRIBUTES) {
+        throwWindowsException(env, GetLastError());
+    }
+    return (jint)value;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_SetFileAttributes0(JNIEnv* env, jclass this,
+    jlong address, jint value)
+{
+    LPCWSTR lpFileName = jlong_to_ptr(address);
+    if (SetFileAttributesW(lpFileName, (DWORD)value) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetFileAttributesEx0(JNIEnv* env, jclass this,
+    jlong pathAddress, jlong dataAddress)
+{
+    LPCWSTR lpFileName = jlong_to_ptr(pathAddress);
+    WIN32_FILE_ATTRIBUTE_DATA* data = (WIN32_FILE_ATTRIBUTE_DATA*)jlong_to_ptr(dataAddress);
+
+    BOOL res = GetFileAttributesExW(lpFileName, GetFileExInfoStandard, (LPVOID)data);
+    if (res == 0)
+        throwWindowsException(env, GetLastError());
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_SetFileTime(JNIEnv* env, jclass this,
+    jlong handle, jlong createTime, jlong lastAccessTime, jlong lastWriteTime)
+{
+    HANDLE h = (HANDLE)jlong_to_ptr(handle);
+
+    if (SetFileTime(h,
+        (createTime == (jlong)0) ? NULL : (CONST FILETIME *)&createTime,
+        (lastAccessTime == (jlong)0) ? NULL : (CONST FILETIME *)&lastAccessTime,
+        (lastWriteTime == (jlong)0) ? NULL : (CONST FILETIME *)&lastWriteTime) == 0)
+    {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_SetEndOfFile(JNIEnv* env, jclass this,
+    jlong handle)
+{
+    HANDLE h = (HANDLE)jlong_to_ptr(handle);
+
+    if (SetEndOfFile(h) == 0)
+        throwWindowsException(env, GetLastError());
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetVolumeInformation0(JNIEnv* env, jclass this,
+    jlong address, jobject obj)
+{
+    WCHAR volumeName[MAX_PATH+1];
+    DWORD volumeSerialNumber;
+    DWORD maxComponentLength;
+    DWORD flags;
+    WCHAR fileSystemName[MAX_PATH+1];
+    LPCWSTR lpFileName = jlong_to_ptr(address);
+    jstring str;
+
+    BOOL res = GetVolumeInformationW(lpFileName,
+                                     &volumeName[0],
+                                     MAX_PATH+1,
+                                     &volumeSerialNumber,
+                                     &maxComponentLength,
+                                     &flags,
+                                     &fileSystemName[0],
+                                     MAX_PATH+1);
+    if (res == 0) {
+        throwWindowsException(env, GetLastError());
+        return;
+    }
+
+    str = (*env)->NewString(env, (const jchar *)fileSystemName, (jsize)wcslen(fileSystemName));
+    if (str == NULL) return;
+    (*env)->SetObjectField(env, obj, volumeInfo_fsName, str);
+
+    str = (*env)->NewString(env, (const jchar *)volumeName, (jsize)wcslen(volumeName));
+    if (str == NULL) return;
+    (*env)->SetObjectField(env, obj, volumeInfo_volName, str);
+
+    (*env)->SetIntField(env, obj, volumeInfo_volSN, (jint)volumeSerialNumber);
+    (*env)->SetIntField(env, obj, volumeInfo_flags, (jint)flags);
+}
+
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetDriveType0(JNIEnv* env, jclass this, jlong address) {
+    LPCWSTR lpRootPathName = jlong_to_ptr(address);
+    return (jint)GetDriveTypeW(lpRootPathName);
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetDiskFreeSpaceEx0(JNIEnv* env, jclass this,
+    jlong address, jobject obj)
+{
+    ULARGE_INTEGER freeBytesAvailable;
+    ULARGE_INTEGER totalNumberOfBytes;
+    ULARGE_INTEGER totalNumberOfFreeBytes;
+    LPCWSTR lpDirName = jlong_to_ptr(address);
+
+
+    BOOL res = GetDiskFreeSpaceExW(lpDirName,
+                                   &freeBytesAvailable,
+                                   &totalNumberOfBytes,
+                                   &totalNumberOfFreeBytes);
+    if (res == 0) {
+        throwWindowsException(env, GetLastError());
+        return;
+    }
+
+    (*env)->SetLongField(env, obj, diskSpace_bytesAvailable,
+        long_to_jlong(freeBytesAvailable.QuadPart));
+    (*env)->SetLongField(env, obj, diskSpace_totalBytes,
+        long_to_jlong(totalNumberOfBytes.QuadPart));
+    (*env)->SetLongField(env, obj, diskSpace_totalFree,
+        long_to_jlong(totalNumberOfFreeBytes.QuadPart));
+}
+
+
+JNIEXPORT jstring JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetVolumePathName0(JNIEnv* env, jclass this,
+    jlong address)
+{
+    WCHAR volumeName[MAX_PATH+1];
+    LPCWSTR lpFileName = jlong_to_ptr(address);
+
+
+    BOOL res = GetVolumePathNameW(lpFileName,
+                                  &volumeName[0],
+                                  MAX_PATH+1);
+    if (res == 0) {
+        throwWindowsException(env, GetLastError());
+        return NULL;
+    } else {
+        return (*env)->NewString(env, (const jchar *)volumeName, (jsize)wcslen(volumeName));
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_InitializeSecurityDescriptor(JNIEnv* env, jclass this,
+    jlong address)
+{
+    PSECURITY_DESCRIPTOR pSecurityDescriptor =
+        (PSECURITY_DESCRIPTOR)jlong_to_ptr(address);
+
+    if (InitializeSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_InitializeAcl(JNIEnv* env, jclass this,
+    jlong address, jint size)
+{
+    PACL pAcl = (PACL)jlong_to_ptr(address);
+
+    if (InitializeAcl(pAcl, (DWORD)size, ACL_REVISION) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_SetFileSecurity0(JNIEnv* env, jclass this,
+    jlong pathAddress, jint requestedInformation, jlong descAddress)
+{
+    LPCWSTR lpFileName = jlong_to_ptr(pathAddress);
+    PSECURITY_DESCRIPTOR pSecurityDescriptor = jlong_to_ptr(descAddress);
+    DWORD lengthNeeded = 0;
+
+    BOOL res = SetFileSecurityW(lpFileName,
+                                (SECURITY_INFORMATION)requestedInformation,
+                                pSecurityDescriptor);
+
+    if (res == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetFileSecurity0(JNIEnv* env, jclass this,
+    jlong pathAddress, jint requestedInformation, jlong descAddress, jint nLength)
+{
+    LPCWSTR lpFileName = jlong_to_ptr(pathAddress);
+    PSECURITY_DESCRIPTOR pSecurityDescriptor = jlong_to_ptr(descAddress);
+    DWORD lengthNeeded = 0;
+
+    BOOL res = GetFileSecurityW(lpFileName,
+                                (SECURITY_INFORMATION)requestedInformation,
+                                pSecurityDescriptor,
+                                (DWORD)nLength,
+                                &lengthNeeded);
+
+    if (res == 0) {
+        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+            return (jint)lengthNeeded;
+        } else {
+            throwWindowsException(env, GetLastError());
+            return 0;
+        }
+    } else {
+        return (jint)nLength;
+    }
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetSecurityDescriptorOwner(JNIEnv* env,
+    jclass this, jlong address)
+{
+    PSECURITY_DESCRIPTOR pSecurityDescriptor = jlong_to_ptr(address);
+    PSID pOwner;
+    BOOL bOwnerDefaulted;
+
+
+    if (GetSecurityDescriptorOwner(pSecurityDescriptor, &pOwner, &bOwnerDefaulted) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+    return ptr_to_jlong(pOwner);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_SetSecurityDescriptorOwner(JNIEnv* env,
+    jclass this, jlong descAddress, jlong ownerAddress)
+{
+    PSECURITY_DESCRIPTOR pSecurityDescriptor = jlong_to_ptr(descAddress);
+    PSID pOwner = jlong_to_ptr(ownerAddress);
+
+    if (SetSecurityDescriptorOwner(pSecurityDescriptor, pOwner, FALSE) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetSecurityDescriptorDacl(JNIEnv* env,
+    jclass this, jlong address)
+{
+    PSECURITY_DESCRIPTOR pSecurityDescriptor = jlong_to_ptr(address);
+    BOOL bDaclPresent;
+    PACL pDacl;
+    BOOL bDaclDefaulted;
+
+    if (GetSecurityDescriptorDacl(pSecurityDescriptor, &bDaclPresent, &pDacl, &bDaclDefaulted) == 0) {
+        throwWindowsException(env, GetLastError());
+        return (jlong)0;
+    } else {
+        return (bDaclPresent) ? ptr_to_jlong(pDacl) : (jlong)0;
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_SetSecurityDescriptorDacl(JNIEnv* env,
+    jclass this, jlong descAddress, jlong aclAddress)
+{
+    PSECURITY_DESCRIPTOR pSecurityDescriptor = (PSECURITY_DESCRIPTOR)jlong_to_ptr(descAddress);
+    PACL pAcl = (PACL)jlong_to_ptr(aclAddress);
+
+    if (SetSecurityDescriptorDacl(pSecurityDescriptor, TRUE, pAcl, FALSE) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetAclInformation0(JNIEnv* env,
+    jclass this, jlong address, jobject obj)
+{
+    PACL pAcl = (PACL)jlong_to_ptr(address);
+    ACL_SIZE_INFORMATION acl_size_info;
+
+    if (GetAclInformation(pAcl, (void *) &acl_size_info, sizeof(acl_size_info), AclSizeInformation) == 0) {
+        throwWindowsException(env, GetLastError());
+    } else {
+        (*env)->SetIntField(env, obj, aclInfo_aceCount, (jint)acl_size_info.AceCount);
+    }
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetAce(JNIEnv* env, jclass this, jlong address,
+    jint aceIndex)
+{
+    PACL pAcl = (PACL)jlong_to_ptr(address);
+    LPVOID pAce;
+
+    if (GetAce(pAcl, (DWORD)aceIndex, &pAce) == 0) {
+        throwWindowsException(env, GetLastError());
+        return (jlong)0;
+    } else {
+        return ptr_to_jlong(pAce);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_AddAccessAllowedAceEx(JNIEnv* env,
+    jclass this, jlong aclAddress, jint flags, jint mask, jlong sidAddress)
+{
+    PACL pAcl = (PACL)jlong_to_ptr(aclAddress);
+    PSID pSid = (PSID)jlong_to_ptr(sidAddress);
+
+    if (AddAccessAllowedAceEx(pAcl, ACL_REVISION, (DWORD)flags, (DWORD)mask, pSid) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_AddAccessDeniedAceEx(JNIEnv* env,
+    jclass this, jlong aclAddress, jint flags, jint mask, jlong sidAddress)
+{
+    PACL pAcl = (PACL)jlong_to_ptr(aclAddress);
+    PSID pSid = (PSID)jlong_to_ptr(sidAddress);
+
+    if (AddAccessDeniedAceEx(pAcl, ACL_REVISION, (DWORD)flags, (DWORD)mask, pSid) == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_LookupAccountSid0(JNIEnv* env,
+    jclass this, jlong address, jobject obj)
+{
+    WCHAR domain[255];
+    WCHAR name[255];
+    DWORD domainLen = sizeof(domain);
+    DWORD nameLen = sizeof(name);
+    SID_NAME_USE use;
+    PSID sid = jlong_to_ptr(address);
+    jstring s;
+
+    if (LookupAccountSidW(NULL, sid, &name[0], &nameLen, &domain[0], &domainLen, &use) == 0) {
+        throwWindowsException(env, GetLastError());
+        return;
+    }
+
+    s = (*env)->NewString(env, (const jchar *)domain, (jsize)wcslen(domain));
+    if (s == NULL)
+        return;
+    (*env)->SetObjectField(env, obj, account_domain, s);
+
+    s = (*env)->NewString(env, (const jchar *)name, (jsize)wcslen(name));
+    if (s == NULL)
+        return;
+    (*env)->SetObjectField(env, obj, account_name, s);
+    (*env)->SetIntField(env, obj, account_use, (jint)use);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_LookupAccountName0(JNIEnv* env,
+    jclass this, jlong nameAddress, jlong sidAddress, jint cbSid)
+{
+
+    LPCWSTR accountName = jlong_to_ptr(nameAddress);
+    PSID sid = jlong_to_ptr(sidAddress);
+    WCHAR domain[255];
+    DWORD domainLen = sizeof(domain);
+    SID_NAME_USE use;
+
+    if (LookupAccountNameW(NULL, accountName, sid, (LPDWORD)&cbSid,
+                           &domain[0], &domainLen, &use) == 0)
+    {
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+            throwWindowsException(env, GetLastError());
+        }
+    }
+
+    return cbSid;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetLengthSid(JNIEnv* env,
+    jclass this, jlong address)
+{
+    PSID sid = jlong_to_ptr(address);
+
+    if (GetLengthSid_func == NULL) {
+        JNU_ThrowInternalError(env, "Should not get here");
+        return 0;
+    }
+    return (jint)(*GetLengthSid_func)(sid);
+}
+
+
+JNIEXPORT jstring JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_ConvertSidToStringSid(JNIEnv* env,
+    jclass this, jlong address)
+{
+    PSID sid = jlong_to_ptr(address);
+    LPWSTR string;
+
+    if (ConvertSidToStringSid_func == NULL) {
+        JNU_ThrowInternalError(env, "Should not get here");
+        return NULL;
+    }
+
+    if ((*ConvertSidToStringSid_func)(sid, &string) == 0) {
+        throwWindowsException(env, GetLastError());
+        return NULL;
+    } else {
+        jstring s = (*env)->NewString(env, (const jchar *)string,
+            (jsize)wcslen(string));
+        LocalFree(string);
+        return s;
+    }
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_ConvertStringSidToSid0(JNIEnv* env,
+    jclass this, jlong address)
+{
+    LPWSTR lpStringSid = jlong_to_ptr(address);
+    PSID pSid;
+
+    if (ConvertStringSidToSid_func == NULL) {
+        JNU_ThrowInternalError(env, "Should not get here");
+        return (jlong)0;
+    }
+
+    if ((*ConvertStringSidToSid_func)(lpStringSid, &pSid) == 0)
+        throwWindowsException(env, GetLastError());
+
+    return ptr_to_jlong(pSid);
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetCurrentProcess(JNIEnv* env, jclass this) {
+    HANDLE hProcess = GetCurrentProcess();
+    return ptr_to_jlong(hProcess);
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetCurrentThread(JNIEnv* env, jclass this) {
+    HANDLE hThread = GetCurrentThread();
+    return ptr_to_jlong(hThread);
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_OpenProcessToken(JNIEnv* env,
+    jclass this, jlong process, jint desiredAccess)
+{
+    HANDLE hProcess = (HANDLE)jlong_to_ptr(process);
+    HANDLE hToken;
+
+    if (OpenProcessToken(hProcess, (DWORD)desiredAccess, &hToken) == 0)
+        throwWindowsException(env, GetLastError());
+    return ptr_to_jlong(hToken);
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_OpenThreadToken(JNIEnv* env,
+    jclass this, jlong thread, jint desiredAccess, jboolean openAsSelf)
+{
+    HANDLE hThread = (HANDLE)jlong_to_ptr(thread);
+    HANDLE hToken;
+    BOOL bOpenAsSelf = (openAsSelf == JNI_TRUE) ? TRUE : FALSE;
+
+    if (OpenThreadToken(hThread, (DWORD)desiredAccess, bOpenAsSelf, &hToken) == 0) {
+        if (GetLastError() == ERROR_NO_TOKEN)
+            return (jlong)0;
+        throwWindowsException(env, GetLastError());
+    }
+    return ptr_to_jlong(hToken);
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_DuplicateTokenEx(JNIEnv* env,
+    jclass this, jlong token, jint desiredAccess)
+{
+    HANDLE hToken = (HANDLE)jlong_to_ptr(token);
+    HANDLE resultToken;
+    BOOL res;
+
+    res = DuplicateTokenEx(hToken,
+                           (DWORD)desiredAccess,
+                           NULL,
+                           SecurityImpersonation,
+                           TokenImpersonation,
+                           &resultToken);
+    if (res == 0)
+        throwWindowsException(env, GetLastError());
+    return ptr_to_jlong(resultToken);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_SetThreadToken(JNIEnv* env,
+    jclass this, jlong thread, jlong token)
+{
+    HANDLE hThread = (HANDLE)jlong_to_ptr(thread);
+    HANDLE hToken = (HANDLE)jlong_to_ptr(token);
+
+    if (SetThreadToken(hThread, hToken) == 0)
+        throwWindowsException(env, GetLastError());
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetTokenInformation(JNIEnv* env,
+    jclass this, jlong token, jint tokenInfoClass, jlong tokenInfo, jint tokenInfoLength)
+{
+    BOOL res;
+    DWORD lengthNeeded;
+    HANDLE hToken = (HANDLE)jlong_to_ptr(token);
+    LPVOID result = (LPVOID)jlong_to_ptr(tokenInfo);
+
+    res = GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)tokenInfoClass, (LPVOID)result,
+                              tokenInfoLength, &lengthNeeded);
+    if (res == 0) {
+        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+            return (jint)lengthNeeded;
+        } else {
+            throwWindowsException(env, GetLastError());
+            return 0;
+        }
+    } else {
+        return tokenInfoLength;
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_AdjustTokenPrivileges(JNIEnv* env,
+    jclass this, jlong token, jlong luid, jint attributes)
+{
+    TOKEN_PRIVILEGES privs[1];
+    HANDLE hToken = (HANDLE)jlong_to_ptr(token);
+    PLUID pLuid = (PLUID)jlong_to_ptr(luid);
+
+    privs[0].PrivilegeCount = 1;
+    privs[0].Privileges[0].Luid = *pLuid;
+    privs[0].Privileges[0].Attributes = (DWORD)attributes;
+
+    if (AdjustTokenPrivileges(hToken, FALSE, &privs[0], 1, NULL, NULL) == 0)
+        throwWindowsException(env, GetLastError());
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_LookupPrivilegeValue0(JNIEnv* env,
+    jclass this, jlong name)
+{
+    LPCWSTR lpName = (LPCWSTR)jlong_to_ptr(name);
+    PLUID pLuid = LocalAlloc(0, sizeof(LUID));
+
+    if (pLuid == NULL) {
+        JNU_ThrowInternalError(env, "Unable to allocate LUID structure");
+    } else {
+        if (LookupPrivilegeValueW(NULL, lpName, pLuid) == 0)
+            throwWindowsException(env, GetLastError());
+    }
+    return ptr_to_jlong(pLuid);
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_BuildTrusteeWithSid(JNIEnv* env,
+    jclass this, jlong sid)
+{
+    PSID pSid = (HANDLE)jlong_to_ptr(sid);
+    PTRUSTEE_W pTrustee = LocalAlloc(0, sizeof(TRUSTEE_W));
+
+    if (pTrustee == NULL) {
+        JNU_ThrowInternalError(env, "Unable to allocate TRUSTEE_W structure");
+    } else {
+        BuildTrusteeWithSidW(pTrustee, pSid);
+    }
+    return ptr_to_jlong(pTrustee);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetEffectiveRightsFromAcl(JNIEnv* env,
+    jclass this, jlong acl, jlong trustee)
+{
+    ACCESS_MASK access;
+    PACL pAcl = (PACL)jlong_to_ptr(acl);
+    PTRUSTEE pTrustee = (PTRUSTEE)jlong_to_ptr(trustee);
+
+    if (GetEffectiveRightsFromAcl(pAcl, pTrustee, &access) != ERROR_SUCCESS) {
+        throwWindowsException(env, GetLastError());
+    }
+    return (jint)access;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_CreateSymbolicLink0(JNIEnv* env,
+    jclass this, jlong linkAddress, jlong targetAddress, jint flags)
+{
+    LPCWSTR link = jlong_to_ptr(linkAddress);
+    LPCWSTR target = jlong_to_ptr(targetAddress);
+
+    if (CreateSymbolicLink_func == NULL) {
+        JNU_ThrowInternalError(env, "Should not get here");
+        return;
+    }
+
+    /* On Windows 64-bit this appears to succeed even when there is insufficient privileges */
+    if ((*CreateSymbolicLink_func)(link, target, (DWORD)flags) == 0)
+        throwWindowsException(env, GetLastError());
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_CreateHardLink0(JNIEnv* env,
+    jclass this, jlong newFileAddress, jlong existingFileAddress)
+{
+    LPCWSTR newFile = jlong_to_ptr(newFileAddress);
+    LPCWSTR existingFile = jlong_to_ptr(existingFileAddress);
+
+    if (CreateHardLink_func == NULL) {
+        JNU_ThrowInternalError(env, "Should not get here");
+        return;
+    }
+    if ((*CreateHardLink_func)(newFile, existingFile, NULL) == 0)
+        throwWindowsException(env, GetLastError());
+}
+
+JNIEXPORT jstring JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetFullPathName0(JNIEnv *env,
+                                                         jclass clz,
+                                                         jlong pathAddress)
+{
+    jstring rv = NULL;
+    WCHAR *lpBuf = NULL;
+    WCHAR buf[MAX_PATH];
+    DWORD len;
+    LPCWSTR lpFileName = jlong_to_ptr(pathAddress);
+
+    len = GetFullPathNameW(lpFileName, MAX_PATH, buf, NULL);
+    if (len > 0) {
+        if (len < MAX_PATH) {
+            rv = (*env)->NewString(env, buf, len);
+        } else {
+            len += 1;  /* return length does not include terminator */
+            lpBuf = (WCHAR*)malloc(len * sizeof(WCHAR));
+            if (lpBuf != NULL) {
+                len = GetFullPathNameW(lpFileName, len, lpBuf, NULL);
+                if (len > 0) {
+                    rv = (*env)->NewString(env, lpBuf, len);
+                } else {
+                    JNU_ThrowInternalError(env, "GetFullPathNameW failed");
+                }
+                free(lpBuf);
+            }
+        }
+    }
+    if (len == 0)
+        throwWindowsException(env, GetLastError());
+
+    return rv;
+}
+
+JNIEXPORT jstring JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetFinalPathNameByHandle(JNIEnv* env,
+    jclass this, jlong handle)
+{
+    jstring rv = NULL;
+    WCHAR *lpBuf = NULL;
+    WCHAR path[MAX_PATH];
+    HANDLE h = (HANDLE)jlong_to_ptr(handle);
+    DWORD len;
+
+    if (GetFinalPathNameByHandle_func == NULL) {
+        JNU_ThrowInternalError(env, "Should not get here");
+        return NULL;
+    }
+
+    len = (*GetFinalPathNameByHandle_func)(h, path, MAX_PATH, 0);
+    if (len > 0) {
+        if (len < MAX_PATH) {
+            rv = (*env)->NewString(env, (const jchar *)path, (jsize)len);
+        } else {
+            len += 1;  /* return length does not include terminator */
+            lpBuf = (WCHAR*)malloc(len * sizeof(WCHAR));
+            if (lpBuf != NULL) {
+                len = (*GetFinalPathNameByHandle_func)(h, lpBuf, len, 0);
+                if (len > 0)  {
+                    rv = (*env)->NewString(env, (const jchar *)lpBuf, (jsize)len);
+                } else {
+                    JNU_ThrowInternalError(env, "GetFinalPathNameByHandleW failed");
+                }
+                free(lpBuf);
+            }
+        }
+    }
+
+    if (len == 0)
+        throwWindowsException(env, GetLastError());
+
+    return rv;
+}
+
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_CreateIoCompletionPort(JNIEnv* env, jclass this,
+    jlong fileHandle, jlong existingPort, jint completionKey)
+{
+    HANDLE port = CreateIoCompletionPort((HANDLE)jlong_to_ptr(fileHandle),
+                                         (HANDLE)jlong_to_ptr(existingPort),
+                                         (DWORD)completionKey,
+                                         0);
+    if (port == NULL) {
+        throwWindowsException(env, GetLastError());
+    }
+    return ptr_to_jlong(port);
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetQueuedCompletionStatus0(JNIEnv* env, jclass this,
+    jlong completionPort, jobject obj)
+{
+    DWORD bytesTransferred;
+    DWORD completionKey;
+    OVERLAPPED *lpOverlapped;
+    BOOL res;
+
+    res = GetQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort),
+                                  &bytesTransferred,
+                                  &completionKey,
+                                  &lpOverlapped,
+                                  INFINITE);
+    if (res == 0 && lpOverlapped == NULL) {
+        throwWindowsException(env, GetLastError());
+    } else {
+        DWORD ioResult = (res == 0) ? GetLastError() : 0;
+        (*env)->SetIntField(env, obj, completionStatus_error, ioResult);
+        (*env)->SetIntField(env, obj, completionStatus_bytesTransferred,
+            (jint)bytesTransferred);
+        (*env)->SetIntField(env, obj, completionStatus_completionKey,
+            (jint)completionKey);
+
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_PostQueuedCompletionStatus(JNIEnv* env, jclass this,
+    jlong completionPort, jint completionKey)
+{
+    BOOL res;
+
+    res = PostQueuedCompletionStatus((HANDLE)jlong_to_ptr(completionPort),
+                                     (DWORD)0,  /* dwNumberOfBytesTransferred */
+                                     (DWORD)completionKey,
+                                     NULL);  /* lpOverlapped */
+    if (res == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_ReadDirectoryChangesW(JNIEnv* env, jclass this,
+    jlong hDirectory, jlong bufferAddress, jint bufferLength, jboolean watchSubTree, jint filter,
+    jlong bytesReturnedAddress, jlong pOverlapped)
+{
+    BOOL res;
+    BOOL subtree = (watchSubTree == JNI_TRUE) ? TRUE : FALSE;
+
+    ((LPOVERLAPPED)jlong_to_ptr(pOverlapped))->hEvent = NULL;
+    res = ReadDirectoryChangesW((HANDLE)jlong_to_ptr(hDirectory),
+                                (LPVOID)jlong_to_ptr(bufferAddress),
+                                (DWORD)bufferLength,
+                                subtree,
+                                (DWORD)filter,
+                                (LPDWORD)jlong_to_ptr(bytesReturnedAddress),
+                                (LPOVERLAPPED)jlong_to_ptr(pOverlapped),
+                                NULL);
+    if (res == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_BackupRead0(JNIEnv* env, jclass this,
+    jlong hFile, jlong bufferAddress, jint bufferSize, jboolean abort,
+    jlong context, jobject obj)
+{
+    BOOL res;
+    DWORD bytesTransferred;
+    BOOL a = (abort == JNI_TRUE) ? TRUE : FALSE;
+    VOID* pContext = (VOID*)jlong_to_ptr(context);
+
+    res = BackupRead((HANDLE)jlong_to_ptr(hFile),
+                     (LPBYTE)jlong_to_ptr(bufferAddress),
+                     (DWORD)bufferSize,
+                     &bytesTransferred,
+                     a,
+                     FALSE,
+                     &pContext);
+    if (res == 0) {
+        throwWindowsException(env, GetLastError());
+    } else {
+        (*env)->SetIntField(env, obj, backupResult_bytesTransferred,
+            bytesTransferred);
+        (*env)->SetLongField(env, obj, backupResult_context,
+            ptr_to_jlong(pContext));
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_BackupSeek(JNIEnv* env, jclass this,
+    jlong hFile, jlong bytesToSeek, jlong context)
+{
+    BOOL res;
+    jint lowBytesToSeek = (jint)bytesToSeek;
+    jint highBytesToSeek = (jint)(bytesToSeek >> 32);
+    DWORD lowBytesSeeked;
+    DWORD highBytesSeeked;
+    VOID* pContext = jlong_to_ptr(context);
+
+    res = BackupSeek((HANDLE)jlong_to_ptr(hFile),
+                     (DWORD)lowBytesToSeek,
+                     (DWORD)highBytesToSeek,
+                     &lowBytesSeeked,
+                     &highBytesSeeked,
+                     &pContext);
+    if (res == 0) {
+        throwWindowsException(env, GetLastError());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/AsExecutor.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.nio.channels.AsynchronousChannelGroup;
+import java.util.concurrent.*;
+
+/**
+ * Test that arbitrary tasks can be submitted to a channel group's thread pool.
+ */
+
+public class AsExecutor {
+
+    public static void main(String[] args) throws Exception {
+        // create channel groups
+        ThreadFactory factory = new PrivilegedThreadFactory();
+        AsynchronousChannelGroup group1 = AsynchronousChannelGroup
+            .withFixedThreadPool(5, factory);
+        AsynchronousChannelGroup group2 = AsynchronousChannelGroup
+            .withCachedThreadPool(Executors.newCachedThreadPool(factory), 0);
+
+        try {
+            // execute simple tasks
+            testSimpleTask(group1);
+            testSimpleTask(group2);
+
+            // install security manager and test again
+            System.setSecurityManager( new SecurityManager() );
+            testSimpleTask(group1);
+            testSimpleTask(group2);
+
+            // attempt to execute tasks that run with only frames from boot
+            // class loader on the stack.
+            testAttackingTask(group1);
+            testAttackingTask(group2);
+        } finally {
+            group1.shutdown();
+            group2.shutdown();
+        }
+    }
+
+    static void testSimpleTask(AsynchronousChannelGroup group) throws Exception {
+        Executor executor = (Executor)group;
+        final CountDownLatch latch = new CountDownLatch(1);
+        executor.execute(new Runnable() {
+            public void run() {
+                latch.countDown();
+            }
+        });
+        latch.await();
+    }
+
+    static void testAttackingTask(AsynchronousChannelGroup group) throws Exception {
+        Executor executor = (Executor)group;
+        Attack task = new Attack();
+        executor.execute(task);
+        task.waitUntilDone();
+        if (!task.failedDueToSecurityException())
+            throw new RuntimeException("SecurityException expected");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Attack.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.net.*;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * A task that attempts to attack the current host.
+ */
+
+public class Attack implements Runnable {
+    private final CountDownLatch latch = new CountDownLatch(1);
+    private volatile boolean failedDueToSecurityException;
+
+    public void Attack() {
+        // check class is on boot class path
+        if (Attack.class.getClassLoader() != null)
+            throw new RuntimeException("Attack class not on boot class path");
+    }
+
+    @Override
+    public void run() {
+        try {
+            new Socket("127.0.0.1", 9999).close();
+            throw new RuntimeException("Connected (not expected)");
+        } catch (IOException e) {
+            throw new RuntimeException("IOException (not expected)");
+        } catch (SecurityException e) {
+            failedDueToSecurityException = true;
+        } finally {
+            latch.countDown();
+        }
+    }
+
+    public void waitUntilDone() throws InterruptedException {
+        latch.await();
+    }
+
+    public boolean failedDueToSecurityException() {
+        return failedDueToSecurityException;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/BadProperties.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for AsynchronousChannelGroup
+ * @build BadProperties
+ * @run main/othervm/fail -Djava.nio.channels.DefaultThreadPool.threadFactory BadProperties
+ * @run main/othervm/fail -Djava.nio.channels.DefaultThreadPool.threadFactory=Missing BadProperties
+ * @run main/othervm/fail -Djava.nio.channels.DefaultThreadPool.initialSize BadProperties
+ * @run main/othervm/fail -Djava.nio.channels.DefaultThreadPool.initialSize=NaN BadProperties
+ */
+
+import java.nio.channels.AsynchronousSocketChannel;
+import java.io.IOException;
+
+public class BadProperties {
+    public static void main(String[] args) throws IOException {
+        AsynchronousSocketChannel.open();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for AsynchronousChannelGroup
+ * @build Basic
+ * @run main/othervm -XX:-UseVMInterruptibleIO Basic
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.io.IOException;
+
+public class Basic {
+    static final Random rand = new Random();
+    static final ThreadFactory threadFactory = new ThreadFactory() {
+        @Override
+        public Thread newThread(final Runnable r) {
+            return new Thread(r);
+        }};
+
+
+    public static void main(String[] args) throws Exception {
+        shutdownTests();
+        shutdownNowTests();
+        afterShutdownTests();
+        miscTests();
+    }
+
+    static void shutdownTests() throws Exception {
+        System.out.println("-- test shutdown --");
+
+        // test shutdown with no channels in groups
+        for (int i=0; i<500; i++) {
+            ExecutorService pool = null;
+            AsynchronousChannelGroup group;
+            if (rand.nextBoolean()) {
+                pool = Executors.newCachedThreadPool();
+                group = AsynchronousChannelGroup.withCachedThreadPool(pool, rand.nextInt(5));
+            } else {
+                int nThreads = 1 + rand.nextInt(8);
+                group = AsynchronousChannelGroup.withFixedThreadPool(nThreads, threadFactory);
+            }
+            group.shutdown();
+            if (!group.isShutdown())
+                throw new RuntimeException("Group should be shutdown");
+            // group should terminate quickly
+            boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS);
+            if (!terminated)
+                throw new RuntimeException("Group should have terminated");
+            if (pool != null && !pool.isTerminated())
+                throw new RuntimeException("Executor should have terminated");
+        }
+
+        // shutdown with channel in group
+        for (int i=0; i<500; i++) {
+            ExecutorService pool = null;
+            AsynchronousChannelGroup group;
+            if (rand.nextBoolean()) {
+                pool = Executors.newCachedThreadPool();
+                group = AsynchronousChannelGroup.withCachedThreadPool(pool, rand.nextInt(10));
+            } else {
+                int nThreads = 1 + rand.nextInt(8);
+                group = AsynchronousChannelGroup.withFixedThreadPool(nThreads, threadFactory);
+            }
+            // create channel that is bound to group
+            AsynchronousChannel ch;
+            switch (rand.nextInt(3)) {
+                case 0 : ch = AsynchronousSocketChannel.open(group); break;
+                case 1 : ch = AsynchronousServerSocketChannel.open(group); break;
+                case 2 : ch = AsynchronousDatagramChannel.open(null, group); break;
+                default : throw new AssertionError();
+            }
+            group.shutdown();
+            if (!group.isShutdown())
+                throw new RuntimeException("Group should be shutdown");
+
+            // last channel so should terminate after this channel is closed
+            ch.close();
+
+            // group should terminate quickly
+            boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS);
+            if (!terminated)
+                throw new RuntimeException("Group should have terminated");
+            if (pool != null && !pool.isTerminated())
+                throw new RuntimeException("Executor should have terminated");
+        }
+    }
+
+    static void shutdownNowTests() throws Exception {
+        System.out.println("-- test shutdownNow --");
+
+        for (int i=0; i< 10; i++) {
+            ExecutorService pool = null;
+            AsynchronousChannelGroup group;
+            if (rand.nextBoolean()) {
+                pool = Executors.newCachedThreadPool();
+                group = AsynchronousChannelGroup
+                    .withCachedThreadPool(pool, rand.nextInt(5));
+            } else {
+                int nThreads = 1 + rand.nextInt(8);
+                group = AsynchronousChannelGroup
+                    .withFixedThreadPool(nThreads, threadFactory);
+            }
+
+            // I/O in progress
+            AsynchronousChannel ch;
+            if (rand.nextBoolean()) {
+                AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel
+                    .open(group).bind(new InetSocketAddress(0));
+                listener.accept();
+                ch = listener;
+            } else {
+                AsynchronousDatagramChannel adc =
+                    AsynchronousDatagramChannel.open(null, group);
+                adc.receive(ByteBuffer.allocate(100));
+                ch = adc;
+            }
+
+            // forceful shutdown
+            group.shutdownNow();
+
+            // shutdownNow is required to close all channels
+            if (ch.isOpen())
+                throw new RuntimeException("Channel should be closed");
+
+            boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS);
+            if (!terminated)
+                throw new RuntimeException("Group should have terminated");
+            if (pool != null && !pool.isTerminated())
+                throw new RuntimeException("Executor should have terminated");
+        }
+    }
+
+    // test creating channels in group after group is shutdown
+    static void afterShutdownTests() throws Exception {
+        System.out.println("-- test operations after group is shutdown  --");
+        AsynchronousChannelGroup group =
+            AsynchronousChannelGroup.withFixedThreadPool(1, threadFactory);
+
+        AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group);
+        AsynchronousServerSocketChannel listener = AsynchronousServerSocketChannel.open(group);
+
+        // initiate accept
+        listener.bind(new InetSocketAddress(0));
+        Future<AsynchronousSocketChannel> result = listener.accept();
+
+        // shutdown group
+        group.shutdown();
+        if (!group.isShutdown())
+            throw new RuntimeException("Group should be shutdown");
+
+        // attempt to create another channel
+        try {
+            AsynchronousSocketChannel.open(group);
+            throw new RuntimeException("ShutdownChannelGroupException expected");
+        } catch (ShutdownChannelGroupException x) {
+        }
+        try {
+            AsynchronousServerSocketChannel.open(group);
+            throw new RuntimeException("ShutdownChannelGroupException expected");
+        } catch (ShutdownChannelGroupException x) {
+        }
+
+        // attempt to create another channel by connecting. This should cause
+        // the accept operation to fail.
+        InetAddress lh = InetAddress.getLocalHost();
+        int port = ((InetSocketAddress)listener.getLocalAddress()).getPort();
+        InetSocketAddress isa = new InetSocketAddress(lh, port);
+        ch.connect(isa).get();
+        try {
+            result.get();
+            throw new RuntimeException("Connection was accepted");
+        } catch (ExecutionException x) {
+            Throwable cause = x.getCause();
+            if (!(cause instanceof IOException))
+                throw new RuntimeException("Cause should be IOException");
+            cause = cause.getCause();
+            if (!(cause instanceof ShutdownChannelGroupException))
+                throw new RuntimeException("IOException cause should be ShutdownChannelGroupException");
+        }
+
+        // initiate another accept even though channel group is shutdown.
+        Future<AsynchronousSocketChannel> res = listener.accept();
+        try {
+            res.get(3, TimeUnit.SECONDS);
+            throw new RuntimeException("TimeoutException expected");
+        } catch (TimeoutException x) {
+        }
+        // connect to the listener which should cause the accept to complete
+        AsynchronousSocketChannel.open().connect(isa);
+        try {
+            res.get();
+            throw new RuntimeException("Connection was accepted");
+        } catch (ExecutionException x) {
+            Throwable cause = x.getCause();
+            if (!(cause instanceof IOException))
+                throw new RuntimeException("Cause should be IOException");
+            cause = cause.getCause();
+            if (!(cause instanceof ShutdownChannelGroupException))
+                throw new RuntimeException("IOException cause should be ShutdownChannelGroupException");
+        }
+
+        // group should *not* terminate as channels are open
+        boolean terminated = group.awaitTermination(3, TimeUnit.SECONDS);
+        if (terminated)
+            throw new RuntimeException("Group should not have terminated");
+
+        // close channel; group should terminate quickly
+        ch.close();
+        listener.close();
+        terminated = group.awaitTermination(3, TimeUnit.SECONDS);
+        if (!terminated)
+            throw new RuntimeException("Group should have terminated");
+    }
+
+    static void miscTests() throws Exception {
+        System.out.println("-- miscellenous tests --");
+        try {
+            AsynchronousChannelGroup.withFixedThreadPool(1, null);
+            throw new RuntimeException("NPE expected");
+        } catch (NullPointerException x) {
+        }
+        try {
+            AsynchronousChannelGroup.withFixedThreadPool(0, threadFactory);
+            throw new RuntimeException("IAE expected");
+        } catch (IllegalArgumentException e) {
+        }
+        try {
+            AsynchronousChannelGroup.withCachedThreadPool(null, 0);
+            throw new RuntimeException("NPE expected");
+        } catch (NullPointerException x) {
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for AsynchronousChannelGroup
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.net.*;
+import java.util.concurrent.*;
+import java.io.IOException;
+
+/**
+ * This test verifies that a channel or channel group can be closed from a
+ * completion handler when there are no threads available to handle I/O events.
+ */
+
+public class GroupOfOne {
+
+    public static void main(String[] args) throws Exception {
+        // create listener to accept connections
+        final AsynchronousServerSocketChannel listener =
+            AsynchronousServerSocketChannel.open()
+                .bind(new InetSocketAddress(0));
+        listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
+            public void completed(AsynchronousSocketChannel ch, Void att) {
+                listener.accept(null, this);
+            }
+            public void failed(Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
+        });
+
+        int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
+        SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port);
+
+        test(sa, true, false);
+        test(sa, false, true);
+        test(sa, true, true);
+    }
+
+    static void test(SocketAddress sa,
+                     final boolean closeChannel,
+                     final boolean shutdownGroup)
+        throws Exception
+    {
+        // group with 1 thread
+        final AsynchronousChannelGroup group = AsynchronousChannelGroup
+            .withFixedThreadPool(1, new ThreadFactory() {
+                @Override
+                public Thread newThread(final Runnable r) {
+                    return new Thread(r);
+                }});
+        final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group);
+
+        // the latch counts down when:
+        // 1. The read operation fails (expected)
+        // 2. the close/shutdown completes
+        final CountDownLatch latch = new CountDownLatch(2);
+
+        ch.connect(sa, null, new CompletionHandler<Void,Void>() {
+            public void completed(Void result, Void att)  {
+                System.out.println("Connected");
+
+                // initiate I/O operation that does not complete (successfully)
+                ByteBuffer buf = ByteBuffer.allocate(100);
+                ch.read(buf, null, new CompletionHandler<Integer,Void>() {
+                    public void completed(Integer bytesRead, Void att)  {
+                        throw new RuntimeException();
+                    }
+                    public void failed(Throwable exc, Void att) {
+                        if (!(exc instanceof AsynchronousCloseException))
+                            throw new RuntimeException(exc);
+                        System.out.println("Read failed (expected)");
+                        latch.countDown();
+                    }
+                    public void cancelled(Void att) {
+                        throw new RuntimeException();
+                    }
+                });
+
+                // close channel or shutdown group
+                try {
+                    if (closeChannel) {
+                        System.out.print("Close channel ...");
+                        ch.close();
+                        System.out.println(" done.");
+                    }
+                    if (shutdownGroup) {
+                        System.out.print("Shutdown group ...");
+                        group.shutdownNow();
+                        System.out.println(" done.");
+                    }
+                    latch.countDown();
+                } catch (IOException e) {
+                    throw new RuntimeException();
+                }
+            }
+            public void failed(Throwable exc, Void att) {
+                throw new RuntimeException(exc);
+            }
+            public void cancelled(Void att) {
+                throw new RuntimeException();
+            }
+        });
+
+        latch.await();
+
+        // clean-up
+        group.shutdown();
+        boolean terminated = group.awaitTermination(5, TimeUnit.SECONDS);
+        if (!terminated)
+            throw new RuntimeException("Group did not terminate");
+
+        System.out.println("TEST OKAY");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Identity.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for AsynchronousChannelGroup
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+
+/**
+ * Tests that the completion handler is invoked by a thread with
+ * the expected identity.
+ */
+
+public class Identity {
+    static final Random rand = new Random();
+    static final CountDownLatch done = new CountDownLatch(1);
+    static final AtomicBoolean failed = new AtomicBoolean(false);
+
+    static void fail(String msg) {
+        failed.set(true);
+        done.countDown();
+        throw new RuntimeException(msg);
+    }
+
+    // thread-local identifies the thread
+    private static final ThreadLocal<Integer> myGroup =
+        new ThreadLocal<Integer>() {
+            @Override protected Integer initialValue() {
+                return Integer.valueOf(-1);
+            }
+        };
+
+    // creates a ThreadFactory that constructs groups with the given identity
+    static final ThreadFactory createThreadFactory(final int groupId) {
+        return new ThreadFactory() {
+            @Override
+            public Thread newThread(final Runnable r) {
+                Thread t = new Thread(new Runnable() {
+                    public void run() {
+                        myGroup.set(groupId);
+                        r.run();
+                    }});
+                t.setDaemon(true);
+                return t;
+            }
+        };
+    }
+
+    public static void main(String[] args) throws Exception {
+        // create listener to accept connections
+        final AsynchronousServerSocketChannel listener =
+            AsynchronousServerSocketChannel.open()
+                .bind(new InetSocketAddress(0));
+        listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
+            public void completed(final AsynchronousSocketChannel ch, Void att) {
+                listener.accept(null, this);
+
+                final ByteBuffer buf = ByteBuffer.allocate(100);
+                ch.read(buf, null, new CompletionHandler<Integer,Void>() {
+                    public void completed(Integer bytesRead, Void att) {
+                        buf.clear();
+                        ch.read(buf, null, this);
+                    }
+                    public void failed(Throwable exc, Void att) {
+                    }
+                    public void cancelled(Void att) {
+                    }
+                });
+            }
+            public void failed(Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
+        });
+        int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
+        SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port);
+
+        // create 3-10 channels, each in its own group
+        final int groupCount = 3 + rand.nextInt(8);
+        final AsynchronousSocketChannel[] channel = new AsynchronousSocketChannel[groupCount];
+        for (int i=0; i<groupCount; i++) {
+            ThreadFactory factory = createThreadFactory(i);
+            AsynchronousChannelGroup group;
+            if (rand.nextBoolean()) {
+                int nThreads = 1 + rand.nextInt(10);
+                group = AsynchronousChannelGroup.withFixedThreadPool(nThreads, factory);
+            } else {
+                ExecutorService pool = Executors.newCachedThreadPool(factory);
+                group = AsynchronousChannelGroup.withCachedThreadPool(pool, rand.nextInt(5));
+            }
+
+            // create channel in group and connect it to the server
+            AsynchronousSocketChannel ch = AsynchronousSocketChannel.open(group);
+            ch.connect(sa).get();
+            channel[i] = ch;
+        }
+
+        // randomly write to each channel, ensuring that the completion handler
+        // is always invoked by a thread with the right identity.
+        final AtomicInteger writeCount = new AtomicInteger(100);
+        channel[0].write(getBuffer(), 0, new CompletionHandler<Integer,Integer>() {
+            public void completed(Integer bytesWritten, Integer groupId) {
+                if (bytesWritten != 1)
+                    fail("Expected 1 byte to be written");
+                if (!myGroup.get().equals(groupId))
+                    fail("Handler invoked by thread with the wrong identity");
+                if (writeCount.decrementAndGet() > 0) {
+                    int id = rand.nextInt(groupCount);
+                    channel[id].write(getBuffer(), id, this);
+                } else {
+                    done.countDown();
+                }
+            }
+            public void failed(Throwable exc, Integer groupId) {
+                fail(exc.getMessage());
+            }
+            public void cancelled(Integer groupId) {
+                fail("I/O operation was cancelled");
+            }
+        });
+
+        // wait until
+        done.await();
+        if (failed.get())
+            throw new RuntimeException("Test failed - see log for details");
+    }
+
+    static ByteBuffer getBuffer() {
+        ByteBuffer buf;
+        if (rand.nextBoolean()) {
+            buf = ByteBuffer.allocateDirect(1);
+        } else {
+            buf = ByteBuffer.allocate(1);
+        }
+        buf.put((byte)0);
+        buf.flip();
+        return buf;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/PrivilegedThreadFactory.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.util.concurrent.ThreadFactory;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * The "privileged" ThreadFactory used by the AsExecutor test.
+ */
+
+public class PrivilegedThreadFactory implements ThreadFactory {
+    public void PrivilegedThreadPoolFactory() {
+        // check class is on boot class path
+        if (PrivilegedThreadFactory.class.getClassLoader() != null)
+            throw new RuntimeException("PrivilegedThreadFactory class not on boot class path");
+    }
+
+    @Override
+    public Thread newThread(final Runnable r) {
+        return AccessController.doPrivileged(new PrivilegedAction<Thread>() {
+            @Override
+            public Thread run() {
+                Thread t = new Thread(r);
+                t.setDaemon(true);
+                return t;
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Restart.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for AsynchronousChannelGroup
+ * @build Restart
+ * @run main/othervm -XX:-UseVMInterruptibleIO Restart
+ */
+
+import java.nio.channels.*;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+import java.io.IOException;
+
+/**
+ * Exercise replacement of threads in the thread pool when completion handlers
+ * terminate due to errors or runtime exceptions.
+ */
+
+public class Restart {
+    static final Random rand = new Random();
+
+    public static void main(String[] args) throws Exception {
+        // thread group for thread pools
+        final ThreadGroup tg = new ThreadGroup("test");
+
+        // keep track of the number of threads that terminate
+        final AtomicInteger exceptionCount = new AtomicInteger(0);
+        final Thread.UncaughtExceptionHandler ueh =
+            new Thread.UncaughtExceptionHandler() {
+                public void uncaughtException(Thread t, Throwable e) {
+                    exceptionCount.incrementAndGet();
+                }
+            };
+        ThreadFactory factory = new ThreadFactory() {
+            @Override
+            public Thread newThread(Runnable r) {
+                Thread t = new Thread(tg, r);
+                t.setUncaughtExceptionHandler(ueh);
+                return t;
+            }
+        };
+
+        // group with fixed thread pool
+        int nThreads = 1 + rand.nextInt(4);
+        AsynchronousChannelGroup group =
+            AsynchronousChannelGroup.withFixedThreadPool(nThreads, factory);
+        testRestart(group, 100);
+        group.shutdown();
+
+        // group with custom thread pool
+        ExecutorService pool = Executors.newCachedThreadPool(factory);
+        group = AsynchronousChannelGroup.withCachedThreadPool(pool, rand.nextInt(5));
+        testRestart(group, 100);
+        group.shutdown();
+
+        // give time for threads to terminate
+        Thread.sleep(3000);
+        int actual = exceptionCount.get();
+        if (actual != 200)
+            throw new RuntimeException(actual + " exceptions, expected: " + 200);
+    }
+
+    static void testRestart(AsynchronousChannelGroup group, int count)
+        throws Exception
+    {
+        AsynchronousServerSocketChannel listener =
+            AsynchronousServerSocketChannel.open(group)
+                .bind(new InetSocketAddress(0));
+
+        for (int i=0; i<count; i++) {
+            final CountDownLatch latch = new CountDownLatch(1);
+
+            listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
+                public void completed(AsynchronousSocketChannel ch, Void att) {
+                    try {
+                        ch.close();
+                    } catch (IOException ignore) { }
+
+                    latch.countDown();
+
+                    // throw error or runtime exception
+                    if (rand.nextBoolean()) {
+                        throw new Error();
+                    } else {
+                        throw new RuntimeException();
+                    }
+                }
+                public void failed(Throwable exc, Void att) {
+                }
+                public void cancelled(Void att) {
+                }
+            });
+
+            // establish loopback connection which should cause completion
+            // handler to be invoked.
+            int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
+            AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
+            InetAddress lh = InetAddress.getLocalHost();
+            ch.connect(new InetSocketAddress(lh, port)).get();
+            ch.close();
+
+            // wait for handler to be invoked
+            latch.await();
+        }
+
+        // clean-up
+        listener.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for AsynchronousChannelGroup
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.net.*;
+import java.util.concurrent.*;
+import java.io.IOException;
+
+public class Unbounded {
+    // number of concurrent completion handlers
+    static final int CONCURRENCY_COUNT = 512;
+
+    public static void main(String[] args) throws Exception {
+        // all accepted connections are added to a queue
+        final ArrayBlockingQueue<AsynchronousSocketChannel> queue =
+            new ArrayBlockingQueue<AsynchronousSocketChannel>(CONCURRENCY_COUNT);
+
+        // create listener to accept connections
+        final AsynchronousServerSocketChannel listener =
+            AsynchronousServerSocketChannel.open()
+                .bind(new InetSocketAddress(0));
+        listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
+            public void completed(AsynchronousSocketChannel ch, Void att) {
+                queue.add(ch);
+                listener.accept(null, this);
+            }
+            public void failed(Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
+        });
+        System.out.println("Listener created.");
+
+        // establish lots of connections
+        int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
+        SocketAddress sa = new InetSocketAddress(InetAddress.getLocalHost(), port);
+        AsynchronousSocketChannel[] channels =
+            new AsynchronousSocketChannel[CONCURRENCY_COUNT];
+        for (int i=0; i<CONCURRENCY_COUNT; i++) {
+            int attempts = 0;
+            for (;;) {
+                try {
+                    channels[i] = AsynchronousSocketChannel.open();
+                    channels[i].connect(sa).get();
+                    break;
+                } catch (IOException x) {
+                    // probably resource issue so back off and retry
+                    if (++attempts >= 3)
+                        throw x;
+                    Thread.sleep(50);
+                }
+            }
+        }
+        System.out.println("All connection established.");
+
+        // the barrier where all threads (plus the main thread) wait
+        final CyclicBarrier barrier = new CyclicBarrier(CONCURRENCY_COUNT+1);
+
+        // initiate a read operation on each channel.
+        for (int i=0; i<CONCURRENCY_COUNT; i++) {
+            ByteBuffer buf = ByteBuffer.allocateDirect(100);
+            channels[i].read( buf, channels[i],
+                new CompletionHandler<Integer,AsynchronousSocketChannel>() {
+                    public void completed(Integer bytesRead, AsynchronousSocketChannel ch) {
+                        try {
+                            ch.close();
+                            barrier.await();
+                        } catch (Exception x) {
+                            throw new AssertionError(x);
+                        }
+                    }
+                    public void failed(Throwable exc, AsynchronousSocketChannel ch) {
+                    }
+                    public void cancelled(AsynchronousSocketChannel ch) {
+                    }
+                });
+        }
+        System.out.println("All read operations outstanding.");
+
+        // write data to each of the accepted connections
+        int remaining = CONCURRENCY_COUNT;
+        while (remaining > 0) {
+            AsynchronousSocketChannel ch = queue.take();
+            ch.write(ByteBuffer.wrap("welcome".getBytes())).get();
+            ch.close();
+            remaining--;
+        }
+
+        // wait for all threads to reach the barrier
+        System.out.println("Waiting for all threads to reach barrier");
+        barrier.await();
+        listener.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/run_any_task.sh	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,52 @@
+#
+# Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+# @test
+# @bug 4607272
+# @summary Unit test for AsynchronousChannelGrou#execute
+# @build AsExecutor PrivilegedThreadFactory Attack
+# @run shell run_any_task.sh
+
+# if TESTJAVA isn't set then we assume an interactive run.
+
+if [ -z "$TESTJAVA" ]; then
+    TESTSRC=.
+    TESTCLASSES=.
+    JAVA=java
+    JAR=jar
+else
+    JAVA="${TESTJAVA}/bin/java"
+    JAR="${TESTJAVA}/bin/jar"
+fi
+
+echo "Creating JAR file ..."
+$JAR -cf "${TESTCLASSES}/Privileged.jar" \
+    -C "${TESTCLASSES}" PrivilegedThreadFactory.class \
+    -C "${TESTCLASSES}" PrivilegedThreadFactory\$1.class \
+    -C "${TESTCLASSES}" Attack.class
+
+echo "Running test ..."
+$JAVA -XX:-UseVMInterruptibleIO \
+    -Xbootclasspath/a:"${TESTCLASSES}/Privileged.jar" \
+    -classpath "${TESTCLASSES}" \
+    AsExecutor
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,448 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4527345
+ * @summary Unit test for AsynchronousDatagramChannel
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.net.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+
+public class Basic {
+
+    public static void main(String[] args) throws Exception {
+        doReceiveTests();
+        doReadTests();
+        doSendTests();
+        doWriteTests();
+        doCancelTests();
+        doMulticastTests();
+    }
+
+    // basic receive tests
+    static void doReceiveTests() throws Exception {
+        final byte[] msg = "hello".getBytes();
+
+        AsynchronousDatagramChannel ch = AsynchronousDatagramChannel.open()
+            .bind(new InetSocketAddress(0));
+        int port = ((InetSocketAddress)(ch.getLocalAddress())).getPort();
+        InetAddress rh = InetAddress.getLocalHost();
+        final SocketAddress sa = new InetSocketAddress(rh, port);
+
+        DatagramChannel sender = DatagramChannel.open();
+        ByteBuffer dst = ByteBuffer.allocateDirect(100);
+
+        // Test: datagram packet received immediately
+        sender.send(ByteBuffer.wrap(msg), sa);
+        dst.clear();
+        ch.receive(dst).get(1, TimeUnit.SECONDS);
+        if (dst.flip().remaining() != msg.length)
+            throw new RuntimeException("Unexpected number of bytes read");
+
+        // Test: datagram packet not received immediately
+        dst.clear();
+        final CountDownLatch latch = new CountDownLatch(1);
+        ch.receive(dst, null, new CompletionHandler<SocketAddress,Void>() {
+            public void completed(SocketAddress source, Void att) {
+                latch.countDown();
+            }
+            public void failed (Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
+        });
+        Thread.sleep(2000);
+        sender.send(ByteBuffer.wrap(msg), sa);
+        latch.await(2, TimeUnit.SECONDS);  // wait for completion handler
+
+        // Test: timeout
+        dst.clear();
+        final AtomicReference<Throwable> exception = new AtomicReference<Throwable>();
+        ch.receive(dst, 2, TimeUnit.SECONDS, null, new CompletionHandler<SocketAddress,Void>() {
+            public void completed(SocketAddress source, Void att) {
+            }
+            public void failed (Throwable exc, Void att) {
+                exception.set(exc);
+            }
+            public void cancelled(Void att) {
+            }
+        });
+        Throwable result;
+        while ((result = exception.get()) == null) {
+            Thread.sleep(100);
+        }
+        if (!(result instanceof InterruptedByTimeoutException))
+            throw new RuntimeException("InterruptedByTimeoutException expected");
+
+        // AsynchronousCloseException
+        dst = ByteBuffer.allocateDirect(100);
+        exception.set(null);
+        ch.receive(dst, null, new CompletionHandler<SocketAddress,Void>() {
+            public void completed(SocketAddress source, Void att) {
+            }
+            public void failed (Throwable exc, Void att) {
+                exception.set(exc);
+            }
+            public void cancelled(Void att) {
+            }
+        });
+        ch.close();
+        while ((result = exception.get()) == null) {
+            Thread.sleep(100);
+        }
+        if (!(result instanceof AsynchronousCloseException))
+            throw new RuntimeException("AsynchronousCloseException expected");
+
+        // done
+        sender.close();
+    }
+
+    // basic read tests
+    static void doReadTests() throws Exception {
+        final byte[] msg = "hello".getBytes();
+
+        AsynchronousDatagramChannel ch = AsynchronousDatagramChannel.open()
+            .bind(new InetSocketAddress(0));
+        int port = ((InetSocketAddress)(ch.getLocalAddress())).getPort();
+        InetAddress lh = InetAddress.getLocalHost();
+        final SocketAddress sa = new InetSocketAddress(lh, port);
+
+        DatagramChannel sender = DatagramChannel.open();
+        ByteBuffer dst = ByteBuffer.allocateDirect(100);
+
+        // Test: not connected
+        try {
+            ch.read(dst);
+            throw new RuntimeException("NotYetConnectedException expected");
+        } catch (NotYetConnectedException e) {
+        }
+
+        // connect the channel
+        sender.bind(new InetSocketAddress(0));
+        ch.connect(new InetSocketAddress(lh,
+                ((InetSocketAddress)(sender.getLocalAddress())).getPort()));
+
+        // Test: datagram packet received immediately
+        sender.send(ByteBuffer.wrap(msg), sa);
+        dst.clear();
+        ch.read(dst).get(1, TimeUnit.SECONDS);
+        if (dst.flip().remaining() != msg.length)
+            throw new RuntimeException("Unexpected number of bytes read");
+
+        // Test: datagram packet not received immediately
+        dst.clear();
+        final CountDownLatch l1 = new CountDownLatch(1);
+        ch.read(dst, null, new CompletionHandler<Integer,Void>() {
+            public void completed(Integer bytesRead, Void att) {
+                l1.countDown();
+            }
+            public void failed (Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
+        });
+        Thread.sleep(2000);
+        sender.send(ByteBuffer.wrap(msg), sa);
+        l1.await(2, TimeUnit.SECONDS);
+
+        // Test: timeout
+        dst.clear();
+        final AtomicReference<Throwable> exception = new AtomicReference<Throwable>();
+        ch.read(dst, 2, TimeUnit.SECONDS, null, new CompletionHandler<Integer,Void>() {
+            public void completed(Integer bytesRead, Void att) {
+            }
+            public void failed (Throwable exc, Void att) {
+                exception.set(exc);
+            }
+            public void cancelled(Void att) {
+            }
+        });
+        Throwable result;
+        while ((result = exception.get()) == null) {
+            Thread.sleep(100);
+        }
+        if (!(result instanceof InterruptedByTimeoutException))
+            throw new RuntimeException("InterruptedByTimeoutException expected");
+
+        // AsynchronousCloseException
+        dst.clear();
+        exception.set(null);
+        ch.read(dst, null, new CompletionHandler<Integer,Void>() {
+            public void completed(Integer bytesRead, Void att) {
+            }
+            public void failed (Throwable exc, Void att) {
+                exception.set(exc);
+            }
+            public void cancelled(Void att) {
+            }
+        });
+        ch.close();
+        while ((result = exception.get()) == null) {
+            Thread.sleep(100);
+        }
+        if (!(result instanceof AsynchronousCloseException))
+            throw new RuntimeException("AsynchronousCloseException expected");
+
+        // done
+        sender.close();
+    }
+
+    // basic send tests
+    static void doSendTests() throws Exception {
+        final byte[] msg = "hello".getBytes();
+
+        DatagramChannel reader = DatagramChannel.open()
+            .bind(new InetSocketAddress(0));
+        int port = ((InetSocketAddress)(reader.getLocalAddress())).getPort();
+        InetAddress rh = InetAddress.getLocalHost();
+        SocketAddress sa = new InetSocketAddress(rh, port);
+
+        AsynchronousDatagramChannel ch = AsynchronousDatagramChannel.open();
+
+        // Test: send datagram packet to reader
+        int bytesSent = ch.send(ByteBuffer.wrap(msg), sa).get();
+        if (bytesSent != msg.length)
+            throw new RuntimeException("Unexpected number of bytes sent");
+
+        // check received
+        ByteBuffer dst = ByteBuffer.allocateDirect(100);
+        reader.receive(dst);
+        dst.flip();
+        if (dst.remaining() != msg.length)
+            throw new RuntimeException("Unexpected number of bytes received");
+
+        // Test: send datagram packet to reader and check completion handler
+        // is invoked
+        final CountDownLatch l2 = new CountDownLatch(1);
+        ch.send(ByteBuffer.wrap(msg), sa, null, new CompletionHandler<Integer,Void>() {
+            public void completed(Integer bytesSent, Void att) {
+                if (bytesSent != msg.length)
+                    throw new RuntimeException("Unexpected number of bytes received");
+                l2.countDown();
+            }
+            public void failed (Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
+        });
+        l2.await(5, TimeUnit.SECONDS);
+
+        // check received
+        dst.clear();
+        reader.receive(dst);
+        dst.flip();
+        if (dst.remaining() != msg.length)
+            throw new RuntimeException("Unexpected number of bytes received");
+
+        // Test: check that failed method is invoked
+        ch.close();
+        final CountDownLatch l3 = new CountDownLatch(1);
+        ch.send(ByteBuffer.wrap(msg), sa, null, new CompletionHandler<Integer,Void>() {
+            public void completed(Integer bytesSent, Void att) {
+                throw new RuntimeException("completed method invoked");
+            }
+            public void failed (Throwable exc, Void att) {
+                if (exc instanceof ClosedChannelException) {
+                    l3.countDown();
+                } else {
+                    throw new RuntimeException(exc);
+                }
+            }
+            public void cancelled(Void att) {
+            }
+        });
+        l3.await(5, TimeUnit.SECONDS);
+
+        // done
+        reader.close();
+    }
+
+    // basic write tests
+    static void doWriteTests() throws Exception {
+        final byte[] msg = "hello".getBytes();
+
+        DatagramChannel reader = DatagramChannel.open()
+            .bind(new InetSocketAddress(0));
+        int port = ((InetSocketAddress)(reader.getLocalAddress())).getPort();
+        InetAddress rh = InetAddress.getLocalHost();
+        SocketAddress sa = new InetSocketAddress(rh, port);
+
+        AsynchronousDatagramChannel ch = AsynchronousDatagramChannel.open();
+
+        // Test: unconnected
+        try {
+            ch.write(ByteBuffer.wrap(msg)).get();
+            throw new RuntimeException("NotYetConnectedException expected");
+        } catch (NotYetConnectedException e) {
+        }
+
+        // Test: connect, and write datagram
+        ch.connect(sa);
+        int bytesSent = ch.write(ByteBuffer.wrap(msg)).get();
+        if (bytesSent != msg.length)
+            throw new RuntimeException("Unexpected number of bytes sent");
+
+        // check received
+        ByteBuffer dst = ByteBuffer.allocateDirect(100);
+        reader.receive(dst);
+        dst.flip();
+        if (dst.remaining() != msg.length)
+            throw new RuntimeException("Unexpected number of bytes received");
+
+        // Test: write datagram and check completion handler is invoked
+        final CountDownLatch l2 = new CountDownLatch(1);
+        ch.write(ByteBuffer.wrap(msg), null, new CompletionHandler<Integer,Void>() {
+            public void completed(Integer bytesSent, Void att) {
+                if (bytesSent != msg.length)
+                    throw new RuntimeException("Unexpected number of bytes received");
+                l2.countDown();
+            }
+            public void failed (Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
+        });
+        l2.await(5, TimeUnit.SECONDS);
+
+        // check received
+        dst.clear();
+        reader.receive(dst);
+        dst.flip();
+        if (dst.remaining() != msg.length)
+            throw new RuntimeException("Unexpected number of bytes received");
+
+        // done
+        ch.close();
+        reader.close();
+    }
+
+    static void cancelAndCheck(Future<?> result, CountDownLatch latch)
+        throws InterruptedException
+    {
+        boolean cancelled = result.cancel(false);
+        if (!cancelled)
+            throw new RuntimeException("Not cancelled");
+        if (!result.isDone())
+            throw new RuntimeException("Should be done");
+        try {
+            result.get();
+            throw new RuntimeException("Result not expected");
+        } catch (CancellationException e) {
+            // expected
+        } catch (ExecutionException e) {
+            throw new RuntimeException("Should not fail");
+        }
+
+        // make sure that completion handler is invoked
+        latch.await();
+    }
+
+    // basic cancel tests
+    static void doCancelTests() throws Exception {
+        InetAddress lh = InetAddress.getLocalHost();
+
+        // timed and non-timed receive
+        for (int i=0; i<2; i++) {
+            AsynchronousDatagramChannel ch =
+                AsynchronousDatagramChannel.open().bind(new InetSocketAddress(0));
+            final CountDownLatch latch = new CountDownLatch(1);
+            long timeout = (i == 0) ? 0L : 60L;
+            Future<SocketAddress> remote = ch
+                .receive(ByteBuffer.allocate(100), timeout, TimeUnit.SECONDS, null,
+                    new CompletionHandler<SocketAddress,Void>() {
+                        public void completed(SocketAddress source, Void att) {
+                        }
+                        public void failed (Throwable exc, Void att) {
+                        }
+                        public void cancelled(Void att) {
+                            latch.countDown();
+                        }
+                    });
+            cancelAndCheck(remote, latch);
+            ch.close();
+        }
+
+        // timed and non-timed read
+        for (int i=0; i<2; i++) {
+            AsynchronousDatagramChannel ch =
+                AsynchronousDatagramChannel.open().bind(new InetSocketAddress(0));
+             ch.connect(new InetSocketAddress(lh,
+                ((InetSocketAddress)(ch.getLocalAddress())).getPort()));
+            final CountDownLatch latch = new CountDownLatch(1);
+            long timeout = (i == 0) ? 0L : 60L;
+            Future<Integer> result = ch
+                .read(ByteBuffer.allocate(100), timeout, TimeUnit.SECONDS, null,
+                    new CompletionHandler<Integer,Void>() {
+                        public void completed(Integer bytesRead, Void att) {
+                        }
+                        public void failed (Throwable exc, Void att) {
+                        }
+                        public void cancelled(Void att) {
+                            latch.countDown();
+                        }
+                    });
+            cancelAndCheck(result, latch);
+            ch.close();
+        }
+    }
+
+    // basic multicast test
+    static void doMulticastTests() throws Exception {
+        final byte[] msg = "hello".getBytes();
+
+        AsynchronousDatagramChannel ch = AsynchronousDatagramChannel
+            .open(StandardProtocolFamily.INET, null)
+            .setOption(StandardSocketOption.SO_REUSEADDR, true)
+            .bind(new InetSocketAddress(0));
+
+        InetAddress lh = InetAddress.getLocalHost();
+        int port = ((InetSocketAddress)(ch.getLocalAddress())).getPort();
+
+        // join group
+        InetAddress group = InetAddress.getByName("225.4.5.6");
+        NetworkInterface interf = NetworkInterface.getByInetAddress(lh);
+        MembershipKey key = ch.join(group, interf);
+
+        // check key
+        if (key.channel() != ch)
+            throw new RuntimeException("Not the expected channel");
+
+        // send message to group
+        DatagramChannel sender = DatagramChannel.open();
+        sender.send(ByteBuffer.wrap(msg), new InetSocketAddress(group, port));
+        sender.close();
+
+        // check message received
+        ByteBuffer dst = ByteBuffer.allocate(200);
+        SocketAddress source = ch.receive(dst).get(2, TimeUnit.SECONDS);
+        if (!((InetSocketAddress)source).getAddress().equals(lh))
+            throw new RuntimeException("Unexpected source");
+
+        // done
+        ch.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,585 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for AsynchronousFileChannel
+ */
+
+import java.nio.file.*;
+import java.nio.channels.*;
+import java.nio.ByteBuffer;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicReference;
+import static java.nio.file.StandardOpenOption.*;
+
+public class Basic {
+
+    private static final Random rand = new Random();
+
+    public static void main(String[] args) throws IOException {
+        // create temporary file
+        File blah = File.createTempFile("blah", null);
+        blah.deleteOnExit();
+
+        final AsynchronousFileChannel ch = AsynchronousFileChannel
+            .open(blah.toPath(), READ, WRITE);
+
+        // run tests
+        testUsingCompletionHandlers(ch);
+        testUsingWaitOnResult(ch);
+        testLocking(ch);
+        testInterruptHandlerThread(ch);
+
+        // close channel and invoke test that expects channel to be closed
+        ch.close();
+        testClosedChannel(ch);
+
+        // these tests open the file themselves
+        testCustomThreadPool(blah.toPath());
+        testAsynchronousClose(blah.toPath());
+        testCancel(blah.toPath());
+        testTruncate(blah.toPath());
+    }
+
+    /*
+     * Generate buffer with random contents
+     * Writes buffer to file using a CompletionHandler to consume the result
+     *    of each write operation
+     * Reads file to EOF to a new buffer using a CompletionHandler to consume
+     *    the result of each read operation
+     * Compares buffer contents
+     */
+    static void testUsingCompletionHandlers(AsynchronousFileChannel ch)
+        throws IOException
+    {
+        System.out.println("testUsingCompletionHandlers");
+
+        ch.truncate(0L);
+
+        // generate buffer with random elements and write it to file
+        ByteBuffer src = genBuffer();
+        writeFully(ch, src, 0L);
+
+        // read to EOF or buffer is full
+        ByteBuffer dst = (rand.nextBoolean()) ?
+            ByteBuffer.allocateDirect(src.capacity()) :
+            ByteBuffer.allocate(src.capacity());
+        readAll(ch, dst, 0L);
+
+        // check buffers are the same
+        src.flip();
+        dst.flip();
+        if (!src.equals(dst)) {
+            throw new RuntimeException("Contents differ");
+        }
+    }
+
+    /*
+     * Generate buffer with random contents
+     * Writes buffer to file, invoking the Future's get method to wait for
+     *    each write operation to complete
+     * Reads file to EOF to a new buffer, invoking the Future's get method to
+     *    wait for each write operation to complete
+     * Compares buffer contents
+     */
+    static void testUsingWaitOnResult(AsynchronousFileChannel ch)
+        throws IOException
+    {
+        System.out.println("testUsingWaitOnResult");
+
+        ch.truncate(0L);
+
+        // generate buffer
+        ByteBuffer src = genBuffer();
+
+        // write buffer completely to file
+        long position = 0L;
+        while (src.hasRemaining()) {
+            Future<Integer> result = ch.write(src, position);
+            try {
+                int n = result.get();
+                // update position
+                position += n;
+            } catch (ExecutionException x) {
+                throw new RuntimeException(x.getCause());
+            } catch (InterruptedException x) {
+                throw new RuntimeException(x);
+            }
+        }
+
+        // read file into new buffer
+        ByteBuffer dst = (rand.nextBoolean()) ?
+            ByteBuffer.allocateDirect(src.capacity()) :
+            ByteBuffer.allocate(src.capacity());
+        position = 0L;
+        int n;
+        do {
+            Future<Integer> result = ch.read(dst, position);
+            try {
+                n = result.get();
+
+                // update position
+                if (n > 0) position += n;
+            } catch (ExecutionException x) {
+                throw new RuntimeException(x.getCause());
+            } catch (InterruptedException x) {
+                throw new RuntimeException(x);
+            }
+        } while (n > 0);
+
+        // check buffers are the same
+        src.flip();
+        dst.flip();
+        if (!src.equals(dst)) {
+            throw new RuntimeException("Contents differ");
+        }
+    }
+
+    // exercise lock methods
+    static void testLocking(AsynchronousFileChannel ch)
+        throws IOException
+    {
+        System.out.println("testLocking");
+
+        // test 1 - acquire lock and check that tryLock throws
+        // OverlappingFileLockException
+        FileLock fl;
+        try {
+            fl = ch.lock().get();
+        } catch (ExecutionException x) {
+            throw new RuntimeException(x);
+        } catch (InterruptedException x) {
+            throw new RuntimeException("Should not be interrupted");
+        }
+        if (!fl.acquiredBy().equals(ch))
+            throw new RuntimeException("FileLock#acquiredBy returned incorrect channel");
+        try {
+            ch.tryLock();
+            throw new RuntimeException("OverlappingFileLockException expected");
+        } catch (OverlappingFileLockException x) {
+        }
+        fl.release();
+
+        // test 2 - acquire try and check that lock throws OverlappingFileLockException
+        fl = ch.tryLock();
+        if (fl == null)
+            throw new RuntimeException("Unable to acquire lock");
+        try {
+            ch.lock(null, new CompletionHandler<FileLock,Void> () {
+                public void completed(FileLock result, Void att) {
+                }
+                public void failed(Throwable exc, Void att) {
+                }
+                public void cancelled(Void att) {
+                }
+            });
+            throw new RuntimeException("OverlappingFileLockException expected");
+        } catch (OverlappingFileLockException x) {
+        }
+        fl.release();
+    }
+
+    // interrupt should not close channel
+    static void testInterruptHandlerThread(final AsynchronousFileChannel ch) {
+        System.out.println("testInterruptHandlerThread");
+
+        ByteBuffer buf = ByteBuffer.allocateDirect(100);
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        ch.read(buf, 0L, null, new CompletionHandler<Integer,Void>() {
+            public void completed(Integer result, Void att) {
+                try {
+                    Thread.currentThread().interrupt();
+                    long size = ch.size();
+                    latch.countDown();
+                } catch (IOException x) {
+                    x.printStackTrace();
+                }
+            }
+            public void failed(Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
+        });
+
+        // wait for handler to complete
+        await(latch);
+    }
+
+    // invoke method on closed channel
+    static void testClosedChannel(AsynchronousFileChannel ch) {
+        System.out.println("testClosedChannel");
+
+        if (ch.isOpen())
+            throw new RuntimeException("Channel should be closed");
+
+        ByteBuffer buf = ByteBuffer.allocateDirect(100);
+
+        // check read fails with ClosedChannelException
+        try {
+            ch.read(buf, 0L).get();
+            throw new RuntimeException("ExecutionException expected");
+        } catch (ExecutionException x) {
+            if (!(x.getCause() instanceof ClosedChannelException))
+                throw new RuntimeException("Cause of ClosedChannelException expected");
+        } catch (InterruptedException x) {
+        }
+
+        // check write fails with ClosedChannelException
+        try {
+            ch.write(buf, 0L).get();
+            throw new RuntimeException("ExecutionException expected");
+        } catch (ExecutionException x) {
+            if (!(x.getCause() instanceof ClosedChannelException))
+                throw new RuntimeException("Cause of ClosedChannelException expected");
+        } catch (InterruptedException x) {
+        }
+
+        // check lock fails with ClosedChannelException
+        try {
+            ch.lock().get();
+            throw new RuntimeException("ExecutionException expected");
+        } catch (ExecutionException x) {
+            if (!(x.getCause() instanceof ClosedChannelException))
+                throw new RuntimeException("Cause of ClosedChannelException expected");
+        } catch (InterruptedException x) {
+        }
+    }
+
+
+    // exercise custom thread pool
+    static void testCustomThreadPool(Path file) throws IOException {
+        System.out.println("testCustomThreadPool");
+
+        // records threads that are created
+        final List<Thread> threads = new ArrayList<Thread>();
+
+        ThreadFactory threadFactory = new ThreadFactory() {
+             @Override
+             public Thread newThread(Runnable r) {
+                 Thread t = new Thread(r);
+                 t.setDaemon(true);
+                 synchronized (threads) {
+                     threads.add(t);
+                 }
+                 return t;
+             }
+        };
+
+        // exercise tests with varied number of threads
+        for (int nThreads=1; nThreads<=5; nThreads++) {
+            synchronized (threads) {
+                threads.clear();
+            }
+            ExecutorService executor = Executors.newFixedThreadPool(nThreads, threadFactory);
+            Set<StandardOpenOption> opts = EnumSet.of(WRITE);
+            AsynchronousFileChannel ch = AsynchronousFileChannel.open(file, opts, executor);
+            try {
+                for (int i=0; i<10; i++) {
+                    // do I/O operation to see which thread invokes the completion handler
+                    final AtomicReference<Thread> invoker = new AtomicReference<Thread>();
+                    final CountDownLatch latch = new CountDownLatch(1);
+
+                    ch.write(genBuffer(), 0L, null, new CompletionHandler<Integer,Void>() {
+                        public void completed(Integer result, Void att) {
+                            invoker.set(Thread.currentThread());
+                            latch.countDown();
+                        }
+                        public void failed(Throwable exc, Void att) {
+                        }
+                        public void cancelled(Void att) {
+                        }
+                    });
+                    await(latch);
+
+                    // check invoker
+                    boolean found = false;
+                    synchronized (threads) {
+                        for (Thread t: threads) {
+                            if (t == invoker.get()) {
+                                found = true;
+                                break;
+                            }
+                        }
+                    }
+                    if (!found)
+                        throw new RuntimeException("Invoker thread not found");
+                }
+            } finally {
+                ch.close();
+            }
+        }
+    }
+
+    // exercise asynchronous close
+    static void testAsynchronousClose(Path file) throws IOException {
+        System.out.println("testAsynchronousClose");
+
+        // create file
+        AsynchronousFileChannel ch = AsynchronousFileChannel
+            .open(file, WRITE, TRUNCATE_EXISTING);
+        long size = 0L;
+        do {
+            ByteBuffer buf = genBuffer();
+            int n = buf.remaining();
+            writeFully(ch, buf, size);
+            size += n;
+        } while (size < (50L * 1024L * 1024L));
+
+        ch.close();
+
+        ch = AsynchronousFileChannel.open(file, WRITE, SYNC);
+
+        // randomize number of writers, buffer size, and positions
+
+        int nwriters = 1 + rand.nextInt(8);
+        ByteBuffer[] buf = new ByteBuffer[nwriters];
+        long[] position = new long[nwriters];
+        for (int i=0; i<nwriters; i++) {
+            buf[i] = genBuffer();
+            position[i] = rand.nextInt((int)size);
+        }
+
+        // initiate I/O
+        Future[] result = new Future[nwriters];
+        for (int i=0; i<nwriters; i++) {
+            result[i] = ch.write(buf[i], position[i]);
+        }
+
+        // close file
+        ch.close();
+
+        // write operations should complete or fail with AsynchronousCloseException
+        for (int i=0; i<nwriters; i++) {
+            try {
+                result[i].get();
+            } catch (ExecutionException x) {
+                Throwable cause = x.getCause();
+                if (!(cause instanceof AsynchronousCloseException))
+                    throw new RuntimeException(cause);
+            } catch (CancellationException  x) {
+                throw new RuntimeException(x);   // should not happen
+            } catch (InterruptedException x) {
+                throw new RuntimeException(x);   // should not happen
+            }
+        }
+    }
+
+    // exercise cancel method
+    static void testCancel(Path file) throws IOException {
+        System.out.println("testCancel");
+
+        for (int i=0; i<2; i++) {
+            boolean mayInterruptIfRunning = (i == 0) ? false : true;
+
+            // open with SYNC option to improve chances that write will not
+            // complete immediately
+            AsynchronousFileChannel ch = AsynchronousFileChannel
+                .open(file, WRITE, SYNC);
+
+            // start write operation
+            final CountDownLatch latch = new CountDownLatch(1);
+            Future<Integer> res = ch.write(genBuffer(), 0L, null,
+                new CompletionHandler<Integer,Void>() {
+                    public void completed(Integer result, Void att) {
+                    }
+                    public void failed(Throwable exc, Void att) {
+                    }
+                    public void cancelled(Void att) {
+                        latch.countDown();
+                    }
+            });
+
+            // cancel operation
+            boolean cancelled = res.cancel(mayInterruptIfRunning);
+
+            // check post-conditions
+            if (!res.isDone())
+                throw new RuntimeException("isDone should return true");
+            if (res.isCancelled() != cancelled)
+                throw new RuntimeException("isCancelled not consistent");
+            try {
+                res.get();
+                if (!cancelled)
+                    throw new RuntimeException("CancellationException expected");
+            } catch (CancellationException x) {
+                // expected
+            } catch (ExecutionException x) {
+                throw new RuntimeException(x);
+            } catch (InterruptedException x) {
+                throw new RuntimeException(x);
+            }
+            try {
+                res.get(1, TimeUnit.SECONDS);
+                throw new RuntimeException("CancellationException expected");
+            } catch (CancellationException x) {
+                // expected
+            } catch (ExecutionException x) {
+                throw new RuntimeException(x);
+            } catch (TimeoutException x) {
+                throw new RuntimeException(x);
+            } catch (InterruptedException x) {
+                throw new RuntimeException(x);
+            }
+
+            // check that cancelled method is invoked
+            if (cancelled)
+                await(latch);
+
+            ch.close();
+        }
+    }
+
+    // exercise truncate method
+    static void testTruncate(Path file) throws IOException {
+        System.out.println("testTruncate");
+
+        // basic tests
+        AsynchronousFileChannel ch = AsynchronousFileChannel
+            .open(file, CREATE, WRITE, TRUNCATE_EXISTING);
+        try {
+            writeFully(ch, genBuffer(), 0L);
+            long size = ch.size();
+
+            // attempt to truncate to a size greater than the current size
+            if (ch.truncate(size + 1L).size() != size)
+                throw new RuntimeException("Unexpected size after truncation");
+
+            // truncate file
+            if (ch.truncate(size - 1L).size() != (size - 1L))
+                throw new RuntimeException("Unexpected size after truncation");
+
+            // invalid size
+            try {
+                ch.truncate(-1L);
+                throw new RuntimeException("IllegalArgumentException expected");
+            } catch (IllegalArgumentException e) { }
+
+        } finally {
+            ch.close();
+        }
+
+        // channel is closed
+        try {
+            ch.truncate(0L);
+            throw new RuntimeException("ClosedChannelException expected");
+        } catch (ClosedChannelException  e) { }
+
+        // channel is read-only
+        ch = AsynchronousFileChannel.open(file, READ);
+        try {
+            try {
+            ch.truncate(0L);
+                throw new RuntimeException("NonWritableChannelException expected");
+            } catch (NonWritableChannelException  e) { }
+        } finally {
+            ch.close();
+        }
+    }
+
+    // returns ByteBuffer with random bytes
+    static ByteBuffer genBuffer() {
+        int size = 1024 + rand.nextInt(16000);
+        byte[] buf = new byte[size];
+        boolean useDirect = rand.nextBoolean();
+        if (useDirect) {
+            ByteBuffer bb = ByteBuffer.allocateDirect(buf.length);
+            bb.put(buf);
+            bb.flip();
+            return bb;
+        } else {
+            return ByteBuffer.wrap(buf);
+        }
+    }
+
+    // writes all remaining bytes in the buffer to the given channel at the
+    // given position
+    static void writeFully(final AsynchronousFileChannel ch,
+                           final ByteBuffer src,
+                           long position)
+    {
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        // use position as attachment
+        ch.write(src, position, position, new CompletionHandler<Integer,Long>() {
+            public void completed(Integer result, Long position) {
+                int n = result;
+                if (src.hasRemaining()) {
+                    long p = position + n;
+                    ch.write(src, p, p, this);
+                } else {
+                    latch.countDown();
+                }
+            }
+            public void failed(Throwable exc, Long position) {
+            }
+            public void cancelled(Long position) {
+            }
+        });
+
+        // wait for writes to complete
+        await(latch);
+    }
+
+    static void readAll(final AsynchronousFileChannel ch,
+                        final ByteBuffer dst,
+                       long position)
+    {
+        final CountDownLatch latch = new CountDownLatch(1);
+
+        // use position as attachment
+        ch.read(dst, position, position, new CompletionHandler<Integer,Long>() {
+            public void completed(Integer result, Long position) {
+                int n = result;
+                if (n > 0) {
+                    long p = position + n;
+                    ch.read(dst, p, p, this);
+                } else {
+                    latch.countDown();
+                }
+            }
+            public void failed(Throwable exc, Long position) {
+            }
+            public void cancelled(Long position) {
+            }
+        });
+
+        // wait for reads to complete
+        await(latch);
+    }
+
+    static void await(CountDownLatch latch) {
+        // wait until done
+        boolean done = false;
+        while (!done) {
+            try {
+                latch.await();
+                done = true;
+            } catch (InterruptedException x) { }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for java.nio.channels.AsynchronousFileChannel
+ * @build CustomThreadPool MyThreadFactory
+ * @run main/othervm -Djava.nio.channels.DefaultThreadPool.threadFactory=MyThreadFactory CustomThreadPool
+ */
+
+import java.io.File;
+import static java.nio.file.StandardOpenOption.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class CustomThreadPool {
+
+    public static void main(String[] args) throws Exception {
+        File blah = File.createTempFile("blah", null);
+        blah.deleteOnExit();
+        AsynchronousFileChannel ch =
+            AsynchronousFileChannel.open(blah.toPath(), READ, WRITE);
+        ByteBuffer src = ByteBuffer.wrap("Scooby Snacks".getBytes());
+
+        final AtomicReference<Thread> invoker = new AtomicReference<Thread>();
+        ch.write(src, 0, invoker,
+            new CompletionHandler<Integer,AtomicReference<Thread>>() {
+                public void completed(Integer result, AtomicReference<Thread> invoker) {
+                    invoker.set(Thread.currentThread());
+                }
+                public void failed(Throwable exc, AtomicReference<Thread> invoker) {
+                }
+                public void cancelled(AtomicReference<Thread> invoker) {
+                }
+            });
+        Thread t;
+        while ((t = invoker.get()) == null) {
+            Thread.sleep(100);
+        }
+        ch.close();
+
+        // check handler was run by known thread
+        if (!MyThreadFactory.created(t))
+            throw new RuntimeException("Handler invoked by unknown thread");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for AsynchronousFileChannel#lock method
+ */
+
+import java.net.*;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.file.*;
+import static java.nio.file.StandardOpenOption.*;
+import java.nio.channels.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Random;
+import java.util.concurrent.*;
+
+public class Lock {
+
+    static final Random rand = new Random();
+
+    public static void main(String[] args) throws Exception {
+        if (args.length > 0 && args[0].equals("-lockslave")) {
+            int port = Integer.parseInt(args[1]);
+            runLockSlave(port);
+            System.exit(0);
+        }
+
+        LockSlaveMirror slave = startLockSlave();
+        try {
+
+             // create temporary file
+            File blah = File.createTempFile("blah", null);
+            blah.deleteOnExit();
+
+            testLockProtocol(blah, slave);
+            testAsyncClose(blah, slave);
+
+        } finally {
+            slave.shutdown();
+        }
+    }
+
+    // test locking protocol
+    static void testLockProtocol(File file, LockSlaveMirror slave)
+        throws Exception
+    {
+        FileLock fl;
+
+        // slave VM opens file and acquires exclusive lock
+        slave.open(file.getPath()).lock();
+
+        AsynchronousFileChannel ch = AsynchronousFileChannel
+            .open(file.toPath(), READ, WRITE);
+
+        // this VM tries to acquire lock
+        // (lock should not be acquire until released by slave VM)
+        Future<FileLock> result = ch.lock();
+        try {
+            result.get(2, TimeUnit.SECONDS);
+            throw new RuntimeException("Timeout expected");
+        } catch (TimeoutException x) {
+        }
+
+        // slave VM releases lock
+        slave.unlock();
+
+        // this VM should now acquire lock
+        fl = result.get();
+        fl.release();
+
+        // slave VM acquires lock on range
+        slave.lock(0, 10, false);
+
+        // this VM acquires lock on non-overlapping range
+        fl = ch.lock(10, 10, false, null, null).get();
+        fl.release();
+
+        // done
+        ch.close();
+        slave.close();
+    }
+
+    // test close of channel with outstanding lock operation
+    static void testAsyncClose(File file, LockSlaveMirror slave) throws Exception {
+        // slave VM opens file and acquires exclusive lock
+        slave.open(file.getPath()).lock();
+
+        for (int i=0; i<100; i++) {
+            AsynchronousFileChannel ch = AsynchronousFileChannel
+                .open(file.toPath(), READ, WRITE);
+
+            // try to lock file (should not complete because file is locked by slave)
+            Future<FileLock> result = ch.lock();
+            try {
+                result.get(rand.nextInt(100), TimeUnit.MILLISECONDS);
+                throw new RuntimeException("Timeout expected");
+            } catch (TimeoutException x) {
+            }
+
+            // close channel with lock operation outstanding
+            ch.close();
+
+            // operation should complete with AsynchronousCloseException
+            try {
+                result.get();
+                throw new RuntimeException("ExecutionException expected");
+            } catch (ExecutionException x) {
+                if (!(x.getCause() instanceof AsynchronousCloseException)) {
+                    x.getCause().printStackTrace();
+                    throw new RuntimeException("AsynchronousCloseException expected");
+                }
+            }
+        }
+
+        slave.close();
+    }
+
+    // starts a "lock slave" in another process, returning a mirror object to
+    // control the slave
+    static LockSlaveMirror startLockSlave() throws Exception {
+        ServerSocketChannel ssc = ServerSocketChannel.open()
+            .bind(new InetSocketAddress(0));
+        int port = ((InetSocketAddress)(ssc.getLocalAddress())).getPort();
+
+        String sep = FileSystems.getDefault().getSeparator();
+
+        String command = System.getProperty("java.home") +
+            sep + "bin" + sep + "java Lock -lockslave " + port;
+        Process p = Runtime.getRuntime().exec(command);
+        IOHandler.handle(p.getInputStream());
+        IOHandler.handle(p.getErrorStream());
+
+        // wait for slave to connect
+        SocketChannel sc = ssc.accept();
+        return new LockSlaveMirror(sc);
+    }
+
+    // commands that the slave understands
+    static final String OPEN_CMD    = "open";
+    static final String CLOSE_CMD   = "close";
+    static final String LOCK_CMD    = "lock";
+    static final String UNLOCK_CMD  = "unlock";
+    static final char TERMINATOR    = ';';
+
+    // provides a proxy to a "lock slave"
+    static class LockSlaveMirror {
+        private final SocketChannel sc;
+
+        LockSlaveMirror(SocketChannel sc) {
+            this.sc = sc;
+        }
+
+        private void sendCommand(String cmd, String... params)
+            throws IOException
+        {
+            for (String s: params) {
+                cmd += " " + s;
+            }
+            cmd += TERMINATOR;
+
+            ByteBuffer buf = Charset.defaultCharset().encode(cmd);
+            while (buf.hasRemaining()) {
+                sc.write(buf);
+            }
+
+            // wait for ack
+            buf = ByteBuffer.allocate(1);
+            int n = sc.read(buf);
+            if (n != 1)
+                throw new RuntimeException("Reply expected");
+            if (buf.get(0) != TERMINATOR)
+                throw new RuntimeException("Terminated expected");
+        }
+
+        LockSlaveMirror open(String file) throws IOException {
+            sendCommand(OPEN_CMD, file);
+            return this;
+        }
+
+        void close() throws IOException {
+            sendCommand(CLOSE_CMD);
+        }
+
+        LockSlaveMirror lock() throws IOException {
+            sendCommand(LOCK_CMD);
+            return this;
+        }
+
+
+        LockSlaveMirror lock(long position, long size, boolean shared)
+            throws IOException
+        {
+            sendCommand(LOCK_CMD, position + "," + size + "," + shared);
+            return this;
+        }
+
+        LockSlaveMirror unlock() throws IOException {
+            sendCommand(UNLOCK_CMD);
+            return this;
+        }
+
+        void shutdown() throws IOException {
+            sc.close();
+        }
+    }
+
+    // Helper class to direct process output to the parent System.out
+    static class IOHandler implements Runnable {
+        private final InputStream in;
+
+        IOHandler(InputStream in) {
+            this.in = in;
+        }
+
+        static void handle(InputStream in) {
+            IOHandler handler = new IOHandler(in);
+            Thread thr = new Thread(handler);
+            thr.setDaemon(true);
+            thr.start();
+        }
+
+        public void run() {
+            try {
+                byte b[] = new byte[100];
+                for (;;) {
+                    int n = in.read(b);
+                    if (n < 0) return;
+                    for (int i=0; i<n; i++) {
+                        System.out.print((char)b[i]);
+                    }
+                }
+            } catch (IOException ioe) { }
+        }
+    }
+
+    // slave process that responds to simple commands a socket connection
+    static void runLockSlave(int port) throws Exception {
+
+        // establish connection to parent
+        SocketChannel sc = SocketChannel.open(new InetSocketAddress(port));
+        ByteBuffer buf = ByteBuffer.allocateDirect(1024);
+
+        FileChannel fc = null;
+        FileLock fl = null;
+        try {
+            for (;;) {
+
+                // read command (ends with ";")
+                buf.clear();
+                int n, last = 0;
+                do {
+                    n = sc.read(buf);
+                    if (n < 0)
+                        return;
+                    if (n == 0)
+                        throw new AssertionError();
+                    last += n;
+                } while (buf.get(last-1) != TERMINATOR);
+
+                // decode into command and optional parameter
+                buf.flip();
+                String s = Charset.defaultCharset().decode(buf).toString();
+                int sp = s.indexOf(" ");
+                String cmd = (sp < 0) ? s.substring(0, s.length()-1) :
+                    s.substring(0, sp);
+                String param = (sp < 0) ? "" : s.substring(sp+1, s.length()-1);
+
+                // execute
+                if (cmd.equals(OPEN_CMD)) {
+                    if (fc != null)
+                        throw new RuntimeException("File already open");
+                    fc = FileChannel.open(Paths.get(param),READ, WRITE);
+                }
+                if (cmd.equals(CLOSE_CMD)) {
+                    if (fc == null)
+                        throw new RuntimeException("No file open");
+                    fc.close();
+                    fc = null;
+                    fl = null;
+                }
+                if (cmd.equals(LOCK_CMD)) {
+                    if (fl != null)
+                        throw new RuntimeException("Already holding lock");
+
+                    if (param.length() == 0) {
+                        fl = fc.lock();
+                    } else {
+                        String[] values = param.split(",");
+                        if (values.length != 3)
+                            throw new RuntimeException("Lock parameter invalid");
+                        long position = Long.parseLong(values[0]);
+                        long size = Long.parseLong(values[1]);
+                        boolean shared = Boolean.parseBoolean(values[2]);
+                        fl = fc.lock(position, size, shared);
+                    }
+                }
+
+                if (cmd.equals(UNLOCK_CMD)) {
+                    if (fl == null)
+                        throw new RuntimeException("Not holding lock");
+                    fl.release();
+                    fl = null;
+                }
+
+                // send reply
+                byte[] reply = { TERMINATOR };
+                n = sc.write(ByteBuffer.wrap(reply));
+            }
+
+        } finally {
+            sc.close();
+            if (fc != null) fc.close();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/MyThreadFactory.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.util.concurrent.ThreadFactory;
+import java.util.*;
+
+public class MyThreadFactory implements ThreadFactory {
+
+    private static final Set<Thread> threads = new HashSet<Thread>();
+
+    static boolean created(Thread t) {
+        synchronized (threads) {
+            return threads.contains(t);
+        }
+    }
+
+    public MyThreadFactory() {
+    }
+
+    @Override
+    public Thread newThread(Runnable r) {
+        Thread t = new Thread(r);
+        t.setDaemon(true);
+        synchronized (threads) {
+            threads.add(t);
+        }
+        return t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for AsynchronousServerSocketChannel
+ * @run main/timeout=180 Basic
+ */
+
+import java.nio.channels.*;
+import java.net.*;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class Basic {
+
+    public static void main(String[] args) throws Exception {
+        testBind();
+        testAccept();
+    }
+
+    static void testBind() throws Exception {
+        System.out.println("-- bind --");
+
+        AsynchronousServerSocketChannel ch = AsynchronousServerSocketChannel.open();
+        if (ch.getLocalAddress() != null)
+            throw new RuntimeException("Local address should be 'null'");
+        ch.bind(new InetSocketAddress(0), 20);
+
+        // check local address after binding
+        InetSocketAddress local = (InetSocketAddress)ch.getLocalAddress();
+        if (local.getPort() == 0)
+            throw new RuntimeException("Unexpected port");
+        if (!local.getAddress().isAnyLocalAddress())
+            throw new RuntimeException("Not bound to a wildcard address");
+
+        // try to re-bind
+        try {
+            ch.bind(new InetSocketAddress(0));
+            throw new RuntimeException("AlreadyBoundException expected");
+        } catch (AlreadyBoundException x) {
+        }
+        ch.close();
+
+        // check ClosedChannelException
+        ch = AsynchronousServerSocketChannel.open();
+        ch.close();
+        try {
+            ch.bind(new InetSocketAddress(0));
+            throw new RuntimeException("ClosedChannelException  expected");
+        } catch (ClosedChannelException  x) {
+        }
+    }
+
+    static void testAccept() throws Exception {
+        System.out.println("-- accept --");
+
+        final AsynchronousServerSocketChannel listener =
+            AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0));
+
+        InetAddress lh = InetAddress.getLocalHost();
+        int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
+        final InetSocketAddress isa = new InetSocketAddress(lh, port);
+
+        // establish a few loopback connections
+        for (int i=0; i<100; i++) {
+            SocketChannel sc = SocketChannel.open(isa);
+            AsynchronousSocketChannel ch = listener.accept().get();
+            sc.close();
+            ch.close();
+        }
+
+       final AtomicReference<Throwable> exception = new AtomicReference<Throwable>();
+
+        // start accepting
+        listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
+            public void completed(AsynchronousSocketChannel ch, Void att) {
+                try {
+                    ch.close();
+                } catch (IOException ignore) { }
+            }
+            public void failed(Throwable exc, Void att) {
+                exception.set(exc);
+            }
+            public void cancelled(Void att) {
+            }
+        });
+
+        // check AcceptPendingException
+        try {
+            listener.accept();
+            throw new RuntimeException("AcceptPendingException expected");
+        } catch (AcceptPendingException x) {
+        }
+
+        // asynchronous close
+        listener.close();
+        while (exception.get() == null)
+            Thread.sleep(100);
+        if (!(exception.get() instanceof AsynchronousCloseException))
+            throw new RuntimeException("AsynchronousCloseException expected");
+
+        // once closed when a further attemt should throw ClosedChannelException
+        try {
+            listener.accept().get();
+            throw new RuntimeException("ExecutionException expected");
+        } catch (ExecutionException x) {
+            if (!(x.getCause() instanceof ClosedChannelException))
+                throw new RuntimeException("Cause of ClosedChannelException expected");
+        } catch (InterruptedException x) {
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/WithSecurityManager.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for AsynchronousServerServerSocketChannel
+ * @build WithSecurityManager
+ * @run main/othervm WithSecurityManager allow
+ * @run main/othervm WithSecurityManager deny
+ */
+
+import java.nio.file.Paths;
+import java.nio.channels.*;
+import java.net.*;
+import java.util.concurrent.*;
+
+public class WithSecurityManager {
+    public static void main(String[] args) throws Exception {
+        boolean allow = false;
+        String policy = (args[0].equals("allow")) ? "java.policy.allow" :
+            "java.policy.deny";
+
+        String testSrc = System.getProperty("test.src");
+        if (testSrc == null)
+            testSrc = ".";
+
+        System.setProperty("java.security.policy",
+            Paths.get(testSrc).resolve(policy).toString());
+        System.setSecurityManager(new SecurityManager());
+
+        AsynchronousServerSocketChannel listener =
+            AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0));
+
+        InetAddress lh = InetAddress.getLocalHost();
+        int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
+
+        // establish and accept connection
+        SocketChannel sc = SocketChannel.open(new InetSocketAddress(lh, port));
+        Future<AsynchronousSocketChannel> result = listener.accept();
+
+        if (allow) {
+            // no security exception
+            result.get().close();
+        } else {
+            try {
+                result.get();
+            } catch (ExecutionException x) {
+                if (!(x.getCause() instanceof SecurityException))
+                    throw new RuntimeException("SecurityException expected");
+            }
+        }
+
+        sc.close();
+        listener.close();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/java.policy.allow	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,3 @@
+grant {
+    permission java.net.SocketPermission "*:1024-", "accept,connect,resolve";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/java.policy.deny	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,3 @@
+grant {
+    permission java.net.SocketPermission "*:1024-", "connect,resolve";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,805 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for AsynchronousSocketChannel
+ * @run main/timeout=600 Basic
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import static java.net.StandardSocketOption.*;
+import java.net.*;
+import java.util.Random;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+import java.io.IOException;
+
+public class Basic {
+    static final Random rand = new Random();
+
+    public static void main(String[] args) throws Exception {
+        testBind();
+        testSocketOptions();
+        testConnect();
+        testCloseWhenPending();
+        testCancel();
+        testRead1();
+        testRead2();
+        testRead3();
+        testWrite1();
+        testWrite2();
+        testTimeout();
+        testShutdown();
+    }
+
+    static class Server {
+        private final ServerSocketChannel ssc;
+        private final InetSocketAddress address;
+
+        Server() throws IOException {
+            ssc = ServerSocketChannel.open().bind(new InetSocketAddress(0));
+
+            InetAddress lh = InetAddress.getLocalHost();
+            int port = ((InetSocketAddress)(ssc.getLocalAddress())).getPort();
+            address = new InetSocketAddress(lh, port);
+        }
+
+        InetSocketAddress address() {
+            return address;
+        }
+
+        SocketChannel accept() throws IOException {
+            return ssc.accept();
+        }
+
+        void close() {
+            try {
+                ssc.close();
+            } catch (IOException ignore) { }
+        }
+
+    }
+
+    static void testBind() throws Exception {
+        System.out.println("-- bind --");
+
+        AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
+        if (ch.getLocalAddress() != null)
+            throw new RuntimeException("Local address should be 'null'");
+        ch.bind(new InetSocketAddress(0));
+
+        // check local address after binding
+        InetSocketAddress local = (InetSocketAddress)ch.getLocalAddress();
+        if (local.getPort() == 0)
+            throw new RuntimeException("Unexpected port");
+        if (!local.getAddress().isAnyLocalAddress())
+            throw new RuntimeException("Not bound to a wildcard address");
+
+        // try to re-bind
+        try {
+            ch.bind(new InetSocketAddress(0));
+            throw new RuntimeException("AlreadyBoundException expected");
+        } catch (AlreadyBoundException x) {
+        }
+        ch.close();
+
+        // check ClosedChannelException
+        ch = AsynchronousSocketChannel.open();
+        ch.close();
+        try {
+            ch.bind(new InetSocketAddress(0));
+            throw new RuntimeException("ClosedChannelException  expected");
+        } catch (ClosedChannelException  x) {
+        }
+    }
+
+    static void testSocketOptions() throws Exception {
+        System.out.println("-- socket options --");
+
+        AsynchronousSocketChannel ch = AsynchronousSocketChannel.open()
+            .setOption(SO_RCVBUF, 128*1024)
+            .setOption(SO_SNDBUF, 128*1024)
+            .setOption(SO_REUSEADDR, true)
+            .bind(new InetSocketAddress(0));
+
+        // default values
+        if ((Boolean)ch.getOption(SO_KEEPALIVE))
+            throw new RuntimeException("Default of SO_KEEPALIVE should be 'false'");
+        if ((Boolean)ch.getOption(TCP_NODELAY))
+            throw new RuntimeException("Default of TCP_NODELAY should be 'false'");
+
+        // set and check
+        if (!(Boolean)ch.setOption(SO_KEEPALIVE, true).getOption(SO_KEEPALIVE))
+            throw new RuntimeException("SO_KEEPALIVE did not change");
+        if (!(Boolean)ch.setOption(TCP_NODELAY, true).getOption(TCP_NODELAY))
+            throw new RuntimeException("SO_KEEPALIVE did not change");
+
+        // read others (can't check as actual value is implementation dependent)
+        ch.getOption(SO_RCVBUF);
+        ch.getOption(SO_SNDBUF);
+
+        ch.close();
+    }
+
+    static void testConnect() throws Exception {
+        System.out.println("-- connect --");
+
+        Server server = new Server();
+        AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
+        ch.connect(server.address()).get();
+
+        // check local address
+        if (ch.getLocalAddress() == null)
+            throw new RuntimeException("Not bound to local address");
+
+        // check remote address
+        InetSocketAddress remote = (InetSocketAddress)ch.getRemoteAddress();
+        if (remote.getPort() != server.address().getPort())
+            throw new RuntimeException("Connected to unexpected port");
+        if (!remote.getAddress().equals(server.address().getAddress()))
+            throw new RuntimeException("Connected to unexpected address");
+
+        // try to connect again
+        try {
+            ch.connect(server.address()).get();
+            throw new RuntimeException("AlreadyConnectedException expected");
+        } catch (AlreadyConnectedException x) {
+        }
+        ch.close();
+
+        // check that connect fails with ClosedChannelException)
+        ch = AsynchronousSocketChannel.open();
+        ch.close();
+        try {
+            ch.connect(server.address()).get();
+            throw new RuntimeException("ExecutionException expected");
+        } catch (ExecutionException x) {
+            if (!(x.getCause() instanceof ClosedChannelException))
+                throw new RuntimeException("Cause of ClosedChannelException expected");
+        }
+        final AtomicReference<Throwable> connectException =
+            new AtomicReference<Throwable>();
+        ch.connect(server.address(), null, new CompletionHandler<Void,Void>() {
+            public void completed(Void result, Void att) {
+            }
+            public void failed(Throwable exc, Void att) {
+                connectException.set(exc);
+            }
+            public void cancelled(Void att) {
+            }
+        });
+        while (connectException.get() == null) {
+            Thread.sleep(100);
+        }
+        if (!(connectException.get() instanceof ClosedChannelException))
+            throw new RuntimeException("ClosedChannelException expected");
+
+        System.out.println("-- connect to non-existent host --");
+
+        // test failure
+        InetAddress badHost = InetAddress.getByName("1.2.3.4");
+        if (!badHost.isReachable(10*1000)) {
+
+            ch = AsynchronousSocketChannel.open();
+            try {
+                ch.connect(new InetSocketAddress(badHost, 9876)).get();
+                throw new RuntimeException("Connection should not be established");
+            } catch (ExecutionException x) {
+            }
+            if (ch.isOpen())
+                throw new RuntimeException("Channel should be closed");
+        }
+
+        server.close();
+    }
+
+    static void testCloseWhenPending() throws Exception {
+        System.out.println("-- asynchronous close when connecting --");
+
+        AsynchronousSocketChannel ch;
+
+        // asynchronous close while connecting
+        InetAddress rh = InetAddress.getByName("1.2.3.4");
+        if (!rh.isReachable(3000)) {
+            InetSocketAddress isa = new InetSocketAddress(rh, 1234);
+
+            ch = AsynchronousSocketChannel.open();
+            Future<Void> result = ch.connect(isa);
+
+            // give time to initiate the connect (SYN)
+            Thread.sleep(50);
+
+            // close
+            ch.close();
+
+            // check that AsynchronousCloseException is thrown
+            try {
+                result.get();
+                throw new RuntimeException("Should not connect");
+            } catch (ExecutionException x) {
+                if (!(x.getCause() instanceof AsynchronousCloseException))
+                    throw new RuntimeException(x);
+            }
+        }
+
+        System.out.println("-- asynchronous close when reading --");
+
+        Server server = new Server();
+        ch = AsynchronousSocketChannel.open();
+        ch.connect(server.address()).get();
+
+        ByteBuffer dst = ByteBuffer.allocateDirect(100);
+        Future<Integer> result = ch.read(dst);
+
+        // attempt a second read - should fail with ReadPendingException
+        ByteBuffer buf = ByteBuffer.allocateDirect(100);
+        try {
+            ch.read(buf);
+            throw new RuntimeException("ReadPendingException expected");
+        } catch (ReadPendingException x) {
+        }
+
+        // close channel (should cause initial read to complete)
+        ch.close();
+
+        // check that AsynchronousCloseException is thrown
+        try {
+            result.get();
+            throw new RuntimeException("Should not read");
+        } catch (ExecutionException x) {
+            if (!(x.getCause() instanceof AsynchronousCloseException))
+                throw new RuntimeException(x);
+        }
+
+        System.out.println("-- asynchronous close when writing --");
+
+        ch = AsynchronousSocketChannel.open();
+        ch.connect(server.address()).get();
+
+        final AtomicReference<Throwable> writeException =
+            new AtomicReference<Throwable>();
+
+        // write bytes to fill socket buffer
+        ch.write(genBuffer(), ch, new CompletionHandler<Integer,AsynchronousSocketChannel>() {
+            public void completed(Integer result, AsynchronousSocketChannel ch) {
+                ch.write(genBuffer(), ch, this);
+            }
+            public void failed(Throwable x, AsynchronousSocketChannel ch) {
+                writeException.set(x);
+            }
+            public void cancelled(AsynchronousSocketChannel ch) {
+            }
+        });
+
+        // give time for socket buffer to fill up.
+        Thread.sleep(5*1000);
+
+        //  attempt a concurrent write - should fail with WritePendingException
+        try {
+            ch.write(genBuffer());
+            throw new RuntimeException("WritePendingException expected");
+        } catch (WritePendingException x) {
+        }
+
+        // close channel - should cause initial write to complete
+        ch.close();
+
+        // wait for exception
+        while (writeException.get() == null) {
+            Thread.sleep(100);
+        }
+        if (!(writeException.get() instanceof AsynchronousCloseException))
+            throw new RuntimeException("AsynchronousCloseException expected");
+
+        server.close();
+    }
+
+    static void testCancel() throws Exception {
+        System.out.println("-- cancel --");
+
+        Server server = new Server();
+
+        for (int i=0; i<2; i++) {
+            boolean mayInterruptIfRunning = (i == 0) ? false : true;
+
+            // establish loopback connection
+            AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
+            ch.connect(server.address()).get();
+            SocketChannel peer = server.accept();
+
+            // start read operation
+            final CountDownLatch latch = new CountDownLatch(1);
+            ByteBuffer buf = ByteBuffer.allocate(1);
+            Future<Integer> res = ch.read(buf, null,
+                new CompletionHandler<Integer,Void>() {
+                    public void completed(Integer result, Void att) {
+                    }
+                    public void failed(Throwable exc, Void att) {
+                    }
+                    public void cancelled(Void att) {
+                        latch.countDown();
+                    }
+            });
+
+            // cancel operation
+            boolean cancelled = res.cancel(mayInterruptIfRunning);
+
+            // check post-conditions
+            if (!res.isDone())
+                throw new RuntimeException("isDone should return true");
+            if (res.isCancelled() != cancelled)
+                throw new RuntimeException("isCancelled not consistent");
+            try {
+                res.get();
+                throw new RuntimeException("CancellationException expected");
+            } catch (CancellationException x) {
+            }
+            try {
+                res.get(1, TimeUnit.SECONDS);
+                throw new RuntimeException("CancellationException expected");
+            } catch (CancellationException x) {
+            }
+
+            // check that completion handler executed.
+            latch.await();
+
+            ch.close();
+            peer.close();
+        }
+
+        server.close();
+    }
+
+    static void testRead1() throws Exception {
+        System.out.println("-- read (1) --");
+
+        Server server = new Server();
+        final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
+        ch.connect(server.address()).get();
+
+        // read with 0 bytes remaining should complete immediately
+        ByteBuffer buf = ByteBuffer.allocate(1);
+        buf.put((byte)0);
+        int n = ch.read(buf).get();
+        if (n != 0)
+            throw new RuntimeException("0 expected");
+
+        // write bytes and close connection
+        SocketChannel sc = server.accept();
+        ByteBuffer src = genBuffer();
+        sc.setOption(StandardSocketOption.SO_SNDBUF, src.remaining());
+        while (src.hasRemaining())
+            sc.write(src);
+        sc.close();
+
+        // reads should complete immediately
+        final ByteBuffer dst = ByteBuffer.allocateDirect(src.capacity() + 100);
+        final CountDownLatch latch = new CountDownLatch(1);
+        ch.read(dst, null, new CompletionHandler<Integer,Void>() {
+            public void completed(Integer result, Void att) {
+                int n = result;
+                if (n > 0) {
+                    ch.read(dst, null, this);
+                } else {
+                    latch.countDown();
+                }
+            }
+            public void failed(Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
+        });
+
+        latch.await();
+
+        // check buffers
+        src.flip();
+        dst.flip();
+        if (!src.equals(dst)) {
+            throw new RuntimeException("Contents differ");
+        }
+
+        // close channel
+        ch.close();
+
+        // check read fails with ClosedChannelException
+        try {
+            ch.read(dst).get();
+            throw new RuntimeException("ExecutionException expected");
+        } catch (ExecutionException x) {
+            if (!(x.getCause() instanceof ClosedChannelException))
+                throw new RuntimeException("Cause of ClosedChannelException expected");
+        }
+
+        server.close();
+    }
+
+    static void testRead2() throws Exception {
+        System.out.println("-- read (2) --");
+
+        Server server = new Server();
+
+        final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
+        ch.connect(server.address()).get();
+        SocketChannel sc = server.accept();
+
+        ByteBuffer src = genBuffer();
+
+        // read until the buffer is full
+        final ByteBuffer dst = ByteBuffer.allocateDirect(src.capacity());
+        final CountDownLatch latch = new CountDownLatch(1);
+        ch.read(dst, null, new CompletionHandler<Integer,Void>() {
+            public void completed(Integer result, Void att) {
+                if (dst.hasRemaining()) {
+                    ch.read(dst, null, this);
+                } else {
+                    latch.countDown();
+                }
+            }
+            public void failed(Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
+        });
+
+        // trickle the writing
+        do {
+            int rem = src.remaining();
+            int size = (rem <= 100) ? rem : 50 + rand.nextInt(rem - 100);
+            ByteBuffer buf = ByteBuffer.allocate(size);
+            for (int i=0; i<size; i++)
+                buf.put(src.get());
+            buf.flip();
+            Thread.sleep(50 + rand.nextInt(1500));
+            while (buf.hasRemaining())
+                sc.write(buf);
+        } while (src.hasRemaining());
+
+        // wait until ascynrhonous reading has completed
+        latch.await();
+
+        // check buffers
+        src.flip();
+        dst.flip();
+        if (!src.equals(dst)) {
+           throw new RuntimeException("Contents differ");
+        }
+
+        sc.close();
+        ch.close();
+        server.close();
+    }
+
+    // exercise scattering read
+    static void testRead3() throws Exception {
+        System.out.println("-- read (3) --");
+
+        Server server = new Server();
+        final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
+        ch.connect(server.address()).get();
+        SocketChannel sc = server.accept();
+
+        ByteBuffer[] dsts = new ByteBuffer[3];
+        for (int i=0; i<dsts.length; i++) {
+            dsts[i] = ByteBuffer.allocateDirect(100);
+        }
+
+        // scattering read that completes ascynhronously
+        final CountDownLatch latch = new CountDownLatch(1);
+        ch.read(dsts, 0, dsts.length, 0L, TimeUnit.SECONDS, null,
+            new CompletionHandler<Long,Void>() {
+                public void completed(Long result, Void att) {
+                    long n = result;
+                    if (n <= 0)
+                        throw new RuntimeException("No bytes read");
+                    latch.countDown();
+                }
+                public void failed(Throwable exc, Void att) {
+                }
+                public void cancelled(Void att) {
+                }
+        });
+
+        // write some bytes
+        sc.write(genBuffer());
+
+        // read should now complete
+        latch.await();
+
+        // write more bytes
+        sc.write(genBuffer());
+
+        // read should complete immediately
+        for (int i=0; i<dsts.length; i++) {
+            dsts[i].rewind();
+        }
+        long n = ch
+            .read(dsts, 0, dsts.length, 0L, TimeUnit.SECONDS, null, null).get();
+        if (n <= 0)
+            throw new RuntimeException("No bytes read");
+
+        ch.close();
+        sc.close();
+        server.close();
+    }
+
+    static void testWrite1() throws Exception {
+        System.out.println("-- write (1) --");
+
+        Server server = new Server();
+        final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
+        ch.connect(server.address()).get();
+        SocketChannel sc = server.accept();
+
+        // write with 0 bytes remaining should complete immediately
+        ByteBuffer buf = ByteBuffer.allocate(1);
+        buf.put((byte)0);
+        int n = ch.write(buf).get();
+        if (n != 0)
+            throw new RuntimeException("0 expected");
+
+        // write all bytes and close connection when done
+        final ByteBuffer src = genBuffer();
+        ch.write(src, null, new CompletionHandler<Integer,Void>() {
+            public void completed(Integer result, Void att) {
+                if (src.hasRemaining()) {
+                    ch.write(src, null, this);
+                } else {
+                    try {
+                        ch.close();
+                    } catch (IOException ignore) { }
+                }
+            }
+            public void failed(Throwable exc, Void att) {
+            }
+            public void cancelled(Void att) {
+            }
+        });
+
+        // read to EOF or buffer full
+        ByteBuffer dst = ByteBuffer.allocateDirect(src.capacity() + 100);
+        do {
+            n = sc.read(dst);
+        } while (n > 0);
+        sc.close();
+
+        // check buffers
+        src.flip();
+        dst.flip();
+        if (!src.equals(dst)) {
+            throw new RuntimeException("Contents differ");
+        }
+
+        // check write fails with ClosedChannelException
+        try {
+            ch.read(dst).get();
+            throw new RuntimeException("ExecutionException expected");
+        } catch (ExecutionException x) {
+            if (!(x.getCause() instanceof ClosedChannelException))
+                throw new RuntimeException("Cause of ClosedChannelException expected");
+        }
+
+        server.close();
+    }
+
+    // exercise gathering write
+    static void testWrite2() throws Exception {
+        System.out.println("-- write (2) --");
+
+        Server server = new Server();
+        final AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
+        ch.connect(server.address()).get();
+        SocketChannel sc = server.accept();
+
+        // write buffers (should complete immediately)
+        ByteBuffer[] srcs = genBuffers(1);
+        long n = ch
+            .write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS, null, null).get();
+        if (n <= 0)
+            throw new RuntimeException("No bytes written");
+
+        // set to true to signal that no more buffers should be written
+        final AtomicBoolean continueWriting = new AtomicBoolean(true);
+
+        // number of bytes written
+        final AtomicLong bytesWritten = new AtomicLong(n);
+
+        // write until socket buffer is full so as to create the conditions
+        // for when a write does not complete immediately
+        srcs = genBuffers(1);
+        ch.write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS, null,
+            new CompletionHandler<Long,Void>() {
+                public void completed(Long result, Void att) {
+                    long n = result;
+                    if (n <= 0)
+                        throw new RuntimeException("No bytes written");
+                    bytesWritten.addAndGet(n);
+                    if (continueWriting.get()) {
+                        ByteBuffer[] srcs = genBuffers(8);
+                        ch.write(srcs, 0, srcs.length, 0L, TimeUnit.SECONDS,
+                            null, this);
+                    }
+                }
+                public void failed(Throwable exc, Void att) {
+                }
+                public void cancelled(Void att) {
+                }
+        });
+
+        // give time for socket buffer to fill up.
+        Thread.sleep(5*1000);
+
+        // signal handler to stop further writing
+        continueWriting.set(false);
+
+        // read until done
+        ByteBuffer buf = ByteBuffer.allocateDirect(4096);
+        long total = 0L;
+        do {
+            n = sc.read(buf);
+            if (n <= 0)
+                throw new RuntimeException("No bytes read");
+            buf.rewind();
+            total += n;
+        } while (total < bytesWritten.get());
+
+        ch.close();
+        sc.close();
+        server.close();
+    }
+
+    static void testShutdown() throws Exception {
+        System.out.println("-- shutdown--");
+
+        Server server = new Server();
+        AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
+        ch.connect(server.address()).get();
+        SocketChannel sc = server.accept();
+
+        ByteBuffer buf = ByteBuffer.allocateDirect(1000);
+        int n;
+
+        // check read
+        ch.shutdownInput();
+        n = ch.read(buf).get();
+        if (n != -1)
+            throw new RuntimeException("-1 expected");
+        // check full with full buffer
+        buf.put(new byte[100]);
+        n = ch.read(buf).get();
+        if (n != -1)
+            throw new RuntimeException("-1 expected");
+
+        // check write
+        ch.shutdownOutput();
+        try {
+            ch.write(buf).get();
+            throw new RuntimeException("ClosedChannelException expected");
+        } catch (ExecutionException x) {
+            if (!(x.getCause() instanceof ClosedChannelException))
+                throw new RuntimeException("ClosedChannelException expected");
+        }
+
+        sc.close();
+        ch.close();
+        server.close();
+    }
+
+    static void testTimeout() throws Exception {
+        Server server = new Server();
+        AsynchronousSocketChannel ch = AsynchronousSocketChannel.open();
+        ch.connect(server.address()).get();
+
+        System.out.println("-- timeout when reading --");
+
+        // this read should timeout
+        ByteBuffer dst = ByteBuffer.allocate(512);
+        try {
+            ch.read(dst, 3, TimeUnit.SECONDS, null, null).get();
+            throw new RuntimeException("Read did not timeout");
+        } catch (ExecutionException x) {
+            if (!(x.getCause() instanceof InterruptedByTimeoutException))
+                throw new RuntimeException("InterruptedByTimeoutException expected");
+        }
+
+        // after a timeout then further reading should throw unspecified runtime exception
+        boolean exceptionThrown = false;
+        try {
+            ch.read(dst);
+        } catch (RuntimeException x) {
+            exceptionThrown = true;
+        }
+        if (!exceptionThrown)
+            throw new RuntimeException("RuntimeException expected after timeout.");
+
+
+        System.out.println("-- timeout when writing --");
+
+        final AtomicReference<Throwable> writeException = new AtomicReference<Throwable>();
+
+        final long timeout = 5;
+        final TimeUnit unit = TimeUnit.SECONDS;
+
+        // write bytes to fill socket buffer
+        ch.write(genBuffer(), timeout, unit, ch,
+            new CompletionHandler<Integer,AsynchronousSocketChannel>()
+        {
+            public void completed(Integer result, AsynchronousSocketChannel ch) {
+                ch.write(genBuffer(), timeout, unit, ch, this);
+            }
+            public void failed(Throwable exc, AsynchronousSocketChannel ch) {
+                writeException.set(exc);
+            }
+            public void cancelled(AsynchronousSocketChannel ch) {
+            }
+        });
+
+        // wait for exception
+        while (writeException.get() == null) {
+            Thread.sleep(100);
+        }
+        if (!(writeException.get() instanceof InterruptedByTimeoutException))
+            throw new RuntimeException("InterruptedByTimeoutException expected");
+
+        // after a timeout then further writing should throw unspecified runtime exception
+        exceptionThrown = false;
+        try {
+            ch.write(genBuffer());
+        } catch (RuntimeException x) {
+            exceptionThrown = true;
+        }
+        if (!exceptionThrown)
+            throw new RuntimeException("RuntimeException expected after timeout.");
+
+        ch.close();
+    }
+
+   // returns ByteBuffer with random bytes
+   static ByteBuffer genBuffer() {
+       int size = 1024 + rand.nextInt(16000);
+       byte[] buf = new byte[size];
+       rand.nextBytes(buf);
+       boolean useDirect = rand.nextBoolean();
+       if (useDirect) {
+           ByteBuffer bb = ByteBuffer.allocateDirect(buf.length);
+           bb.put(buf);
+           bb.flip();
+           return bb;
+       } else {
+           return ByteBuffer.wrap(buf);
+       }
+   }
+
+   // return ByteBuffer[] with random bytes
+   static ByteBuffer[] genBuffers(int max) {
+       int len = 1;
+       if (max > 1)
+           len += rand.nextInt(max);
+       ByteBuffer[] bufs = new ByteBuffer[len];
+       for (int i=0; i<len; i++)
+           bufs[i] = genBuffer();
+       return bufs;
+   }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Leaky.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Unit test for AsynchronousSocketChannel
+ * @run main/othervm -XX:+DisableExplicitGC -mx64m Leaky
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.net.*;
+import java.util.concurrent.Future;
+
+/**
+ * Heap buffers must be substituted with direct buffers when doing I/O. This
+ * test creates a scenario on Windows that challenges the per-thread buffer
+ * cache and quickly leads to an OutOfMemoryError if temporary buffers are
+ * not returned to the native heap.
+ */
+
+public class Leaky {
+
+    static final int K = 1024;
+
+    static class Connection {
+        private final AsynchronousSocketChannel client;
+        private final SocketChannel peer;
+        private final ByteBuffer dst;
+        private Future<Integer> readResult;
+
+        Connection() throws Exception {
+            ServerSocketChannel ssc =
+                ServerSocketChannel.open().bind(new InetSocketAddress(0));
+            InetAddress lh = InetAddress.getLocalHost();
+            int port = ((InetSocketAddress)(ssc.getLocalAddress())).getPort();
+            SocketAddress remote = new InetSocketAddress(lh, port);
+            client = AsynchronousSocketChannel.open();
+            client.connect(remote).get();
+            peer = ssc.accept();
+            ssc.close();
+            dst = ByteBuffer.allocate(K*K);
+        }
+
+        void startRead() {
+            dst.clear();
+            readResult = client.read(dst);
+        }
+
+        void write() throws Exception {
+            peer.write(ByteBuffer.wrap("X".getBytes()));
+        }
+
+        void finishRead() throws Exception {
+            readResult.get();
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        final int CONNECTION_COUNT = 10;
+        Connection[] connections = new Connection[CONNECTION_COUNT];
+        for (int i=0; i<CONNECTION_COUNT; i++) {
+            connections[i] = new Connection();
+        }
+
+        for (int i=0; i<1024; i++) {
+            // initiate reads
+            for (Connection conn: connections) {
+                conn.startRead();
+            }
+
+            // write data so that the read can complete
+            for (Connection conn: connections) {
+                conn.write();
+            }
+
+            // complete read
+            for (Connection conn: connections) {
+                conn.finishRead();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/Channels/Basic2.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4607272
+ * @summary Test Channels methods for interoperability between streams and
+ *     asynchronous byte channels
+ */
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Random;
+
+public class Basic2 {
+
+    static final Random rand = new Random();
+
+    public static void main(String[] args) throws Exception {
+        // establish loopback connection
+        AsynchronousServerSocketChannel listener =
+            AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(0));
+        int port = ((InetSocketAddress)(listener.getLocalAddress())).getPort();
+        InetSocketAddress isa =
+            new InetSocketAddress(InetAddress.getLocalHost(), port);
+        AsynchronousSocketChannel ch1 = AsynchronousSocketChannel.open();
+        ch1.connect(isa).get();
+        AsynchronousSocketChannel ch2 = listener.accept().get();
+
+        // start thread to write to stream
+        Writer writer = new Writer(Channels.newOutputStream(ch1));
+        Thread writerThread = new Thread(writer);
+        writerThread.start();
+
+        // start thread to read from stream
+        Reader reader = new Reader(Channels.newInputStream(ch2));
+        Thread readerThread = new Thread(reader);
+        readerThread.start();
+
+        // wait for threads to complete
+        writerThread.join();
+        readerThread.join();
+
+        // check that reader received what we expected
+        if (reader.total() != writer.total())
+            throw new RuntimeException("Unexpected number of bytes read");
+        if (reader.hash() != writer.hash())
+            throw new RuntimeException("Hash incorrect for bytes read");
+
+        // channels should be closed
+        if (ch1.isOpen() || ch2.isOpen())
+            throw new RuntimeException("Channels should be closed");
+    }
+
+    static class Reader implements Runnable {
+        private final InputStream in;
+        private volatile int total;
+        private volatile int hash;
+
+        Reader(InputStream in) {
+            this.in = in;
+        }
+
+        public void run() {
+            try {
+                int n;
+                do {
+                    // random offset/len
+                    byte[] buf = new byte[128 + rand.nextInt(128)];
+                    int len, off;
+                    if (rand.nextBoolean()) {
+                        len = buf.length;
+                        off = 0;
+                        n = in.read(buf);
+                    } else {
+                        len = 1 + rand.nextInt(64);
+                        off = rand.nextInt(64);
+                        n = in.read(buf, off, len);
+                    }
+                    if (n > len)
+                        throw new RuntimeException("Too many bytes read");
+                    if (n > 0) {
+                        total += n;
+                        for (int i=0; i<n; i++) {
+                            int value = buf[off + i];
+                            hash = hash ^ value;
+                        }
+                    }
+                } while (n > 0);
+                in.close();
+
+            } catch (IOException x) {
+                x.printStackTrace();
+            }
+        }
+
+        int total() { return total; }
+        int hash() { return hash; }
+    }
+
+    static class Writer implements Runnable {
+        private final OutputStream out;
+        private final int total;
+        private volatile int hash;
+
+        Writer(OutputStream out) {
+            this.out = out;
+            this.total = 50*1000 + rand.nextInt(50*1000);
+        }
+
+        public void run() {
+            hash = 0;
+            int rem = total;
+            try {
+                do {
+                    byte[] buf = new byte[1 + rand.nextInt(rem)];
+                    int off, len;
+
+                    // write random bytes
+                    if (rand.nextBoolean()) {
+                        off = 0;
+                        len = buf.length;
+                    } else {
+                        off = rand.nextInt(buf.length);
+                        int r = buf.length - off;
+                        len = (r <= 1) ? 1 : (1 + rand.nextInt(r));
+                    }
+                    for (int i=0; i<len; i++) {
+                        byte value = (byte)rand.nextInt(256);
+                        buf[off + i] = value;
+                        hash = hash ^ value;
+                    }
+                    if ((off == 0) && (len == buf.length)) {
+                        out.write(buf);
+                    } else {
+                        out.write(buf, off, len);
+                    }
+                    rem -= len;
+                } while (rem > 0);
+
+                // close stream when done
+                out.close();
+
+            } catch (IOException x) {
+                x.printStackTrace();
+            }
+        }
+
+        int total() { return total; }
+        int hash() { return hash; }
+    }
+}
--- a/jdk/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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
@@ -64,11 +64,11 @@
         // check key
         if (!key.isValid())
             throw new RuntimeException("key is not valid");
-        if (!key.getGroup().equals(group))
+        if (!key.group().equals(group))
             throw new RuntimeException("group is incorrect");
-        if (!key.getNetworkInterface().equals(nif))
+        if (!key.networkInterface().equals(nif))
             throw new RuntimeException("network interface is incorrect");
-        if (key.getSourceAddress() != null)
+        if (key.sourceAddress() != null)
             throw new RuntimeException("key is source specific");
 
         // drop membership
@@ -86,11 +86,11 @@
             }
             if (!key.isValid())
                 throw new RuntimeException("key is not valid");
-            if (!key.getGroup().equals(group))
+            if (!key.group().equals(group))
                 throw new RuntimeException("group is incorrect");
-            if (!key.getNetworkInterface().equals(nif))
+            if (!key.networkInterface().equals(nif))
                 throw new RuntimeException("network interface is incorrect");
-            if (!key.getSourceAddress().equals(source))
+            if (!key.sourceAddress().equals(source))
                 throw new RuntimeException("key's source address incorrect");
 
             // drop membership
--- a/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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
@@ -49,7 +49,7 @@
         DatagramChannel dc = DatagramChannel.open();
 
         // check supported options
-        Set<SocketOption<?>> options = dc.options();
+        Set<SocketOption<?>> options = dc.supportedOptions();
         List<? extends SocketOption<?>> expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF,
             SO_REUSEADDR, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF, IP_MULTICAST_TTL,
             IP_MULTICAST_LOOP);
--- a/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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
@@ -48,7 +48,7 @@
         ServerSocketChannel ssc = ServerSocketChannel.open();
 
         // check supported options
-        Set<SocketOption<?>> options = ssc.options();
+        Set<SocketOption<?>> options = ssc.supportedOptions();
         if (!options.contains(SO_REUSEADDR))
             throw new RuntimeException("SO_REUSEADDR should be supported");
         if (!options.contains(SO_RCVBUF))
--- a/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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
@@ -48,7 +48,7 @@
         SocketChannel sc = SocketChannel.open();
 
         // check supported options
-        Set<SocketOption<?>> options = sc.options();
+        Set<SocketOption<?>> options = sc.supportedOptions();
         List<? extends SocketOption> expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF,
             SO_KEEPALIVE, SO_REUSEADDR, SO_LINGER, TCP_NODELAY);
         for (SocketOption opt: expected) {
--- a/jdk/test/java/nio/channels/etc/NetworkChannelTests.java	Wed Feb 11 13:16:53 2009 +0000
+++ b/jdk/test/java/nio/channels/etc/NetworkChannelTests.java	Sun Feb 15 12:25:54 2009 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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
@@ -103,13 +103,14 @@
 
         // closed
         ch.close();
-        if (ch.getLocalAddress() != null) {
-            throw new RuntimeException("Local address return when closed");
-        }
+        try {
+            ch.getLocalAddress();
+            throw new RuntimeException("ClosedChannelException expected");
+        } catch (ClosedChannelException e) { }
     }
 
     /**
-     * Exercise getConnectedAddress method (SocketChannel only)
+     * Exercise getRemoteAddress method (SocketChannel only)
      */
     static void connectedAddressTests() throws IOException {
         ServerSocketChannel ssc = ServerSocketChannel.open()
@@ -121,19 +122,21 @@
         SocketChannel sc = SocketChannel.open();
 
         // not connected
-        if (sc.getConnectedAddress() != null)
-            throw new RuntimeException("getConnectedAddress returned address when not connected");
+        if (sc.getRemoteAddress() != null)
+            throw new RuntimeException("getRemoteAddress returned address when not connected");
 
         // connected
         sc.connect(server);
-        SocketAddress remote = sc.getConnectedAddress();
+        SocketAddress remote = sc.getRemoteAddress();
         if (!remote.equals(server))
-            throw new RuntimeException("getConnectedAddress returned incorrect address");
+            throw new RuntimeException("getRemoteAddress returned incorrect address");
 
         // closed
         sc.close();
-        if (sc.getConnectedAddress() != null)
-            throw new RuntimeException("getConnectedAddress returned address when closed");
+        try {
+            sc.getRemoteAddress();
+            throw new RuntimeException("ClosedChannelException expected");
+        } catch (ClosedChannelException e) { }
 
         ssc.close();
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/CheckProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+
+public class CheckProvider {
+    public static void main(String[] args) {
+        Class<?> c = AsynchronousChannelProvider.provider().getClass();
+
+        String expected = args[0];
+        String actual = c.getName();
+
+        if (!actual.equals(expected))
+            throw new RuntimeException("Provider is of type '" + actual +
+                "', expected '" + expected + "'");
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/META-INF/services/java.nio.channels.spi.AsynchronousChannelProvider	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,1 @@
+Provider1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider1.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.nio.channels.*;
+import java.net.ProtocolFamily;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.io.IOException;
+
+public class Provider1 extends AsynchronousChannelProvider {
+    public Provider1() {
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factorry)
+        throws IOException
+    {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
+        throws IOException
+    {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public AsynchronousSocketChannel openAsynchronousSocketChannel
+        (AsynchronousChannelGroup group) throws IOException
+    {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel
+        (AsynchronousChannelGroup group) throws IOException
+    {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public AsynchronousDatagramChannel openAsynchronousDatagramChannel
+        (ProtocolFamily family, AsynchronousChannelGroup group) throws IOException
+    {
+        throw new RuntimeException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider2.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.nio.channels.*;
+import java.net.ProtocolFamily;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.io.IOException;
+
+public class Provider2 extends AsynchronousChannelProvider {
+    public Provider2() {
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup
+        (int nThreads, ThreadFactory threadFactory) throws IOException
+    {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup
+        (ExecutorService executor, int initialSize) throws IOException
+    {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public AsynchronousSocketChannel openAsynchronousSocketChannel
+        (AsynchronousChannelGroup group) throws IOException
+    {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel
+        (AsynchronousChannelGroup group) throws IOException
+    {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public AsynchronousDatagramChannel openAsynchronousDatagramChannel
+        (ProtocolFamily family, AsynchronousChannelGroup group) throws IOException
+    {
+        throw new RuntimeException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/custom_provider.sh	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,71 @@
+#
+# Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+# @test
+# @summary Unit test for java.nio.channels.spi.AsynchronousChannelProvider
+# @build Provider1 Provider2 CheckProvider
+# @run shell custom_provider.sh
+
+# if TESTJAVA isn't set then we assume an interactive run.
+
+if [ -z "$TESTJAVA" ]; then
+    TESTSRC=.
+    TESTCLASSES=.
+    JAVA=java
+else
+    JAVA="${TESTJAVA}/bin/java"
+fi
+
+OS=`uname -s`
+case "$OS" in
+    Windows_* )
+        CLASSPATH="${TESTCLASSES};${TESTSRC}"
+        ;;
+    * )
+        CLASSPATH=${TESTCLASSES}:${TESTSRC}
+        ;;
+esac
+export CLASSPATH
+
+failures=0
+
+go() {
+    echo ''
+    $JAVA $1 $2 $3 2>&1
+    if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
+}
+
+# Run the tests
+
+go CheckProvider Provider1
+go -Djava.nio.channels.spi.AsynchronousChannelProvider=Provider2 CheckProvider \
+  Provider2
+
+#
+# Results
+#
+echo ''
+if [ $failures -gt 0 ];
+  then echo "$failures test(s) failed";
+  else echo "All test(s) passed"; fi
+exit $failures
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/DirectoryStream/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.DirectoryStream
+ * @library ..
+ */
+
+import java.nio.file.*;
+import java.util.*;
+import java.io.IOException;
+
+public class Basic {
+    static boolean found;
+
+    static void doTest(final Path dir) throws IOException {
+        DirectoryStream<Path> stream;
+
+        // test that directory is empty
+        Files.withDirectory(dir, new FileAction<FileRef>() {
+            public void invoke(FileRef entry) {
+                throw new RuntimeException("directory not empty");
+            }
+        });
+
+        // create file in directory
+        final Path foo = Paths.get("foo");
+        dir.resolve(foo).createFile();
+
+        // iterate over directory and check there is one entry
+        found = false;
+        Files.withDirectory(dir, new FileAction<Path>() {
+            public void invoke(Path entry) {
+                if (entry.getName().equals(foo)) {
+                    if (found)
+                        throw new RuntimeException("entry already found");
+                    found = true;
+                } else {
+                    throw new RuntimeException("entry " + entry.getName() +
+                        " not expected");
+                }
+            }
+        });
+        if (!found)
+            throw new RuntimeException("entry not found");
+
+        // check filtering: f* should match foo
+        DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
+            private PathMatcher matcher =
+                dir.getFileSystem().getPathMatcher("glob:f*");
+            public boolean accept(Path file) {
+                return matcher.matches(file);
+            }
+        };
+        Files.withDirectory(dir, filter, new FileAction<Path>() {
+            public void invoke(Path entry) {
+                if (!entry.getName().equals(foo))
+                    throw new RuntimeException("entry not expected");
+            }
+        });
+
+        // check filtering: z* should not match any files
+        filter = new DirectoryStream.Filter<Path>() {
+            private PathMatcher matcher =
+                dir.getFileSystem().getPathMatcher("glob:z*");
+            public boolean accept(Path file) {
+                return matcher.matches(file);
+            }
+        };
+        Files.withDirectory(dir, filter, new FileAction<FileRef>() {
+            public void invoke(FileRef entry) {
+                throw new RuntimeException("no matching entries expected");
+            }
+        });
+
+        // check that exception or error thrown by filter is not thrown
+        // by newDirectoryStream or iterator method.
+        stream = dir.newDirectoryStream(new DirectoryStream.Filter<Path>() {
+            public boolean accept(Path file) {
+                throw new RuntimeException("Should not be visible");
+            }
+        });
+        try {
+            stream.iterator();
+        } finally {
+            stream.close();
+        }
+
+        // test NotDirectoryException
+        try {
+            dir.resolve(foo).newDirectoryStream();
+            throw new RuntimeException("NotDirectoryException not thrown");
+        } catch (NotDirectoryException x) {
+        }
+
+        // test iterator remove method
+        stream = dir.newDirectoryStream();
+        Iterator<Path> i = stream.iterator();
+        while (i.hasNext()) {
+            Path entry = i.next();
+            if (!entry.getName().equals(foo))
+                throw new RuntimeException("entry not expected");
+            i.remove();
+        }
+        stream.close();
+
+        // test IllegalStateException
+        stream =  dir.newDirectoryStream();
+        i = stream.iterator();
+        try {
+            stream.iterator();
+            throw new RuntimeException("IllegalStateException not thrown as expected");
+        } catch (IllegalStateException x) {
+        }
+        stream.close();
+        try {
+            stream.iterator();
+            throw new RuntimeException("IllegalStateException not thrown as expected");
+        } catch (IllegalStateException x) {
+        }
+        try {
+            i.hasNext();
+            throw new RuntimeException("ConcurrentModificationException not thrown as expected");
+        } catch (ConcurrentModificationException x) {
+            Throwable t = x.getCause();
+            if (!(t instanceof IllegalStateException))
+                throw new RuntimeException("Cause is not IllegalStateException as expected");
+        }
+        try {
+            i.next();
+            throw new RuntimeException("IllegalStateException not thrown as expected");
+        } catch (ConcurrentModificationException x) {
+            Throwable t = x.getCause();
+            if (!(t instanceof IllegalStateException))
+                throw new RuntimeException("Cause is not IllegalStateException as expected");
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            doTest(dir);
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/DirectoryStream/Filters.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.DirectoryStreamFilters
+ * @library ..
+ */
+
+import java.nio.file.*;
+import static java.nio.file.DirectoryStreamFilters.*;
+import java.nio.file.attribute.Attributes;
+import java.io.*;
+import java.util.*;
+
+public class Filters {
+    static final Random rand = new Random();
+
+    // returns a filter that only accepts files that are larger than a given size
+    static DirectoryStream.Filter<FileRef> newMinimumSizeFilter(final long min) {
+        return new DirectoryStream.Filter<FileRef>() {
+            public boolean accept(FileRef file) {
+                try {
+                    long size = Attributes.readBasicFileAttributes(file).size();
+                    return size >= min;
+                } catch (IOException e) {
+                    throw new IOError(e);
+                }
+            }
+        };
+    }
+
+    // returns a filter that only accepts files that are matched by a given glob
+    static DirectoryStream.Filter<Path> newGlobFilter(final String glob) {
+        return new DirectoryStream.Filter<Path>() {
+            PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:"+ glob);
+            public boolean accept(Path file) {
+                return matcher.matches(file.getName());
+            }
+        };
+    }
+
+    static final int BIG_FILE_THRESHOLD = 8192;
+
+    static int totalCount;
+    static int htmlCount;
+    static int bigAndHtmlCount;
+    static int bigOrHtmlCount;
+
+    // generates random files in the test directory and initializes the counts
+    static void setup(Path dir) throws IOException {
+        // create 10-26 files.
+        totalCount = 10 + rand.nextInt(17);
+        char firstChar = 'A';
+        for (int i=0; i<totalCount; i++) {
+            boolean isHtml = rand.nextBoolean();
+            boolean isBig = rand.nextBoolean();
+            if (isHtml) {
+                htmlCount++;
+                if (isBig) bigAndHtmlCount++;
+            }
+            if (isHtml || isBig)
+                bigOrHtmlCount++;
+            String name;
+            if (isHtml) {
+                name = firstChar + ".html";
+            } else {
+                name = firstChar + ".tmp";
+            }
+            firstChar++;
+            int size = rand.nextInt(BIG_FILE_THRESHOLD);
+            if (isBig)
+                size += BIG_FILE_THRESHOLD;
+            Path file = dir.resolve(name);
+            OutputStream out = file.newOutputStream();
+            try {
+                if (size > 0)
+                    out.write(new byte[size]);
+            } finally {
+                out.close();
+            }
+            System.out.format("Created %s, size %d byte(s)\n", name, size);
+        }
+    }
+
+    static boolean isHtml(Path file) {
+        return file.toString().endsWith(".html");
+    }
+
+    static boolean isBig(Path file) throws IOException {
+        long size = Attributes.readBasicFileAttributes(file).size();
+        return size >= BIG_FILE_THRESHOLD;
+    }
+
+    static void checkCount(int expected, int actual) {
+        if (actual != expected)
+            throw new RuntimeException("'" + expected +
+                "' entries expected, actual: " + actual);
+    }
+
+    static void doTests(Path dir) throws IOException {
+        final List<DirectoryStream.Filter<Path>> emptyList = Collections.emptyList();
+
+        // list containing two filters
+        List<DirectoryStream.Filter<? super Path>> filters =
+            new ArrayList<DirectoryStream.Filter<? super Path>>();
+        filters.add(newMinimumSizeFilter(BIG_FILE_THRESHOLD));
+        filters.add(newGlobFilter("*.html"));
+
+        int accepted;
+        DirectoryStream<Path> stream;
+
+        System.out.println("Test: newContentTypeFilter");
+        accepted = 0;
+        stream = dir.newDirectoryStream(newContentTypeFilter("text/html"));
+        try {
+            for (Path entry: stream) {
+                if (!isHtml(entry))
+                    throw new RuntimeException("html file expected");
+                accepted++;
+            }
+        } finally {
+            stream.close();
+        }
+        checkCount(htmlCount, accepted);
+
+        System.out.println("Test: allOf with list of filters");
+        accepted = 0;
+        stream = dir.newDirectoryStream(allOf(filters));
+        try {
+            for (Path entry: stream) {
+                if (!isHtml(entry))
+                    throw new RuntimeException("html file expected");
+                if (!isBig(entry))
+                    throw new RuntimeException("big file expected");
+                accepted++;
+            }
+        } finally {
+            stream.close();
+        }
+        checkCount(bigAndHtmlCount, accepted);
+
+        System.out.println("Test: allOf with empty list");
+        accepted = 0;
+        stream = dir.newDirectoryStream(allOf(emptyList));
+        try {
+            for (Path entry: stream) {
+                accepted++;
+            }
+        } finally {
+            stream.close();
+        }
+        checkCount(totalCount, accepted);
+
+        System.out.println("Test: anyOf with list of filters");
+        accepted = 0;
+        stream = dir.newDirectoryStream(anyOf(filters));
+        try {
+            for (Path entry: stream) {
+                if (!isHtml(entry) && !isBig(entry))
+                    throw new RuntimeException("html or big file expected");
+                accepted++;
+            }
+        } finally {
+            stream.close();
+        }
+        checkCount(bigOrHtmlCount, accepted);
+
+        System.out.println("Test: anyOf with empty list");
+        accepted = 0;
+        stream = dir.newDirectoryStream(anyOf(emptyList));
+        try {
+            for (Path entry: stream) {
+                accepted++;
+            }
+        } finally {
+            stream.close();
+        }
+        checkCount(0, accepted);
+
+        System.out.println("Test: complementOf");
+        accepted = 0;
+        stream = dir.newDirectoryStream(complementOf(newGlobFilter("*.html")));
+        try {
+            for (Path entry: stream) {
+                accepted++;
+            }
+        } finally {
+            stream.close();
+        }
+        checkCount(totalCount-htmlCount, accepted);
+
+        System.out.println("Test: nulls");
+        try {
+            newContentTypeFilter(null);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException npe) { }
+        try {
+            allOf(null);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException npe) { }
+        try {
+            anyOf(null);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException npe) { }
+        try {
+            complementOf(null);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException npe) { }
+    }
+
+    public static void main(String[] args) throws IOException {
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            setup(dir);
+            doTests(dir);
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/DirectoryStream/SecureDS.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.SecureDirectoryStream
+ * @library ..
+ */
+
+import java.nio.file.*;
+import static java.nio.file.StandardOpenOption.*;
+import static java.nio.file.LinkOption.*;
+import java.nio.file.attribute.*;
+import java.nio.channels.*;
+import java.io.IOException;
+import java.util.*;
+
+public class SecureDS {
+    static boolean supportsLinks;
+
+    public static void main(String[] args) throws IOException {
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            DirectoryStream stream = dir.newDirectoryStream();
+            stream.close();
+            if (!(stream instanceof SecureDirectoryStream)) {
+                System.out.println("SecureDirectoryStream not supported.");
+                return;
+            }
+
+            supportsLinks = TestUtil.supportsLinks(dir);
+
+            // run tests
+            doBasicTests(dir);
+            doMoveTests(dir);
+            miscTests(dir);
+
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+
+    // Exercise each of SecureDirectoryStream's method (except move)
+    static void doBasicTests(Path dir) throws IOException {
+        Path dir1 = dir.resolve("dir1").createDirectory();
+        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();
+        Path dirEntry = Paths.get("mydir");
+        dir1.resolve(dirEntry).createDirectory();
+        // myfilelink -> myfile
+        Path link1Entry = Paths.get("myfilelink");
+        if (supportsLinks)
+            dir1.resolve(link1Entry).createSymbolicLink(fileEntry);
+        // mydirlink -> mydir
+        Path link2Entry = Paths.get("mydirlink");
+        if (supportsLinks)
+            dir1.resolve(link2Entry).createSymbolicLink(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);
+
+        // Test: iterate over all entries
+        int count = 0;
+        for (Path entry: stream) { count++; }
+        assertTrue(count == (supportsLinks ? 4 : 2));
+
+        // Test: getFileAttributeView to access directory's attributes
+        assertTrue(stream
+            .getFileAttributeView(BasicFileAttributeView.class)
+                .readAttributes()
+                    .isDirectory());
+
+        // Test: dynamic access to directory's attributes
+        BasicFileAttributeView view = stream.
+            getFileAttributeView(BasicFileAttributeView.class);
+        Map<String,?> attrs = view.readAttributes("*");
+        assertTrue((Boolean)attrs.get("isDirectory"));
+        attrs = view.readAttributes("isRegularFile", "size");
+        assertTrue(!(Boolean)attrs.get("isRegularFile"));
+        assertTrue((Long)attrs.get("size") >= 0);
+        int linkCount = (Integer)view.getAttribute("linkCount");
+        assertTrue(linkCount > 0);
+        view.setAttribute("lastModifiedTime", 0L);
+
+        // Test: getFileAttributeView to access attributes of entries
+        assertTrue(stream
+            .getFileAttributeView(fileEntry, BasicFileAttributeView.class)
+                .readAttributes()
+                    .isRegularFile());
+        assertTrue(stream
+            .getFileAttributeView(fileEntry, BasicFileAttributeView.class, NOFOLLOW_LINKS)
+                .readAttributes()
+                    .isRegularFile());
+        assertTrue(stream
+            .getFileAttributeView(dirEntry, BasicFileAttributeView.class)
+                .readAttributes()
+                    .isDirectory());
+        assertTrue(stream
+            .getFileAttributeView(dirEntry, BasicFileAttributeView.class, NOFOLLOW_LINKS)
+                .readAttributes()
+                    .isDirectory());
+        if (supportsLinks) {
+            assertTrue(stream
+                .getFileAttributeView(link1Entry, BasicFileAttributeView.class)
+                    .readAttributes()
+                        .isRegularFile());
+            assertTrue(stream
+                .getFileAttributeView(link1Entry, BasicFileAttributeView.class, NOFOLLOW_LINKS)
+                    .readAttributes()
+                        .isSymbolicLink());
+            assertTrue(stream
+                .getFileAttributeView(link2Entry, BasicFileAttributeView.class)
+                    .readAttributes()
+                        .isDirectory());
+            assertTrue(stream
+                .getFileAttributeView(link2Entry, BasicFileAttributeView.class, NOFOLLOW_LINKS)
+                    .readAttributes()
+                        .isSymbolicLink());
+        }
+
+        // Test: dynamic access to entry attributes
+        view = stream
+             .getFileAttributeView(fileEntry, PosixFileAttributeView.class, NOFOLLOW_LINKS);
+        if (view != null) {
+            attrs = view.readAttributes("owner", "size");
+            UserPrincipal owner = (UserPrincipal)attrs.get("owner");
+            assertTrue(owner != null);
+            assertTrue((Long)attrs.get("size") >= 0L);
+            view.setAttribute("lastAccessTime", 0L);
+        }
+
+        // Test: newByteChannel
+        Set<StandardOpenOption> opts = Collections.emptySet();
+        stream.newByteChannel(fileEntry, opts).close();
+        if (supportsLinks) {
+            stream.newByteChannel(link1Entry, opts).close();
+            try {
+                Set<OpenOption> mixed = new HashSet<OpenOption>();
+                mixed.add(READ);
+                mixed.add(NOFOLLOW_LINKS);
+                stream.newByteChannel(link1Entry, mixed).close();
+                shouldNotGetHere();
+            } catch (IOException x) { }
+        }
+
+        // Test: newDirectoryStream
+        stream.newDirectoryStream(dirEntry, true, null).close();
+        stream.newDirectoryStream(dirEntry, false, null).close();
+        if (supportsLinks) {
+            stream.newDirectoryStream(link2Entry, true, null).close();
+            try {
+                stream.newDirectoryStream(link2Entry, false, null).close();
+                shouldNotGetHere();
+            } catch (IOException x) { }
+        }
+
+        // Test: delete
+        if (supportsLinks) {
+            stream.deleteFile(link1Entry);
+            stream.deleteFile(link2Entry);
+        }
+        stream.deleteDirectory(dirEntry);
+        stream.deleteFile(fileEntry);
+
+        // Test: remove
+        // (requires resetting environment to get new iterator)
+        stream.close();
+        dir2.moveTo(dir1);
+        dir1.resolve(fileEntry).createFile();
+        stream = (SecureDirectoryStream)dir1.newDirectoryStream();
+        dir1.moveTo(dir2);
+        Iterator<Path> iter = stream.iterator();
+        int removed = 0;
+        while (iter.hasNext()) {
+            iter.next();
+            iter.remove();
+            removed++;
+        }
+        assertTrue(removed == 1);
+
+        // clean-up
+        stream.close();
+        dir2.delete();
+    }
+
+    // Exercise SecureDirectoryStream's move method
+    static void doMoveTests(Path dir) throws IOException {
+        Path dir1 = dir.resolve("dir1").createDirectory();
+        Path dir2 = dir.resolve("dir2").createDirectory();
+
+        // create dir1/myfile, dir1/mydir, dir1/mylink
+        Path fileEntry = Paths.get("myfile");
+        dir1.resolve(fileEntry).createFile();
+        Path dirEntry = Paths.get("mydir");
+        dir1.resolve(dirEntry).createDirectory();
+        Path linkEntry = Paths.get("mylink");
+        if (supportsLinks)
+            dir1.resolve(linkEntry).createSymbolicLink(Paths.get("missing"));
+
+        // target name
+        Path target = Paths.get("newfile");
+
+        // open stream to both directories
+        SecureDirectoryStream stream1 =
+            (SecureDirectoryStream)dir1.newDirectoryStream();
+        SecureDirectoryStream stream2 =
+            (SecureDirectoryStream)dir2.newDirectoryStream();
+
+        // Test: move dir1/myfile -> dir2/newfile
+        stream1.move(fileEntry, stream2, target);
+        assertTrue(dir1.resolve(fileEntry).notExists());
+        assertTrue(dir2.resolve(target).exists());
+        stream2.deleteFile(target);
+
+        // Test: move dir1/mydir -> dir2/newfile
+        stream1.move(dirEntry, stream2, target);
+        assertTrue(dir1.resolve(dirEntry).notExists());
+        assertTrue(dir2.resolve(target).exists());
+        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());
+            stream2.deleteFile(target);
+        }
+
+        // Test: move between devices
+        String testDirAsString = System.getProperty("test.dir");
+        if (testDirAsString != null) {
+            Path testDir = Paths.get(testDirAsString);
+            if (!dir1.getFileStore().equals(testDir.getFileStore())) {
+                SecureDirectoryStream ts =
+                    (SecureDirectoryStream)testDir.newDirectoryStream();
+                dir1.resolve(fileEntry).createFile();
+                try {
+                    stream1.move(fileEntry, ts, target);
+                    shouldNotGetHere();
+                } catch (AtomicMoveNotSupportedException x) { }
+                ts.close();
+                stream1.deleteFile(fileEntry);
+            }
+        }
+
+        // clean-up
+        dir1.delete();
+        dir2.delete();
+    }
+
+    // null and ClosedDirectoryStreamException
+    static void miscTests(Path dir) throws IOException {
+        Path file = Paths.get("file");
+        dir.resolve(file).createFile();
+
+        SecureDirectoryStream stream =
+            (SecureDirectoryStream)dir.newDirectoryStream();
+
+        // NullPointerException
+        try {
+            stream.getFileAttributeView(null);
+            shouldNotGetHere();
+        } catch (NullPointerException x) { }
+        try {
+            stream.getFileAttributeView(null, BasicFileAttributeView.class);
+            shouldNotGetHere();
+        } catch (NullPointerException x) { }
+        try {
+            stream.getFileAttributeView(file, null);
+            shouldNotGetHere();
+        } catch (NullPointerException x) { }
+        try {
+            stream.newByteChannel(null, EnumSet.of(CREATE,WRITE));
+            shouldNotGetHere();
+        } catch (NullPointerException x) { }
+        try {
+            stream.newByteChannel(null, EnumSet.of(CREATE,WRITE,null));
+            shouldNotGetHere();
+        } catch (NullPointerException x) { }
+        try {
+            stream.newByteChannel(file, null);
+            shouldNotGetHere();
+        } catch (NullPointerException x) { }
+        try {
+            stream.move(null, stream, file);
+            shouldNotGetHere();
+        } catch (NullPointerException x) { }
+        try {
+            stream.move(file, null, file);
+            shouldNotGetHere();
+        } catch (NullPointerException x) { }
+        try {
+            stream.move(file, stream, null);
+            shouldNotGetHere();
+        } catch (NullPointerException x) { }
+        try {
+            stream.newDirectoryStream(null, true, null);
+            shouldNotGetHere();
+        } catch (NullPointerException x) { }
+        try {
+            stream.deleteFile(null);
+            shouldNotGetHere();
+        } catch (NullPointerException x) { }
+        try {
+            stream.deleteDirectory(null);
+            shouldNotGetHere();
+        } catch (NullPointerException x) { }
+
+        // close stream
+        stream.close();
+        stream.close();     // should be no-op
+
+        // ClosedDirectoryStreamException
+        try {
+            stream.newDirectoryStream(file, true, null);
+            shouldNotGetHere();
+        } catch (ClosedDirectoryStreamException x) { }
+        try {
+            stream.newByteChannel(file, EnumSet.of(READ));
+            shouldNotGetHere();
+        } catch (ClosedDirectoryStreamException x) { }
+        try {
+            stream.move(file, stream, file);
+            shouldNotGetHere();
+        } catch (ClosedDirectoryStreamException x) { }
+        try {
+            stream.deleteFile(file);
+            shouldNotGetHere();
+        } catch (ClosedDirectoryStreamException x) { }
+
+        // clean-up
+        dir.resolve(file).delete();
+    }
+
+    static void assertTrue(boolean b) {
+        if (!b) throw new RuntimeException("Assertion failed");
+    }
+
+    static void shouldNotGetHere() {
+        assertTrue(false);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/FileStore/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.FileStore
+ * @library ..
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+
+public class Basic {
+
+    public static void main(String[] args) throws IOException {
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            doTests(dir);
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+
+    static void assertTrue(boolean okay) {
+        if (!okay)
+            throw new RuntimeException("Assertion failed");
+    }
+
+    static void doTests(Path dir) throws IOException {
+        /**
+         * Test: Directory should be on FileStore that is writable
+         */
+        assertTrue(!dir.getFileStore().isReadOnly());
+
+        /**
+         * Test: Two files should have the same FileStore
+         */
+        FileStore store1 = dir.resolve("foo").createFile().getFileStore();
+        FileStore store2 = dir.resolve("bar").createFile().getFileStore();
+        assertTrue(store1.equals(store2));
+        assertTrue(store2.equals(store1));
+        assertTrue(store1.hashCode() == store2.hashCode());
+
+        /**
+         * Test: File and FileStore attributes
+         */
+        assertTrue(store1.supportsFileAttributeView("basic"));
+
+        /**
+         * Test: Enumerate all FileStores
+         */
+        FileStore prev = null;
+        for (FileStore store: FileSystems.getDefault().getFileStores()) {
+            System.out.format("%s (name=%s type=%s)\n", store, store.name(),
+                store.type());
+
+            // check space attributes
+            Attributes.readFileStoreSpaceAttributes(store);
+
+            // two distinct FileStores should not be equal
+            assertTrue(!store.equals(prev));
+            prev = store;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/FileSystem/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.FileSystem
+ * @library ..
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+
+/**
+ * Simple santity checks for java.nio.file.FileSystem
+ */
+public class Basic {
+
+    static void check(boolean okay, String msg) {
+        if (!okay)
+            throw new RuntimeException(msg);
+    }
+
+    static void checkSupported(FileSystem fs, String... views) {
+        for (String view: views) {
+            check(fs.supportedFileAttributeViews().contains(view),
+                "support for '" + view + "' expected");
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        FileSystem fs = FileSystems.getDefault();
+
+        // close should throw UOE
+        try {
+            fs.close();
+            throw new RuntimeException("UnsupportedOperationException expected");
+        } catch (UnsupportedOperationException e) { }
+        check(fs.isOpen(), "should be open");
+
+        check(!fs.isReadOnly(), "should provide read-write access");
+
+        check(fs.provider().getScheme().equals("file"),
+            "should use 'file' scheme");
+
+        // santity check method - need to re-visit this in future as I/O errors
+        // are possible
+        for (FileStore store: fs.getFileStores()) {
+            System.out.println(store);
+        }
+
+        // sanity check supportedFileAttributeViews
+        checkSupported(fs, "basic");
+        String os = System.getProperty("os.name");
+        if (os.equals("SunOS"))
+            checkSupported(fs, "posix", "unix", "owner", "acl", "xattr");
+        if (os.equals("Linux"))
+            checkSupported(fs, "posix", "unix", "owner", "dos", "xattr");
+        if (os.equals("Windows"))
+            checkSupported(fs, "owner", "dos", "acl", "xattr");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Files/ContentType.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.nio.file.*;
+import java.io.*;
+
+/**
+ * Uses Files.probeContentType to probe html file and custom file type.
+ */
+
+public class ContentType {
+
+    static FileRef createHtmlFile() throws IOException {
+        Path file = File.createTempFile("foo", ".html").toPath();
+        OutputStream out = file.newOutputStream();
+        try {
+            out.write("<html><body>foo</body></html>".getBytes());
+        } finally {
+            out.close();
+        }
+
+        return file;
+    }
+
+    static FileRef createUnknownFile() throws IOException {
+        return File.createTempFile("unknown", "unknown-file-type-789").toPath();
+    }
+
+    static FileRef createGrapeFile() throws IOException {
+        return File.createTempFile("red", ".grape").toPath();
+    }
+
+    public static void main(String[] args) throws IOException {
+
+        // exercise default file type detector
+        FileRef file = createHtmlFile();
+        try {
+            String type = Files.probeContentType(file);
+            if (type == null) {
+                System.err.println("Content type cannot be determined - test skipped");
+            } else {
+                if (!type.equals("text/html"))
+                    throw new RuntimeException("Unexpected type: " + type);
+            }
+        } finally {
+            TestUtil.deleteUnchecked(file);
+        }
+        file = createUnknownFile();
+        try {
+            String type = Files.probeContentType(file);
+            if (type != null)
+                 throw new RuntimeException(file + " should not be recognized as:" +
+                     type);
+        } finally {
+            TestUtil.deleteUnchecked(file);
+        }
+
+        // exercise custom file type detector
+        file = createGrapeFile();
+        try {
+            String type = Files.probeContentType(file);
+            if (type == null)
+                throw new RuntimeException("Custom file type detector not installed?");
+            if (!type.equals("grape/unknown"))
+                throw new RuntimeException("Unexpected type: " + type);
+        } finally {
+            TestUtil.deleteUnchecked(file);
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Files/CreateFileTree.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.nio.file.*;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Creates a file tree with possible cycles caused by symbolic links
+ * to ancestor directories.
+ */
+
+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();
+
+        List<Path> dirs = new ArrayList<Path>();
+
+        // create tree
+        Queue<Path> queue = new ArrayDeque<Path>();
+        queue.add(top);
+        int total = 1 + rand.nextInt(20);
+        int n = 0;
+        Path dir;
+        while (((dir = queue.poll()) != null) && (n < total)) {
+            int r = Math.min((total-n), (1+rand.nextInt(3)));
+            for (int i=0; i<r; i++) {
+                String name = "dir" + (++n);
+                Path subdir = dir.resolve(name).createDirectory();
+                queue.offer(subdir);
+                dirs.add(subdir);
+            }
+        }
+        assert dirs.size() >= 2;
+
+        // create a few regular files in the file tree
+        int files = dirs.size() * 3;
+        for (int i=0; i<files; i++) {
+            String name = "file" + (i+1);
+            int x = rand.nextInt(dirs.size());
+            dirs.get(x).resolve(name).createFile();
+        }
+
+        // create a few sym links in the file tree so as to create cycles
+        int links = 1 + rand.nextInt(5);
+        for (int i=0; i<links; i++) {
+            int x = rand.nextInt(dirs.size());
+            int y;
+            do {
+                y = rand.nextInt(dirs.size());
+            } while (y != x);
+            String name = "link" + (i+1);
+            Path link = dirs.get(x).resolve(name);
+            Path target = dirs.get(y);
+            link.createSymbolicLink(target);
+        }
+
+        // done
+        System.out.println(top);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Files/ForceLoad.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Test library dependencies by invoking Files.probeContentType
+ *     before other methods that would cause nio.dll to be loaded.
+ */
+
+import java.nio.file.*;
+import java.io.IOException;
+
+public class ForceLoad {
+
+    public static void main(String[] args) throws IOException {
+        Files.probeContentType(Paths.get("."));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Files/META-INF/services/java.nio.file.spi.FileTypeDetector	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,1 @@
+SimpleFileTypeDetector
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Files/Misc.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.Files for miscellenous cases not
+ *   covered by other tests
+ * @library ..
+ */
+
+import java.nio.file.*;
+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 {
+        try {
+            Files.probeContentType(null);
+            npeExpected();
+        } catch (NullPointerException e) {
+        }
+
+        try {
+            Files.withDirectory(null, "*", new FileAction<Path>() {
+                public void invoke(Path entry) {
+                }
+            });
+            npeExpected();
+        } catch (NullPointerException e) {
+        }
+
+       try {
+            Files.withDirectory(Paths.get("."), (String)null, new FileAction<Path>() {
+                public void invoke(Path entry) {
+                }
+            });
+            npeExpected();
+        } catch (NullPointerException e) {
+        }
+
+        try {
+            Files.withDirectory(Paths.get("."), "*", null);
+            npeExpected();
+        } catch (NullPointerException e) {
+        }
+
+        // test propogation of IOException
+        Path tmpdir = TestUtil.createTemporaryDirectory();
+        try {
+            tmpdir.resolve("foo").createFile();
+            try {
+                Files.withDirectory(tmpdir, new FileAction<Path>() {
+                    public void invoke(Path entry) throws IOException {
+                        throw new IOException();
+                    }
+                });
+                throw new RuntimeException("IOException expected");
+            } catch (IOException e) {
+            }
+        } finally {
+            TestUtil.removeAll(tmpdir);
+        }
+
+        try {
+            Files.walkFileTree(null, EnumSet.noneOf(FileVisitOption.class),
+                Integer.MAX_VALUE, new SimpleFileVisitor<Path>(){});
+            npeExpected();
+        } catch (NullPointerException e) {
+        }
+
+        try {
+            Files.walkFileTree(Paths.get("."), null, Integer.MAX_VALUE,
+                new SimpleFileVisitor<Path>(){});
+            npeExpected();
+        } catch (NullPointerException e) {
+        }
+
+        try {
+            Files.walkFileTree(Paths.get("."), EnumSet.noneOf(FileVisitOption.class),
+                -1, new SimpleFileVisitor<Path>(){});
+            throw new RuntimeException("IllegalArgumentExpected expected");
+        } catch (IllegalArgumentException e) {
+        }
+
+        try {
+            Set<FileVisitOption> opts = new HashSet<FileVisitOption>(1);
+            opts.add(null);
+            Files.walkFileTree(Paths.get("."), opts, Integer.MAX_VALUE,
+                new SimpleFileVisitor<Path>(){});
+            npeExpected();
+        } catch (NullPointerException e) {
+        }
+
+        try {
+            Files.walkFileTree(Paths.get("."), EnumSet.noneOf(FileVisitOption.class),
+                Integer.MAX_VALUE, null);
+            npeExpected();
+        } catch (NullPointerException e) {
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Files/PrintFileTree.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Invokes Files.walkFileTree to traverse a file tree and prints
+ * each of the directories and files. The -L option causes symbolic
+ * links to be followed.
+ */
+
+public class PrintFileTree {
+
+    public static void main(String[] args) throws Exception {
+        boolean followLinks = false;
+        Path dir;
+
+        if (args[0].equals("-L")) {
+            followLinks = true;
+            dir = Paths.get(args[1]);
+        } else {
+            dir = Paths.get(args[0]);
+        }
+
+        Set<FileVisitOption> options = new HashSet<FileVisitOption>();
+        if (followLinks)
+            options.add(FileVisitOption.FOLLOW_LINKS);
+
+        Files.walkFileTree(dir, options, Integer.MAX_VALUE, new FileVisitor<FileRef>() {
+            public FileVisitResult preVisitDirectory(FileRef dir) {
+                System.out.println(dir);
+                return FileVisitResult.CONTINUE;
+            }
+            public FileVisitResult preVisitDirectoryFailed(FileRef dir, IOException exc) {
+                exc.printStackTrace();
+                return FileVisitResult.CONTINUE;
+            }
+            public FileVisitResult visitFile(FileRef file, BasicFileAttributes attrs) {
+                System.out.println(file);
+                return FileVisitResult.CONTINUE;
+            }
+            public FileVisitResult postVisitDirectory(FileRef dir, IOException exc) {
+                if (exc != null) {
+                    exc.printStackTrace();
+                    return FileVisitResult.TERMINATE;
+                }
+                return FileVisitResult.CONTINUE;
+            }
+            public FileVisitResult visitFileFailed(FileRef file, IOException exc) {
+                exc.printStackTrace();
+                return FileVisitResult.TERMINATE;
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Files/SimpleFileTypeDetector.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.nio.file.*;
+import java.nio.file.spi.FileTypeDetector;
+import java.io.*;
+
+
+public class SimpleFileTypeDetector extends FileTypeDetector {
+    public SimpleFileTypeDetector() {
+    }
+
+    public String probeContentType(FileRef 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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Files/SkipSiblings.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Unit test for Files.walkFileTree to test SKIP_SIBLINGS return value.
+ */
+
+public class SkipSiblings {
+
+    static final Random rand = new Random();
+    static final Set<Path> skipped = new HashSet<Path>();
+
+    // check if this path's directory has been skipped
+    static void check(Path path) {
+        if (skipped.contains(path.getParent()))
+            throw new RuntimeException(path + " should not have been visited");
+    }
+
+    // indicates if the siblings of this path should be skipped
+    static boolean skip(Path path) {
+        Path parent = path.getParent();
+        if (parent != null && rand.nextBoolean()) {
+            skipped.add(parent);
+            return true;
+        }
+        return false;
+    }
+
+    public static void main(String[] args) throws Exception {
+        Path dir = Paths.get(args[0]);
+
+        Files.walkFileTree(dir, new FileVisitor<Path>() {
+            public FileVisitResult preVisitDirectory(Path dir) {
+                check(dir);
+                if (skip(dir))
+                    return FileVisitResult.SKIP_SIBLINGS;
+                return FileVisitResult.CONTINUE;
+            }
+            public FileVisitResult preVisitDirectoryFailed(Path dir, IOException exc) {
+                throw new RuntimeException(exc);
+            }
+
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+                check(file);
+                if (skip(file))
+                    return FileVisitResult.SKIP_SIBLINGS;
+                return FileVisitResult.CONTINUE;
+            }
+            public FileVisitResult postVisitDirectory(Path dir, IOException x) {
+                if (x != null)
+                    throw new RuntimeException(x);
+                check(dir);
+                return FileVisitResult.CONTINUE;
+            }
+            public FileVisitResult visitFileFailed(Path file, IOException x) {
+                throw new RuntimeException(x);
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Files/TerminateWalk.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Unit test for Files.walkFileTree to test TERMINATE return value
+ */
+
+public class TerminateWalk {
+
+    static final Random rand = new Random();
+    static boolean terminated;
+
+    static FileVisitResult maybeTerminate() {
+        if (terminated)
+            throw new RuntimeException("FileVisitor invoked after termination");
+        if (rand.nextInt(10) == 0) {
+            terminated = true;
+            return FileVisitResult.TERMINATE;
+        } else {
+            return FileVisitResult.CONTINUE;
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        Path dir = Paths.get(args[0]);
+
+        Files.walkFileTree(dir, new FileVisitor<Path>() {
+            public FileVisitResult preVisitDirectory(Path dir) {
+                return maybeTerminate();
+            }
+            public FileVisitResult preVisitDirectoryFailed(Path dir, IOException exc) {
+                return maybeTerminate();
+            }
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+                return maybeTerminate();
+            }
+            public FileVisitResult postVisitDirectory(Path dir, IOException x) {
+                return maybeTerminate();
+            }
+            public FileVisitResult visitFileFailed(Path file, IOException x) {
+                return maybeTerminate();
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Files/content_type.sh	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,71 @@
+#
+# Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+# @test
+# @bug 4313887
+# @summary Unit test for probeContentType method
+# @library ..
+# @build ContentType SimpleFileTypeDetector
+# @run shell content_type.sh
+
+# if TESTJAVA isn't set then we assume an interactive run.
+
+if [ -z "$TESTJAVA" ]; then
+    TESTSRC=.
+    TESTCLASSES=.
+    JAVA=java
+else
+    JAVA="${TESTJAVA}/bin/java"
+fi
+
+OS=`uname -s`
+case "$OS" in
+    Windows_* )
+        CLASSPATH="${TESTCLASSES};${TESTSRC}"
+        ;;
+    * )
+        CLASSPATH=${TESTCLASSES}:${TESTSRC}
+        ;;
+esac
+export CLASSPATH
+
+failures=0
+
+go() {
+    echo ''
+    $JAVA $1 $2 $3 2>&1
+    if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
+}
+
+# Run the test
+
+go ContentType
+
+#
+# Results
+#
+echo ''
+if [ $failures -gt 0 ];
+  then echo "$failures test(s) failed";
+  else echo "All test(s) passed"; fi
+exit $failures
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Files/walk_file_tree.sh	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,86 @@
+#
+# Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+# @test
+# @bug 4313887
+# @summary Unit test for walkFileTree method
+# @build CreateFileTree PrintFileTree SkipSiblings TerminateWalk
+# @run shell walk_file_tree.sh
+
+# if TESTJAVA isn't set then we assume an interactive run.
+
+if [ -z "$TESTJAVA" ]; then
+    TESTSRC=.
+    TESTCLASSES=.
+    JAVA=java
+else
+    JAVA="${TESTJAVA}/bin/java"
+fi
+
+OS=`uname -s`
+case "$OS" in
+    Windows_* )
+        echo "This test does not run on Windows" 
+        exit 0
+        ;;
+    * )
+        CLASSPATH=${TESTCLASSES}:${TESTSRC}
+        ;;
+esac
+export CLASSPATH
+
+# create the file tree
+ROOT=`$JAVA CreateFileTree`
+if [ $? != 0 ]; then exit 1; fi
+
+failures=0
+
+# print the file tree and compare output with find(1)
+$JAVA PrintFileTree "$ROOT" > out1
+find "$ROOT" > out2
+diff out1 out2
+if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
+
+# repeat test following links (use -follow instead of -L
+# to allow running on older systems)
+$JAVA PrintFileTree -L "$ROOT" > out1
+find "$ROOT" -follow > out2
+diff out1 out2
+if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
+
+# test SKIP_SIBLINGS
+$JAVA SkipSiblings "$ROOT"
+if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
+
+# test TERMINATE
+$JAVA TerminateWalk "$ROOT"
+if [ $? != 0 ]; then failures=`expr $failures + 1`; fi
+
+# clean-up
+rm -r "$ROOT"
+
+echo ''
+if [ $failures -gt 0 ];
+  then echo "$failures test(s) failed";
+  else echo "Test passed"; fi
+exit $failures
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Path/CopyAndMove.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,983 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.Path copyTo/moveTo methods
+ * @library ..
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.file.*;
+import static java.nio.file.StandardCopyOption.*;
+import static java.nio.file.LinkOption.*;
+import java.nio.file.attribute.*;
+import java.io.*;
+import java.util.*;
+
+public class CopyAndMove {
+    static final Random rand = new Random();
+    static boolean heads() { return rand.nextBoolean(); }
+    static boolean supportsLinks;
+
+    public static void main(String[] args) throws Exception {
+        Path dir1 = TestUtil.createTemporaryDirectory();
+        try {
+            supportsLinks = TestUtil.supportsLinks(dir1);
+
+            // Exercise copyTo
+            doCopyTests(dir1);
+
+            // Exercise moveTo
+            // if test.dir differs to temporary file system then can test
+            // moving between devices
+            String testDir = System.getProperty("test.dir");
+            Path dir2 = (testDir != null) ? Paths.get(testDir) : dir1;
+            doMoveTests(dir1, dir2);
+
+        } finally {
+            TestUtil.removeAll(dir1);
+        }
+    }
+
+    static void checkBasicAttributes(BasicFileAttributes attrs1,
+                                     BasicFileAttributes attrs2)
+    {
+        // check file type
+        assertTrue(attrs1.isRegularFile() == attrs2.isRegularFile());
+        assertTrue(attrs1.isDirectory() == attrs2.isDirectory());
+        assertTrue(attrs1.isSymbolicLink() == attrs2.isSymbolicLink());
+        assertTrue(attrs1.isOther() == attrs2.isOther());
+
+        // check last modified time (assume millisecond precision)
+        long time1 = attrs1.resolution().toMillis(attrs1.lastModifiedTime());
+        long time2 = attrs1.resolution().toMillis(attrs2.lastModifiedTime());
+        assertTrue(time1 == time2);
+
+        // check size
+        if (attrs1.isRegularFile())
+            assertTrue(attrs1.size() == attrs2.size());
+    }
+
+    static void checkPosixAttributes(PosixFileAttributes attrs1,
+                                     PosixFileAttributes attrs2)
+    {
+        assertTrue(attrs1.permissions().equals(attrs2.permissions()));
+        assertTrue(attrs1.owner().equals(attrs2.owner()));
+        assertTrue(attrs1.group().equals(attrs2.group()));
+    }
+
+    static void checkDosAttributes(DosFileAttributes attrs1,
+                                   DosFileAttributes attrs2)
+    {
+        assertTrue(attrs1.isReadOnly() == attrs2.isReadOnly());
+        assertTrue(attrs1.isHidden() == attrs2.isHidden());
+        assertTrue(attrs1.isArchive() == attrs2.isArchive());
+        assertTrue(attrs1.isSystem() == attrs2.isSystem());
+    }
+
+    static void checkUserDefinedFileAttributes(Map<String,ByteBuffer> attrs1,
+                                     Map<String,ByteBuffer> attrs2)
+    {
+        assert attrs1.size() == attrs2.size();
+        for (String name: attrs1.keySet()) {
+            ByteBuffer bb1 = attrs1.get(name);
+            ByteBuffer bb2 = attrs2.get(name);
+            assertTrue(bb2 != null);
+            assertTrue(bb1.equals(bb2));
+        }
+    }
+
+    static Map<String,ByteBuffer> readUserDefinedFileAttributes(Path file)
+        throws IOException
+    {
+        UserDefinedFileAttributeView view = file
+            .getFileAttributeView(UserDefinedFileAttributeView.class);
+        Map<String,ByteBuffer> result = new HashMap<String,ByteBuffer>();
+        for (String name: view.list()) {
+            int size = view.size(name);
+            ByteBuffer bb = ByteBuffer.allocate(size);
+            int n = view.read(name, bb);
+            assertTrue(n == size);
+            bb.flip();
+            result.put(name, bb);
+        }
+        return result;
+    }
+
+    // move source to target with verification
+    static void moveAndVerify(Path source, Path target, CopyOption... options)
+        throws IOException
+    {
+        // read attributes before file is moved
+        BasicFileAttributes basicAttributes = null;
+        PosixFileAttributes posixAttributes = null;
+        DosFileAttributes dosAttributes = null;
+        Map<String,ByteBuffer> namedAttributes = null;
+
+        // 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);
+            basicAttributes = posixAttributes;
+        }
+        if (os.startsWith("Windows")) {
+            dosAttributes = Attributes.readDosFileAttributes(source, NOFOLLOW_LINKS);
+            basicAttributes = dosAttributes;
+        }
+        if (basicAttributes == null)
+            basicAttributes = Attributes.readBasicFileAttributes(source, NOFOLLOW_LINKS);
+
+        // hash file contents if regular file
+        int hash = (basicAttributes.isRegularFile()) ? computeHash(source) : 0;
+
+        // record link target if symbolic link
+        Path linkTarget = null;
+        if (basicAttributes.isSymbolicLink())
+            linkTarget = source.readSymbolicLink();
+
+        // read named attributes if available (and file is not a sym link)
+        if (!basicAttributes.isSymbolicLink() &&
+            source.getFileStore().supportsFileAttributeView("xattr"))
+        {
+            namedAttributes = readUserDefinedFileAttributes(source);
+        }
+
+        // move file
+        source.moveTo(target, options);
+
+        // verify source does not exist
+        assertTrue(source.notExists());
+
+        // verify file contents
+        if (basicAttributes.isRegularFile()) {
+            if (computeHash(target) != hash)
+                throw new RuntimeException("Failed to verify move of regular file");
+        }
+
+        // verify link target
+        if (basicAttributes.isSymbolicLink()) {
+            if (!target.readSymbolicLink().equals(linkTarget))
+                throw new RuntimeException("Failed to verify move of symbolic link");
+        }
+
+        // verify basic attributes
+        checkBasicAttributes(basicAttributes,
+            Attributes.readBasicFileAttributes(target, NOFOLLOW_LINKS));
+
+        // verify POSIX attributes
+        if (posixAttributes != null && !basicAttributes.isSymbolicLink()) {
+            checkPosixAttributes(posixAttributes,
+                Attributes.readPosixFileAttributes(target, NOFOLLOW_LINKS));
+        }
+
+        // verify DOS attributes
+        if (dosAttributes != null && !basicAttributes.isSymbolicLink()) {
+            checkDosAttributes(dosAttributes,
+                Attributes.readDosFileAttributes(target, NOFOLLOW_LINKS));
+        }
+
+        // verify named attributes
+        if (namedAttributes != null &&
+            target.getFileStore().supportsFileAttributeView("xattr"))
+        {
+            checkUserDefinedFileAttributes(namedAttributes, readUserDefinedFileAttributes(target));
+        }
+    }
+
+    /**
+     * Tests all possible ways to invoke moveTo
+     */
+    static void doMoveTests(Path dir1, Path dir2) throws IOException {
+        Path source, target, entry;
+
+        boolean sameDevice = dir1.getFileStore().equals(dir2.getFileStore());
+
+        // -- regular file --
+
+        /**
+         * Test: move regular file, target does not exist
+         */
+        source = createSourceFile(dir1);
+        target = getTargetFile(dir1);
+        moveAndVerify(source, target);
+        target.delete();
+
+        /**
+         * Test: move regular file, target exists
+         */
+        source = createSourceFile(dir1);
+        target = getTargetFile(dir1).createFile();
+        try {
+            moveAndVerify(source, target);
+            throw new RuntimeException("FileAlreadyExistsException expected");
+        } catch (FileAlreadyExistsException x) {
+        }
+        target.delete();
+        target.createDirectory();
+        try {
+            moveAndVerify(source, target);
+            throw new RuntimeException("FileAlreadyExistsException expected");
+        } catch (FileAlreadyExistsException x) {
+        }
+        source.delete();
+        target.delete();
+
+        /**
+         * Test: move regular file, target does not exist
+         */
+        source = createSourceFile(dir1);
+        target = getTargetFile(dir1);
+        moveAndVerify(source, target, REPLACE_EXISTING);
+        target.delete();
+
+        /**
+         * Test: move regular file, target exists
+         */
+        source = createSourceFile(dir1);
+        target = getTargetFile(dir1).createFile();
+        moveAndVerify(source, target, REPLACE_EXISTING);
+        target.delete();
+
+        /**
+         * Test: move regular file, target exists and is empty directory
+         */
+        source = createSourceFile(dir1);
+        target = getTargetFile(dir1).createDirectory();
+        moveAndVerify(source, target, REPLACE_EXISTING);
+        target.delete();
+
+        /**
+         * Test: move regular file, target exists and is non-empty directory
+         */
+        source = createSourceFile(dir1);
+        target = getTargetFile(dir1).createDirectory();
+        entry = target.resolve("foo").createFile();
+        try {
+            moveAndVerify(source, target);
+            throw new RuntimeException("FileAlreadyExistsException expected");
+        } catch (FileAlreadyExistsException x) {
+        }
+        entry.delete();
+        source.delete();
+        target.delete();
+
+        /**
+         * Test atomic move of regular file (same file store)
+         */
+        source = createSourceFile(dir1);
+        target = getTargetFile(dir1);
+        moveAndVerify(source, target, ATOMIC_MOVE);
+        target.delete();
+
+        /**
+         * Test atomic move of regular file (different file store)
+         */
+        if (!sameDevice) {
+            source = createSourceFile(dir1);
+            target = getTargetFile(dir2);
+            try {
+                moveAndVerify(source, target, ATOMIC_MOVE);
+                throw new RuntimeException("AtomicMoveNotSupportedException expected");
+            } catch (AtomicMoveNotSupportedException x) {
+            }
+            source.delete();
+        }
+
+        // -- directories --
+
+        /*
+         * Test: move empty directory, target does not exist
+         */
+        source = createSourceDirectory(dir1);
+        target = getTargetFile(dir1);
+        moveAndVerify(source, target);
+        target.delete();
+
+        /**
+         * Test: move empty directory, target exists
+         */
+        source = createSourceDirectory(dir1);
+        target = getTargetFile(dir1).createFile();
+        try {
+            moveAndVerify(source, target);
+            throw new RuntimeException("FileAlreadyExistsException expected");
+        } catch (FileAlreadyExistsException x) {
+        }
+        target.delete();
+        target.createDirectory();
+        try {
+            moveAndVerify(source, target);
+            throw new RuntimeException("FileAlreadyExistsException expected");
+        } catch (FileAlreadyExistsException x) {
+        }
+        source.delete();
+        target.delete();
+
+        /**
+         * Test: move empty directory, target does not exist
+         */
+        source = createSourceDirectory(dir1);
+        target = getTargetFile(dir1);
+        moveAndVerify(source, target, REPLACE_EXISTING);
+        target.delete();
+
+        /**
+         * Test: move empty directory, target exists
+         */
+        source = createSourceDirectory(dir1);
+        target = getTargetFile(dir1).createFile();
+        moveAndVerify(source, target, REPLACE_EXISTING);
+        target.delete();
+
+        /**
+         * Test: move empty, target exists and is empty directory
+         */
+        source = createSourceDirectory(dir1);
+        target = getTargetFile(dir1).createDirectory();
+        moveAndVerify(source, target, REPLACE_EXISTING);
+        target.delete();
+
+        /**
+         * Test: move empty directory, target exists and is non-empty directory
+         */
+        source = createSourceDirectory(dir1);
+        target = getTargetFile(dir1).createDirectory();
+        entry = target.resolve("foo").createFile();
+        try {
+            moveAndVerify(source, target, REPLACE_EXISTING);
+            throw new RuntimeException("FileAlreadyExistsException expected");
+        } catch (FileAlreadyExistsException x) {
+        }
+        entry.delete();
+        source.delete();
+        target.delete();
+
+        /**
+         * Test: move non-empty directory (same file system)
+         */
+        source = createSourceDirectory(dir1);
+        source.resolve("foo").createFile();
+        target = getTargetFile(dir1);
+        moveAndVerify(source, target);
+        target.resolve("foo").delete();
+        target.delete();
+
+        /**
+         * Test: move non-empty directory (different file store)
+         */
+        if (!sameDevice) {
+            source = createSourceDirectory(dir1);
+            source.resolve("foo").createFile();
+            target = getTargetFile(dir2);
+            try {
+                moveAndVerify(source, target);
+                throw new RuntimeException("IOException expected");
+            } catch (IOException x) {
+            }
+            source.resolve("foo").delete();
+            source.delete();
+        }
+
+        /**
+         * Test atomic move of directory (same file store)
+         */
+        source = createSourceDirectory(dir1);
+        source.resolve("foo").createFile();
+        target = getTargetFile(dir1);
+        moveAndVerify(source, target, ATOMIC_MOVE);
+        target.resolve("foo").delete();
+        target.delete();
+
+        // -- symbolic links --
+
+        /**
+         * Test: Move symbolic link to file, target does not exist
+         */
+        if (supportsLinks) {
+            Path tmp = createSourceFile(dir1);
+            source = dir1.resolve("link").createSymbolicLink(tmp);
+            target = getTargetFile(dir1);
+            moveAndVerify(source, target);
+            target.delete();
+            tmp.delete();
+        }
+
+        /**
+         * Test: Move symbolic link to directory, target does not exist
+         */
+        if (supportsLinks) {
+            source = dir1.resolve("link").createSymbolicLink(dir2);
+            target = getTargetFile(dir1);
+            moveAndVerify(source, target);
+            target.delete();
+        }
+
+        /**
+         * Test: Move broken symbolic link, target does not exists
+         */
+        if (supportsLinks) {
+            Path tmp = Paths.get("doesnotexist");
+            source = dir1.resolve("link").createSymbolicLink(tmp);
+            target = getTargetFile(dir1);
+            moveAndVerify(source, target);
+            target.delete();
+        }
+
+        /**
+         * Test: Move symbolic link, target exists
+         */
+        if (supportsLinks) {
+            source = dir1.resolve("link").createSymbolicLink(dir2);
+            target = getTargetFile(dir1).createFile();
+            try {
+                moveAndVerify(source, target);
+                throw new RuntimeException("FileAlreadyExistsException expected");
+            } catch (FileAlreadyExistsException x) {
+            }
+            source.delete();
+            target.delete();
+        }
+
+        /**
+         * Test: Move regular file, target exists
+         */
+        if (supportsLinks) {
+            source = dir1.resolve("link").createSymbolicLink(dir2);
+            target = getTargetFile(dir1).createFile();
+            moveAndVerify(source, target, REPLACE_EXISTING);
+            target.delete();
+        }
+
+        /**
+         * Test: move symbolic link, target exists and is empty directory
+         */
+        if (supportsLinks) {
+            source = dir1.resolve("link").createSymbolicLink(dir2);
+            target = getTargetFile(dir1).createDirectory();
+            moveAndVerify(source, target, REPLACE_EXISTING);
+            target.delete();
+        }
+
+        /**
+         * Test: symbolic link, target exists and is non-empty directory
+         */
+        if (supportsLinks) {
+            source = dir1.resolve("link").createSymbolicLink(dir2);
+            target = getTargetFile(dir1).createDirectory();
+            entry = target.resolve("foo").createFile();
+            try {
+                moveAndVerify(source, target);
+                throw new RuntimeException("FileAlreadyExistsException expected");
+            } catch (FileAlreadyExistsException x) {
+            }
+            entry.delete();
+            source.delete();
+            target.delete();
+        }
+
+        /**
+         * Test atomic move of symbolic link (same file store)
+         */
+        if (supportsLinks) {
+            source = dir1.resolve("link").createSymbolicLink(dir1);
+            target = getTargetFile(dir1).createFile();
+            moveAndVerify(source, target, REPLACE_EXISTING);
+            target.delete();
+        }
+
+        // -- misc. tests --
+
+        /**
+         * Test nulls
+         */
+        source = createSourceFile(dir1);
+        target = getTargetFile(dir1);
+        try {
+            source.moveTo(null);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException x) { }
+        try {
+            source.moveTo(target, (CopyOption[])null);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException x) { }
+        try {
+            CopyOption[] opts = { REPLACE_EXISTING, null };
+            source.moveTo(target, opts);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException x) { }
+        source.delete();
+
+        /**
+         * Test UOE
+         */
+        source = createSourceFile(dir1);
+        target = getTargetFile(dir1);
+        try {
+            source.moveTo(target, new CopyOption() { });
+        } catch (UnsupportedOperationException x) { }
+        try {
+            source.moveTo(target, REPLACE_EXISTING,  new CopyOption() { });
+        } catch (UnsupportedOperationException x) { }
+        source.delete();
+    }
+
+    // copy source to target with verification
+    static void copyAndVerify(Path source, Path target, CopyOption... options)
+        throws IOException
+    {
+        source.copyTo(target, options);
+
+        // get attributes of source and target file to verify copy
+        boolean followLinks = true;
+        LinkOption[] linkOptions = new LinkOption[0];
+        boolean copyAttributes = false;
+        for (CopyOption opt : options) {
+            if (opt == NOFOLLOW_LINKS) {
+                followLinks = false;
+                linkOptions = new LinkOption[] { NOFOLLOW_LINKS };
+            }
+            if (opt == COPY_ATTRIBUTES)
+                copyAttributes = true;
+        }
+        BasicFileAttributes basicAttributes = Attributes
+            .readBasicFileAttributes(source, linkOptions);
+
+        // check hash if regular file
+        if (basicAttributes.isRegularFile())
+            assertTrue(computeHash(source) == computeHash(target));
+
+        // check link target if symbolic link
+        if (basicAttributes.isSymbolicLink())
+            assert( source.readSymbolicLink().equals(target.readSymbolicLink()));
+
+        // check that attributes are copied
+        if (copyAttributes && followLinks) {
+            checkBasicAttributes(basicAttributes,
+                Attributes.readBasicFileAttributes(source, linkOptions));
+
+            // check POSIX attributes are copied
+            String os = System.getProperty("os.name");
+            if (os.equals("SunOS") || os.equals("Linux")) {
+                checkPosixAttributes(
+                    Attributes.readPosixFileAttributes(source, linkOptions),
+                    Attributes.readPosixFileAttributes(target, linkOptions));
+            }
+
+            // check DOS attributes are copied
+            if (os.startsWith("Windows")) {
+                checkDosAttributes(
+                    Attributes.readDosFileAttributes(source, linkOptions),
+                    Attributes.readDosFileAttributes(target, linkOptions));
+            }
+
+            // check named attributes are copied
+            if (followLinks &&
+                source.getFileStore().supportsFileAttributeView("xattr") &&
+                target.getFileStore().supportsFileAttributeView("xattr"))
+            {
+                checkUserDefinedFileAttributes(readUserDefinedFileAttributes(source),
+                                     readUserDefinedFileAttributes(target));
+            }
+        }
+    }
+
+    /**
+     * Tests all possible ways to invoke copyTo
+     */
+    static void doCopyTests(Path dir) throws IOException {
+        Path source, target, link, entry;
+
+        // -- regular file --
+
+        /**
+         * Test: move regular file, target does not exist
+         */
+        source = createSourceFile(dir);
+        target = getTargetFile(dir);
+        copyAndVerify(source, target);
+        source.delete();
+        target.delete();
+
+        /**
+         * Test: copy regular file, target exists
+         */
+        source = createSourceFile(dir);
+        target = getTargetFile(dir).createFile();
+        try {
+            copyAndVerify(source, target);
+            throw new RuntimeException("FileAlreadyExistsException expected");
+        } catch (FileAlreadyExistsException x) {
+        }
+        target.delete();
+        target.createDirectory();
+        try {
+            copyAndVerify(source, target);
+            throw new RuntimeException("FileAlreadyExistsException expected");
+        } catch (FileAlreadyExistsException x) {
+        }
+        source.delete();
+        target.delete();
+
+        /**
+         * Test: copy regular file, target does not exist
+         */
+        source = createSourceFile(dir);
+        target = getTargetFile(dir);
+        copyAndVerify(source, target, REPLACE_EXISTING);
+        source.delete();
+        target.delete();
+
+        /**
+         * Test: copy regular file, target exists
+         */
+        source = createSourceFile(dir);
+        target = getTargetFile(dir).createFile();
+        copyAndVerify(source, target, REPLACE_EXISTING);
+        source.delete();
+        target.delete();
+
+        /**
+         * Test: copy regular file, target exists and is empty directory
+         */
+        source = createSourceFile(dir);
+        target = getTargetFile(dir).createDirectory();
+        copyAndVerify(source, target, REPLACE_EXISTING);
+        source.delete();
+        target.delete();
+
+        /**
+         * Test: copy regular file, target exists and is non-empty directory
+         */
+        source = createSourceFile(dir);
+        target = getTargetFile(dir).createDirectory();
+        entry = target.resolve("foo").createFile();
+        try {
+            copyAndVerify(source, target);
+            throw new RuntimeException("FileAlreadyExistsException expected");
+        } catch (FileAlreadyExistsException x) {
+        }
+        entry.delete();
+        source.delete();
+        target.delete();
+
+        /**
+         * Test: copy regular file + attributes
+         */
+        source = createSourceFile(dir);
+        target = getTargetFile(dir);
+        copyAndVerify(source, target, COPY_ATTRIBUTES);
+        source.delete();
+        target.delete();
+
+
+        // -- directory --
+
+        /*
+         * Test: copy directory, target does not exist
+         */
+        source = createSourceDirectory(dir);
+        target = getTargetFile(dir);
+        copyAndVerify(source, target);
+        source.delete();
+        target.delete();
+
+        /**
+         * Test: copy directory, target exists
+         */
+        source = createSourceDirectory(dir);
+        target = getTargetFile(dir).createFile();
+        try {
+            copyAndVerify(source, target);
+            throw new RuntimeException("FileAlreadyExistsException expected");
+        } catch (FileAlreadyExistsException x) {
+        }
+        target.delete();
+        target.createDirectory();
+        try {
+            copyAndVerify(source, target);
+            throw new RuntimeException("FileAlreadyExistsException expected");
+        } catch (FileAlreadyExistsException x) {
+        }
+        source.delete();
+        target.delete();
+
+        /**
+         * Test: copy directory, target does not exist
+         */
+        source = createSourceDirectory(dir);
+        target = getTargetFile(dir);
+        copyAndVerify(source, target, REPLACE_EXISTING);
+        source.delete();
+        target.delete();
+
+        /**
+         * Test: copy directory, target exists
+         */
+        source = createSourceDirectory(dir);
+        target = getTargetFile(dir).createFile();
+        copyAndVerify(source, target, REPLACE_EXISTING);
+        source.delete();
+        target.delete();
+
+        /**
+         * Test: copy directory, target exists and is empty directory
+         */
+        source = createSourceDirectory(dir);
+        target = getTargetFile(dir).createDirectory();
+        copyAndVerify(source, target, REPLACE_EXISTING);
+        source.delete();
+        target.delete();
+
+        /**
+         * Test: copy directory, target exists and is non-empty directory
+         */
+        source = createSourceDirectory(dir);
+        target = getTargetFile(dir).createDirectory();
+        entry = target.resolve("foo").createFile();
+        try {
+            copyAndVerify(source, target, REPLACE_EXISTING);
+            throw new RuntimeException("FileAlreadyExistsException expected");
+        } catch (FileAlreadyExistsException x) {
+        }
+        entry.delete();
+        source.delete();
+        target.delete();
+
+        /*
+         * Test: copy directory + attributes
+         */
+        source = createSourceDirectory(dir);
+        target = getTargetFile(dir);
+        copyAndVerify(source, target, COPY_ATTRIBUTES);
+        source.delete();
+        target.delete();
+
+        // -- symbolic links --
+
+        /**
+         * Test: Follow link
+         */
+        if (supportsLinks) {
+            source = createSourceFile(dir);
+            link = dir.resolve("link").createSymbolicLink(source);
+            target = getTargetFile(dir);
+            copyAndVerify(link, target);
+            link.delete();
+            source.delete();
+        }
+
+        /**
+         * Test: Copy link (to file)
+         */
+        if (supportsLinks) {
+            source = createSourceFile(dir);
+            link = dir.resolve("link").createSymbolicLink(source);
+            target = getTargetFile(dir);
+            copyAndVerify(link, target, NOFOLLOW_LINKS);
+            link.delete();
+            source.delete();
+        }
+
+        /**
+         * Test: Copy link (to directory)
+         */
+        if (supportsLinks) {
+            source = dir.resolve("mydir").createDirectory();
+            link = dir.resolve("link").createSymbolicLink(source);
+            target = getTargetFile(dir);
+            copyAndVerify(link, target, NOFOLLOW_LINKS);
+            link.delete();
+            source.delete();
+        }
+
+        /**
+         * Test: Copy broken link
+         */
+        if (supportsLinks) {
+            assertTrue(source.notExists());
+            link = dir.resolve("link").createSymbolicLink(source);
+            target = getTargetFile(dir);
+            copyAndVerify(link, target, NOFOLLOW_LINKS);
+            link.delete();
+        }
+
+        /**
+         * Test: Copy link to UNC (Windows only)
+         */
+        if (supportsLinks &&
+            System.getProperty("os.name").startsWith("Windows"))
+        {
+            Path unc = Paths.get("\\\\rialto\\share\\file");
+            link = dir.resolve("link").createSymbolicLink(unc);
+            target = getTargetFile(dir);
+            copyAndVerify(link, target, NOFOLLOW_LINKS);
+            link.delete();
+        }
+
+        // -- misc. tests --
+
+        /**
+         * Test nulls
+         */
+        source = createSourceFile(dir);
+        target = getTargetFile(dir);
+        try {
+            source.copyTo(null);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException x) { }
+        try {
+            source.copyTo(target, (CopyOption[])null);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException x) { }
+        try {
+            CopyOption[] opts = { REPLACE_EXISTING, null };
+            source.copyTo(target, opts);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException x) { }
+        source.delete();
+
+        /**
+         * Test UOE
+         */
+        source = createSourceFile(dir);
+        target = getTargetFile(dir);
+        try {
+            source.copyTo(target, new CopyOption() { });
+        } catch (UnsupportedOperationException x) { }
+        try {
+            source.copyTo(target, REPLACE_EXISTING,  new CopyOption() { });
+        } catch (UnsupportedOperationException x) { }
+        source.delete();
+    }
+
+
+    static void assertTrue(boolean value) {
+        if (!value)
+            throw new RuntimeException("Assertion failed");
+    }
+
+    // computes simple hash of the given file
+    static int computeHash(Path file) throws IOException {
+        int h = 0;
+
+        InputStream in = file.newInputStream();
+        try {
+            byte[] buf = new byte[1024];
+            int n;
+            do {
+                n = in.read(buf);
+                for (int i=0; i<n; i++) {
+                    h = 31*h + (buf[i] & 0xff);
+                }
+            } while (n > 0);
+        } finally {
+            in.close();
+        }
+        return h;
+    }
+
+    // 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();
+        byte[] bytes = new byte[rand.nextInt(128*1024)];
+        rand.nextBytes(bytes);
+        OutputStream out = file.newOutputStream();
+        try {
+            out.write(bytes);
+        } finally {
+            out.close();
+        }
+        randomizeAttributes(file);
+        return file;
+    }
+
+    // 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();
+        randomizeAttributes(subdir);
+        return subdir;
+    }
+
+    // "randomize" the file attributes of the given file.
+    static void randomizeAttributes(Path file) throws IOException {
+        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();
+
+        if (isUnix) {
+            Set<PosixFilePermission> perms = Attributes
+                .readPosixFileAttributes(file, NOFOLLOW_LINKS).permissions();
+            PosixFilePermission[] toChange = {
+                PosixFilePermission.GROUP_READ,
+                PosixFilePermission.GROUP_WRITE,
+                PosixFilePermission.GROUP_EXECUTE,
+                PosixFilePermission.OTHERS_READ,
+                PosixFilePermission.OTHERS_WRITE,
+                PosixFilePermission.OTHERS_EXECUTE
+            };
+            for (PosixFilePermission perm: toChange) {
+                if (heads()) {
+                    perms.add(perm);
+                } else {
+                    perms.remove(perm);
+                }
+            }
+            Attributes.setPosixFilePermissions(file, perms);
+        }
+
+        if (isWindows) {
+            DosFileAttributeView view = file
+                .getFileAttributeView(DosFileAttributeView.class, NOFOLLOW_LINKS);
+            // only set or unset the hidden attribute
+            view.setHidden(heads());
+        }
+
+        boolean addUserDefinedFileAttributes = heads() &&
+            file.getFileStore().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);
+            int n = rand.nextInt(16);
+            while (n > 0) {
+                byte[] value = new byte[1 + rand.nextInt(100)];
+                view.write("user." + Integer.toString(n), ByteBuffer.wrap(value));
+                n--;
+            }
+        }
+    }
+
+    // create name for file in given directory
+    static Path getTargetFile(Path dir) throws IOException {
+        String name = "target" + Integer.toString(rand.nextInt());
+        return dir.resolve(name);
+    }
+ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Path/DeleteOnClose.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.nio.file.*;
+import static java.nio.file.StandardOpenOption.*;
+import java.io.*;
+import java.util.*;
+
+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);
+
+        // 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())
+            throw new RuntimeException("Temporary file was not deleted");
+
+        Path dir = TestUtil.createTemporaryDirectory();
+        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);
+                try {
+                    link.newByteChannel(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 {
+                if (stream instanceof SecureDirectoryStream) {
+                    SecureDirectoryStream secure = (SecureDirectoryStream)stream;
+                    file = Paths.get("foo");
+
+                    Set<OpenOption> opts = new HashSet<OpenOption>();
+                    opts.add(WRITE);
+                    opts.add(DELETE_ON_CLOSE);
+                    secure.newByteChannel(file, opts).close();
+
+                    if (dir.resolve(file).exists())
+                        throw new RuntimeException("File not deleted");
+                }
+            } finally {
+                stream.close();
+            }
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Path/InterruptCopy.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for Sun-specific ExtendedCopyOption.INTERRUPTIBLE option
+ * @library ..
+ * @run main/othervm -XX:-UseVMInterruptibleIO InterruptCopy
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.Attributes;
+import java.io.*;
+import java.util.concurrent.*;
+import com.sun.nio.file.ExtendedCopyOption;
+
+public class InterruptCopy {
+
+    private static final long FILE_SIZE_TO_COPY = 512 * 1024 * 1024;
+    private static final int DELAY_IN_MS = 500;
+
+    public static void main(String[] args) throws Exception {
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            FileStore store = dir.getFileStore();
+            System.out.format("Checking space (%s)\n", store);
+            long usableSpace = Attributes
+                .readFileStoreSpaceAttributes(store).usableSpace();
+            if (usableSpace < 2*FILE_SIZE_TO_COPY) {
+                System.out.println("Insufficient disk space to run test.");
+                return;
+            }
+            doTest(dir);
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+
+    static void doTest(Path dir) throws Exception {
+        final Path source = dir.resolve("foo");
+        final Path target = dir.resolve("bar");
+
+        // create source file (don't create it as sparse file because we
+        // require the copy to take a long time)
+        System.out.println("Creating source file...");
+        byte[] buf = new byte[32*1024];
+        long total = 0;
+        OutputStream out = source.newOutputStream();
+        try {
+            do {
+                out.write(buf);
+                total += buf.length;
+            } while (total < FILE_SIZE_TO_COPY);
+        } finally {
+            out.close();
+        }
+        System.out.println("Source file created.");
+
+        ScheduledExecutorService pool =
+            Executors.newSingleThreadScheduledExecutor();
+        try {
+            // copy source to target in main thread, interrupting it after a delay
+            final Thread me = Thread.currentThread();
+            pool.schedule(new Runnable() {
+                public void run() {
+                    me.interrupt();
+                }}, DELAY_IN_MS, TimeUnit.MILLISECONDS);
+            System.out.println("Copying file...");
+            try {
+                source.copyTo(target, ExtendedCopyOption.INTERRUPTIBLE);
+                throw new RuntimeException("Copy completed (this is not expected)");
+            } catch (IOException e) {
+                boolean interrupted = Thread.interrupted();
+                if (!interrupted)
+                    throw new RuntimeException("Interrupt status was not set");
+                System.out.println("Copy failed (this is expected)");
+            }
+
+            // copy source to target via task in thread pool, interrupting it after
+            // a delay using cancel(true)
+            Future<Void> result = pool.submit(new Callable<Void>() {
+                public Void call() throws IOException {
+                    System.out.println("Copying file...");
+                    source.copyTo(target, ExtendedCopyOption.INTERRUPTIBLE,
+                        StandardCopyOption.REPLACE_EXISTING);
+                    return null;
+                }
+            });
+            Thread.sleep(DELAY_IN_MS);
+            boolean cancelled = result.cancel(true);
+            if (!cancelled)
+                result.get();
+            System.out.println("Copy cancelled.");
+        } finally {
+            pool.shutdown();
+            pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Path/Links.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.Path createSymbolicLink,
+ *     readSymbolicLink, and createLink methods
+ * @library ..
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.*;
+import java.util.*;
+
+public class Links {
+
+    static final boolean isWindows =
+        System.getProperty("os.name").startsWith("Windows");
+
+    static void assertTrue(boolean okay) {
+        if (!okay)
+            throw new RuntimeException("Assertion failed");
+    }
+
+    /**
+     * Exercise createSymbolicLink and readLink methods
+     */
+    static void testSymLinks(Path dir) throws IOException {
+        Path link = dir.resolve("link");
+
+        // Check if sym links are supported
+        try {
+            link.createSymbolicLink(Paths.get("foo"));
+            link.delete();
+        } catch (UnsupportedOperationException x) {
+            // sym links not supported
+            return;
+        } catch (IOException x) {
+            // probably insufficient privileges to create sym links (Windows)
+            return;
+        }
+
+        // Test links to various targets
+        String[] windowsTargets =
+            { "foo", "C:\\foo", "\\foo", "\\\\server\\share\\foo" };
+        String[] otherTargets = { "relative", "/absolute" };
+
+        String[] targets = (isWindows) ? windowsTargets : otherTargets;
+        for (String s: targets) {
+            Path target = Paths.get(s);
+            link.createSymbolicLink(target);
+            try {
+                assertTrue(link.readSymbolicLink().equals(target));
+            } finally {
+                link.delete();
+            }
+        }
+    }
+
+    /**
+     * Exercise createLink method
+     */
+    static void testHardLinks(Path dir) throws IOException {
+        Path foo = dir.resolve("foo").createFile();
+        try {
+            Path bar;
+            try {
+                bar = dir.resolve("bar").createLink(foo);
+            } catch (UnsupportedOperationException x) {
+                return;
+            } catch (IOException x) {
+                // probably insufficient privileges (Windows)
+                return;
+            }
+            try {
+                Object key1 = Attributes
+                    .readBasicFileAttributes(foo).fileKey();
+                Object key2 = Attributes
+                    .readBasicFileAttributes(bar).fileKey();
+                assertTrue((key1 == null) || (key1.equals(key2)));
+
+// Testing of linkCount disabled until linkCount method removed frmo
+// BasicFileAttributes
+/*
+                assertTrue(Attributes
+                    .readBasicFileAttributes(foo).linkCount() >= 2);
+                assertTrue(Attributes
+                    .readBasicFileAttributes(bar).linkCount() >= 2);
+*/
+
+            } finally {
+                bar.delete();
+            }
+
+
+        } finally {
+            foo.delete();
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            testSymLinks(dir);
+            testHardLinks(dir);
+
+            // repeat tests on Windows with long path
+            if (isWindows) {
+                Path dirWithLongPath = null;
+                try {
+                    dirWithLongPath = TestUtil.createDirectoryWithLongPath(dir);
+                } catch (IOException x) {
+                    System.out.println("Unable to create long path: " + x);
+                }
+                if (dirWithLongPath != null) {
+                    System.out.println("");
+                    System.out.println("** REPEAT TESTS WITH LONG PATH **");
+                    testSymLinks(dirWithLongPath);
+                    testHardLinks(dirWithLongPath);
+                }
+            }
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Path/Misc.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,389 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.Path for miscellenous methods not
+ *   covered by other tests
+ * @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 =
+        System.getProperty("os.name").startsWith("Windows");
+    static boolean supportsLinks;
+
+    public static void main(String[] args) throws IOException {
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            supportsLinks = TestUtil.supportsLinks(dir);
+
+            // equals and hashCode methods
+            equalsAndHashCode();
+
+            // checkAccess method
+            checkAccessTests(dir);
+
+            // getFileAttributeView methods
+            getFileAttributeViewTests(dir);
+
+            // toRealPath method
+            toRealPathTests(dir);
+
+            // isSameFile method
+            isSameFileTests(dir);
+
+            // isHidden method
+            isHiddenTests(dir);
+
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+
+    /**
+     * Exercise equals and hashCode methods
+     */
+    static void equalsAndHashCode() {
+
+        Path thisFile = Paths.get("this");
+        Path thatFile = Paths.get("that");
+
+        assertTrue(thisFile.equals(thisFile));
+        assertTrue(!thisFile.equals(thatFile));
+
+        assertTrue(!thisFile.equals(null));
+        assertTrue(!thisFile.equals(new Object()));
+
+        Path likeThis = Paths.get("This");
+        if (isWindows) {
+            // case insensitive
+            assertTrue(thisFile.equals(likeThis));
+            assertTrue(thisFile.hashCode() == likeThis.hashCode());
+        } else {
+            // case senstive
+            assertTrue(!thisFile.equals(likeThis));
+        }
+    }
+
+    /**
+     * 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: 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<AclEntry> 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
+     */
+    static void getFileAttributeViewTests(Path dir) {
+        assertTrue(dir.getFileAttributeView(BasicFileAttributeView.class)
+            instanceof BasicFileAttributeView);
+        assertTrue(dir.getFileAttributeView(BasicFileAttributeView.class, NOFOLLOW_LINKS)
+            instanceof BasicFileAttributeView);
+        assertTrue(dir.getFileAttributeView("basic")
+            instanceof BasicFileAttributeView);
+        assertTrue(dir.getFileAttributeView("basic", NOFOLLOW_LINKS)
+            instanceof BasicFileAttributeView);
+        assertTrue(dir.getFileAttributeView(BogusFileAttributeView.class) == null);
+        assertTrue(dir.getFileAttributeView("bogus") == null);
+        try {
+            dir.getFileAttributeView((Class<FileAttributeView>)null);
+        } catch (NullPointerException ignore) { }
+        try {
+            dir.getFileAttributeView(BasicFileAttributeView.class, (LinkOption[])null);
+        } catch (NullPointerException ignore) { }
+        try {
+            dir.getFileAttributeView(BasicFileAttributeView.class, (LinkOption)null);
+        } catch (NullPointerException ignore) { }
+        try {
+            dir.getFileAttributeView((String)null);
+        } catch (NullPointerException ignore) { }
+        try {
+            dir.getFileAttributeView("basic", (LinkOption[])null);
+        } catch (NullPointerException ignore) { }
+        try {
+            dir.getFileAttributeView("basic", (LinkOption)null);
+        } catch (NullPointerException ignore) { }
+
+    }
+    interface BogusFileAttributeView extends FileAttributeView { }
+
+    /**
+     * Exercise toRealPath method
+     */
+    static void toRealPathTests(Path dir) throws IOException {
+        final Path file = dir.resolve("foo").createFile();
+        final Path link = dir.resolve("link");
+
+        /**
+         * Test: toRealPath(true) will access same file as toRealPath(false)
+         */
+        assertTrue(file.toRealPath(true).isSameFile(file.toRealPath(false)));
+
+        /**
+         * Test: toRealPath(true) should resolve links
+         */
+        if (supportsLinks) {
+            link.createSymbolicLink(file.toAbsolutePath());
+            assertTrue(link.toRealPath(true).equals(file.toRealPath(true)));
+            link.delete();
+        }
+
+
+        /**
+         * Test: toRealPath(false) should not resolve links
+         */
+        if (supportsLinks) {
+            link.createSymbolicLink(file.toAbsolutePath());
+            assertTrue(link.toRealPath(false).getName().equals(link.getName()));
+            link.delete();
+        }
+
+        /**
+         * Test: toRealPath should eliminate "."
+         */
+        assertTrue(dir.resolve(".").toRealPath(true).equals(dir.toRealPath(true)));
+        assertTrue(dir.resolve(".").toRealPath(false).equals(dir.toRealPath(false)));
+
+        /**
+         * Test: toRealPath should eliminate ".." when it doesn't follow a
+         *       symbolic link
+         */
+        Path subdir = dir.resolve("subdir").createDirectory();
+        assertTrue(subdir.resolve("..").toRealPath(true).equals(dir.toRealPath(true)));
+        assertTrue(subdir.resolve("..").toRealPath(false).equals(dir.toRealPath(false)));
+        subdir.delete();
+
+        // 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(false);
+        }
+    }
+
+    /**
+     * Exercise isHidden method
+     */
+    static void isHiddenTests(Path dir) throws IOException {
+        assertTrue(!dir.isHidden());
+
+        Path file = dir.resolve(".foo");
+        if (isWindows) {
+            file.createFile();
+            try {
+                Attributes.setAttribute(file, "dos:hidden", true);
+                assertTrue(file.isHidden());
+            } finally {
+                file.delete();
+            }
+        } else {
+            assertTrue(file.isHidden());
+        }
+    }
+
+    static void assertTrue(boolean okay) {
+        if (!okay)
+            throw new RuntimeException("Assertion Failed");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Path/PathOps.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,752 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.Path path operations
+ */
+
+import java.nio.file.*;
+
+public class PathOps {
+
+    static final java.io.PrintStream out = System.out;
+
+    private String input;
+    private Path path;
+    private Exception exc;
+
+    private PathOps(String s) {
+        out.println();
+        input = s;
+        try {
+            path = FileSystems.getDefault().getPath(s);
+            out.format("%s -> %s", s, path);
+        } catch (Exception x) {
+            exc = x;
+            out.format("%s -> %s", s, x);
+        }
+        out.println();
+    }
+
+    Path path() {
+        return path;
+    }
+
+    void fail() {
+        throw new RuntimeException("PathOps failed");
+    }
+
+    void checkPath() {
+        if (path == null) {
+            throw new InternalError("path is null");
+        }
+    }
+
+    void check(Object result, String expected) {
+        out.format("\tExpected: %s\n", expected);
+        out.format("\tActual: %s\n",  result);
+        if (result == null) {
+            if (expected == null) return;
+        } else {
+            // compare string representations
+            if (expected != null && result.toString().equals(expected.toString()))
+                return;
+        }
+        fail();
+    }
+
+    void check(Object result, boolean expected) {
+        check(result, Boolean.toString(expected));
+    }
+
+    PathOps root(String expected) {
+        out.println("check root");
+        checkPath();
+        check(path.getRoot(), expected);
+        return this;
+    }
+
+    PathOps parent(String expected) {
+        out.println("check parent");
+        checkPath();
+        check(path.getParent(), expected);
+        return this;
+    }
+
+    PathOps name(String expected) {
+        out.println("check name");
+        checkPath();
+        check(path.getName(), expected);
+        return this;
+    }
+
+    PathOps element(int index, String expected) {
+        out.format("check element %d\n", index);
+        checkPath();
+        check(path.getName(index), expected);
+        return this;
+    }
+
+    PathOps subpath(int startIndex, int endIndex, String expected) {
+        out.format("test subpath(%d,%d)\n", startIndex, endIndex);
+        checkPath();
+        check(path.subpath(startIndex, endIndex), expected);
+        return this;
+    }
+
+    PathOps starts(String prefix) {
+        out.format("test startsWith with %s\n", prefix);
+        checkPath();
+        Path s = FileSystems.getDefault().getPath(prefix);
+        check(path.startsWith(s), true);
+        return this;
+    }
+
+    PathOps notStarts(String prefix) {
+        out.format("test not startsWith with %s\n", prefix);
+        checkPath();
+        Path s = FileSystems.getDefault().getPath(prefix);
+        check(path.startsWith(s), false);
+        return this;
+    }
+
+    PathOps ends(String suffix) {
+        out.format("test endsWith %s\n", suffix);
+        checkPath();
+        Path s = FileSystems.getDefault().getPath(suffix);
+        check(path.endsWith(s), true);
+        return this;
+    }
+
+    PathOps notEnds(String suffix) {
+        out.format("test not endsWith %s\n", suffix);
+        checkPath();
+        Path s = FileSystems.getDefault().getPath(suffix);
+        check(path.endsWith(s), false);
+        return this;
+    }
+
+    PathOps absolute() {
+        out.println("check path is absolute");
+        checkPath();
+        check(path.isAbsolute(), true);
+        return this;
+    }
+
+    PathOps notAbsolute() {
+        out.println("check path is not absolute");
+        checkPath();
+        check(path.isAbsolute(), false);
+        return this;
+    }
+
+    PathOps resolve(String other, String expected) {
+        out.format("test resolve %s\n", other);
+        checkPath();
+        check(path.resolve(other), expected);
+        return this;
+    }
+
+    PathOps relativize(String other, String expected) {
+        out.format("test relativize %s\n", other);
+        checkPath();
+        Path that = FileSystems.getDefault().getPath(other);
+        check(path.relativize(that), expected);
+        return this;
+    }
+
+    PathOps normalize(String expected) {
+        out.println("check normalized path");
+        checkPath();
+        check(path.normalize(), expected);
+        return this;
+    }
+
+    PathOps string(String expected) {
+        out.println("check string representation");
+        checkPath();
+        check(path, expected);
+        return this;
+    }
+
+    PathOps invalid() {
+        if (!(exc instanceof InvalidPathException)) {
+            out.println("InvalidPathException not thrown as expected");
+            fail();
+        }
+        return this;
+    }
+
+    static PathOps test(String s) {
+        return new PathOps(s);
+    }
+
+    // -- PathOpss --
+
+    static void header(String s) {
+        out.println();
+        out.println();
+        out.println("-- " + s + " --");
+    }
+
+    static void doWindowsTests() {
+        header("Windows specific tests");
+
+        // all components present
+        test("C:\\a\\b\\c")
+            .root("C:\\")
+            .parent("C:\\a\\b")
+            .name("c");
+        test("C:a\\b\\c")
+            .root("C:")
+            .parent("C:a\\b")
+            .name("c");
+        test("\\\\server\\share\\a")
+            .root("\\\\server\\share\\")
+            .parent("\\\\server\\share\\")
+            .name("a");
+
+        // root component only
+        test("C:\\")
+            .root("C:\\")
+            .parent(null)
+            .name(null);
+        test("C:")
+            .root("C:")
+            .parent(null)
+            .name(null);
+        test("\\\\server\\share\\")
+            .root("\\\\server\\share\\")
+            .parent(null)
+            .name(null);
+
+        // no root component
+        test("a\\b")
+            .root(null)
+            .parent("a")
+            .name("b");
+
+        // name component only
+        test("foo")
+            .root(null)
+            .parent(null)
+            .name("foo");
+
+        // startsWith
+        test("C:\\")
+            .starts("C:\\")
+            .starts("c:\\")
+            .notStarts("C")
+            .notStarts("C:");
+        test("C:")
+            .starts("C:")
+            .starts("c:")
+            .notStarts("C");
+        test("\\")
+            .starts("\\");
+        test("C:\\foo\\bar")
+            .starts("C:\\")
+            .starts("C:\\foo")
+            .starts("C:\\FOO")
+            .starts("C:\\foo\\bar")
+            .starts("C:\\Foo\\Bar")
+            .notStarts("C:")
+            .notStarts("C")
+            .notStarts("C:foo");
+        test("\\foo\\bar")
+            .starts("\\")
+            .starts("\\foo")
+            .starts("\\foO")
+            .starts("\\foo\\bar")
+            .starts("\\fOo\\BaR")
+            .notStarts("foo")
+            .notStarts("foo\\bar");
+        test("foo\\bar")
+            .starts("foo")
+            .starts("foo\\bar")
+            .notStarts("\\");
+        test("\\\\server\\share")
+            .starts("\\\\server\\share")
+            .starts("\\\\server\\share\\")
+            .notStarts("\\");
+
+        // endsWith
+        test("C:\\")
+            .ends("C:\\")
+            .ends("c:\\")
+            .notEnds("\\");
+        test("C:")
+            .ends("C:")
+            .ends("c:");
+        test("\\")
+            .ends("\\");
+        test("C:\\foo\\bar")
+            .ends("bar")
+            .ends("BAR")
+            .ends("foo\\bar")
+            .ends("Foo\\Bar")
+            .ends("C:\\foo\\bar")
+            .ends("c:\\foO\\baR")
+            .notEnds("r")
+            .notEnds("\\foo\\bar");
+        test("\\foo\\bar")
+            .ends("bar")
+            .ends("BaR")
+            .ends("foo\\bar")
+            .ends("foO\\baR")
+            .ends("\\foo\\bar")
+            .ends("\\Foo\\Bar")
+            .notEnds("oo\\bar");
+        test("foo\\bar")
+            .ends("bar")
+            .ends("BAR")
+            .ends("foo\\bar")
+            .ends("Foo\\Bar")
+            .notEnds("ar");
+        test("\\\\server\\share")
+            .ends("\\\\server\\share")
+            .ends("\\\\server\\share\\")
+            .notEnds("shared")
+            .notEnds("\\");
+
+        // elements
+        test("C:\\a\\b\\c")
+            .element(0, "a")
+            .element(1, "b")
+            .element(2, "c");
+        test("foo.bar\\gus.alice")
+            .element(0, "foo.bar")
+            .element(1, "gus.alice");
+
+        // subpath
+        test("C:\\foo")
+            .subpath(0, 1, "foo");
+        test("C:foo")
+            .subpath(0, 1, "foo");
+        test("foo")
+            .subpath(0, 1, "foo");
+        test("C:\\foo\\bar\\gus")
+            .subpath(0, 1, "foo")
+            .subpath(0, 2, "foo\\bar")
+            .subpath(0, 3, "foo\\bar\\gus")
+            .subpath(1, 2, "bar")
+            .subpath(1, 3, "bar\\gus")
+            .subpath(2, 3, "gus");
+        test("\\\\server\\share\\foo")
+            .subpath(0, 1, "foo");
+
+        // isAbsolute
+        test("foo").notAbsolute();
+        test("C:").notAbsolute();
+        test("C:\\").absolute();
+        test("C:\\abc").absolute();
+        test("\\\\server\\share\\").absolute();
+
+        // resolve
+        test("C:\\")
+            .resolve("foo", "C:\\foo")
+            .resolve("D:\\bar", "D:\\bar")
+            .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar")
+            .resolve("C:foo", "C:\\foo")
+            .resolve("D:foo", "D:foo");
+        test("\\")
+            .resolve("foo", "\\foo")
+            .resolve("D:bar", "D:bar")
+            .resolve("C:\\bar", "C:\\bar")
+            .resolve("\\\\server\\share\\bar", "\\\\server\\share\\bar")
+            .resolve("\\foo", "\\foo");
+        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");
+        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");
+        test("C:")
+            .resolve("foo", "C:foo");
+        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");
+
+        // relativize
+        test("foo\\bar")
+            .relativize("foo\\bar", null)
+            .relativize("foo", "..");
+        test("C:\\a\\b\\c")
+            .relativize("C:\\a", "..\\..");
+        test("\\\\server\\share\\foo")
+            .relativize("\\\\server\\share\\bar", "..\\bar");
+
+        // normalize
+        test("C:\\")
+            .normalize("C:\\");
+        test("C:\\.")
+            .normalize("C:\\");
+        test("C:\\..")
+            .normalize("C:\\");
+        test("\\\\server\\share")
+            .normalize("\\\\server\\share\\");
+        test("\\\\server\\share\\.")
+            .normalize("\\\\server\\share\\");
+        test("\\\\server\\share\\..")
+            .normalize("\\\\server\\share\\");
+        test("C:")
+            .normalize("C:");
+        test("C:.")
+            .normalize("C:");
+        test("C:..")
+            .normalize("C:..");
+        test("\\")
+            .normalize("\\");
+        test("\\.")
+            .normalize("\\");
+        test("\\..")
+            .normalize("\\");
+        test("foo")
+            .normalize("foo");
+        test("foo\\.")
+            .normalize("foo");
+        test("foo\\..")
+            .normalize(null);
+        test("C:\\foo")
+            .normalize("C:\\foo");
+        test("C:\\foo\\.")
+            .normalize("C:\\foo");
+        test("C:\\.\\foo")
+            .normalize("C:\\foo");
+        test("C:\\foo\\..")
+            .normalize("C:\\");
+        test("C:\\..\\foo")
+            .normalize("C:\\foo");
+        test("\\\\server\\share\\foo")
+            .normalize("\\\\server\\share\\foo");
+        test("\\\\server\\share\\foo\\.")
+            .normalize("\\\\server\\share\\foo");
+        test("\\\\server\\share\\.\\foo")
+            .normalize("\\\\server\\share\\foo");
+        test("\\\\server\\share\\foo\\..")
+            .normalize("\\\\server\\share\\");
+        test("\\\\server\\share\\..\\foo")
+            .normalize("\\\\server\\share\\foo");
+        test("C:foo")
+            .normalize("C:foo");
+        test("C:foo\\.")
+            .normalize("C:foo");
+        test("C:.\\foo")
+            .normalize("C:foo");
+        test("C:foo\\..")
+            .normalize("C:");
+        test("C:..\\foo")
+            .normalize("C:..\\foo");
+        test("\\foo")
+            .normalize("\\foo");
+        test("\\foo\\.")
+            .normalize("\\foo");
+        test("\\.\\foo")
+            .normalize("\\foo");
+        test("\\foo\\..")
+            .normalize("\\");
+        test("\\..\\foo")
+            .normalize("\\foo");
+        test(".")
+            .normalize(null);
+        test("..")
+            .normalize("..");
+        test("\\..\\..")
+            .normalize("\\");
+        test("..\\..\\foo")
+            .normalize("..\\..\\foo");
+        test("foo\\bar\\..")
+            .normalize("foo");
+        test("foo\\bar\\.\\..")
+            .normalize("foo");
+        test("foo\\bar\\gus\\..\\..")
+            .normalize("foo");
+        test(".\\foo\\.\\bar\\.\\gus\\..\\.\\..")
+            .normalize("foo");
+
+        // UNC corner cases
+        test("\\\\server\\share\\")
+            .root("\\\\server\\share\\")
+            .parent(null)
+            .name(null);
+        test("\\\\server")
+            .invalid();
+        test("\\\\server\\")
+            .invalid();
+        test("\\\\server\\share")
+            .root("\\\\server\\share\\")
+            .parent(null)
+            .name(null);
+
+        // invalid
+        test(":\\foo")
+            .invalid();
+        test("C::")
+            .invalid();
+        test("C:\\?")           // invalid character
+            .invalid();
+        test("C:\\*")           // invalid character
+            .invalid();
+        test("C:\\abc\u0001\\foo")
+            .invalid();
+        test("C:\\\u0019\\foo")
+            .invalid();
+        test("\\\\server\u0019\\share")
+            .invalid();
+        test("\\\\server\\share\u0019")
+            .invalid();
+        test("foo\u0000\bar")
+            .invalid();
+        test("C:\\foo ")                // trailing space
+             .invalid();
+        test("C:\\foo \\bar")
+            .invalid();
+        //test("C:\\foo.")              // trailing dot
+            //.invalid();
+        //test("C:\\foo...\\bar")
+            //.invalid();
+
+        // normalization at construction time (remove redundant and replace slashes)
+        test("C:/a/b/c")
+            .string("C:\\a\\b\\c")
+            .root("C:\\")
+            .parent("C:\\a\\b");
+        test("C://a//b//c")
+            .string("C:\\a\\b\\c")
+            .root("C:\\")
+            .parent("C:\\a\\b");
+
+        // hashCode
+        header("hashCode");
+        int h1 = test("C:\\foo").path().hashCode();
+        int h2 = test("c:\\FOO").path().hashCode();
+        if (h1 != h2)
+            throw new RuntimeException("PathOps failed");
+    }
+
+    static void doUnixTests() {
+        header("Unix specific tests");
+
+        // all components
+        test("/a/b/c")
+            .root("/")
+            .parent("/a/b")
+            .name("c");
+
+        // root component only
+        test("/")
+            .root("/")
+            .parent(null)
+            .name(null);
+
+        // no root component
+        test("a/b")
+            .root(null)
+            .parent("a")
+            .name("b");
+
+        // name component only
+        test("foo")
+            .root(null)
+            .parent(null)
+            .name("foo");
+
+        // startsWith
+        test("/")
+            .starts("/")
+            .notStarts("/foo");
+        test("/foo")
+            .starts("/")
+            .starts("/foo")
+            .notStarts("/f");
+        test("/foo/bar")
+            .starts("/")
+            .starts("/foo")
+            .starts("/foo/bar")
+            .notStarts("/f")
+            .notStarts("foo")
+            .notStarts("foo/bar");
+        test("foo")
+            .starts("foo")
+            .notStarts("f");
+        test("foo/bar")
+            .starts("foo")
+            .starts("foo/bar")
+            .notStarts("f")
+            .notStarts("/foo")
+            .notStarts("/foo/bar");
+
+        // endsWith
+        test("/")
+            .ends("/")
+            .notEnds("foo")
+            .notEnds("/foo");
+        test("/foo")
+            .ends("foo")
+            .ends("/foo")
+            .notEnds("/");
+        test("/foo/bar")
+            .ends("bar")
+            .ends("foo/bar")
+            .ends("/foo/bar")
+            .notEnds("/bar");
+        test("foo")
+            .ends("foo");
+        test("foo/bar")
+            .ends("bar")
+            .ends("foo/bar");
+
+        // elements
+        test("a/b/c")
+            .element(0,"a")
+            .element(1,"b")
+            .element(2,"c");
+
+        // isAbsolute
+        test("/")
+            .absolute();
+        test("/tmp")
+            .absolute();
+        test("tmp")
+            .notAbsolute();
+
+        // resolve
+        test("/tmp")
+            .resolve("foo", "/tmp/foo")
+            .resolve("/foo", "/foo");
+        test("tmp")
+            .resolve("foo", "tmp/foo")
+            .resolve("/foo", "/foo");
+
+        // relativize
+        test("/a/b/c")
+            .relativize("/a/b/c", null)
+            .relativize("/a/b/c/d/e", "d/e")
+            .relativize("/a/x", "../../x");
+
+        // normalize
+        test("/")
+            .normalize("/");
+        test("foo")
+            .normalize("foo");
+        test("/foo")
+            .normalize("/foo");
+        test(".")
+            .normalize(null);
+        test("..")
+            .normalize("..");
+        test("/..")
+            .normalize("/");
+        test("/../..")
+            .normalize("/");
+        test("foo/.")
+            .normalize("foo");
+        test("./foo")
+            .normalize("foo");
+        test("foo/..")
+            .normalize(null);
+        test("../foo")
+            .normalize("../foo");
+        test("../../foo")
+            .normalize("../../foo");
+        test("foo/bar/..")
+            .normalize("foo");
+        test("foo/bar/gus/../..")
+            .normalize("foo");
+        test("/foo/bar/gus/../..")
+            .normalize("/foo");
+
+        // invalid
+        test("foo\u0000\bar")
+            .invalid();
+
+        // normalization
+        test("//foo//bar")
+            .string("/foo/bar")
+            .root("/")
+            .parent("/foo")
+            .name("bar");
+    }
+
+    static void npes() {
+        header("NullPointerException");
+
+        Path path = FileSystems.getDefault().getPath("foo");
+
+        try {
+            path.resolve((String)null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException npe) {
+        }
+
+        try {
+            path.relativize(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException npe) {
+        }
+
+        try {
+            path.compareTo(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException npe) {
+        }
+
+        try {
+            path.startsWith(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException npe) {
+        }
+
+        try {
+            path.endsWith(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException npe) {
+        }
+
+    }
+
+    public static void main(String[] args) {
+        // all platforms
+        npes();
+
+        // operating system specific
+        String osname = System.getProperty("os.name");
+        if (osname.startsWith("Windows")) {
+            doWindowsTests();
+        }
+        if (osname.equals("SunOS") || osname.equals("Linux")) {
+            doUnixTests();
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Path/SBC.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,468 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.Path.newByteChannel
+ * @library ..
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.file.*;
+import static java.nio.file.StandardOpenOption.*;
+import static com.sun.nio.file.ExtendedOpenOption.*;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.channels.*;
+import java.io.IOException;
+import java.util.*;
+
+public class SBC {
+
+    static boolean supportsLinks;
+
+    public static void main(String[] args) throws Exception {
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            supportsLinks = TestUtil.supportsLinks(dir);
+
+            // open options
+            createTests(dir);
+            appendTests(dir);
+            truncateExistingTests(dir);
+            noFollowLinksTests(dir);
+
+            // SeekableByteChannel methods
+            sizeTruncatePositionTests(dir);
+
+            // platform specific
+            if (System.getProperty("os.name").startsWith("Windows"))
+                dosSharingOptionTests(dir);
+
+            // misc. tests
+            badCombinations(dir);
+            unsupportedOptions(dir);
+            nullTests(dir);
+
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+
+    // test CREATE and CREATE_NEW options
+    static void createTests(Path dir) throws Exception {
+        Path file = dir.resolve("foo");
+
+        // CREATE
+        try {
+            // create file (no existing file)
+            file.newByteChannel(CREATE, WRITE).close();
+            if (file.notExists())
+                throw new RuntimeException("File not created");
+
+            // create file (existing file)
+            file.newByteChannel(CREATE, WRITE).close();
+
+            // create file where existing file is a sym link
+            if (supportsLinks) {
+                Path link = dir.resolve("link").createSymbolicLink(file);
+                try {
+                    // file already exists
+                    link.newByteChannel(CREATE, WRITE).close();
+
+                    // file does not exist
+                    file.delete();
+                    link.newByteChannel(CREATE, WRITE).close();
+                    if (file.notExists())
+                        throw new RuntimeException("File not created");
+
+                } finally {
+                    TestUtil.deleteUnchecked(link);
+                }
+            }
+
+        } finally {
+            TestUtil.deleteUnchecked(file);
+        }
+
+        // CREATE_NEW
+        try {
+            // create file
+            file.newByteChannel(CREATE_NEW, WRITE).close();
+            if (file.notExists())
+                throw new RuntimeException("File not created");
+
+            // create should fail
+            try {
+                SeekableByteChannel sbc =
+                    file.newByteChannel(CREATE_NEW, WRITE);
+                sbc.close();
+                throw new RuntimeException("FileAlreadyExistsException not thrown");
+            } catch (FileAlreadyExistsException x) { }
+
+            // create should fail
+            if (supportsLinks) {
+                Path link = dir.resolve("link");
+                Path target = dir.resolve("thisDoesNotExist");
+                link.createSymbolicLink(target);
+                try {
+
+                    try {
+                        SeekableByteChannel sbc =
+                            file.newByteChannel(CREATE_NEW, WRITE);
+                        sbc.close();
+                        throw new RuntimeException("FileAlreadyExistsException not thrown");
+                    } catch (FileAlreadyExistsException x) { }
+
+                } finally {
+                    TestUtil.deleteUnchecked(link);
+                }
+            }
+
+
+        } finally {
+            TestUtil.deleteUnchecked(file);
+        }
+
+        // CREATE_NEW + SPARSE
+        try {
+            SeekableByteChannel sbc = file
+                .newByteChannel(CREATE_NEW, WRITE, SPARSE);
+            try {
+                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);
+        }
+    }
+
+    // test APPEND option
+    static void appendTests(Path dir) throws Exception {
+        Path file = dir.resolve("foo");
+        try {
+            // "hello there" should be written to file
+            SeekableByteChannel sbc = file
+                .newByteChannel(CREATE_NEW, WRITE, APPEND);
+            try {
+                write(sbc, "hello ");
+                sbc.position(0L);
+                write(sbc, "there");
+            } finally {
+                sbc.close();
+            }
+
+            // check file
+            Scanner s = new Scanner(file);
+            try {
+                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 {
+                sbc.read(ByteBuffer.allocate(100));
+            } catch (NonReadableChannelException x) {
+            } finally {
+                sbc.close();
+            }
+        } finally {
+            // clean-up
+            TestUtil.deleteUnchecked(file);
+        }
+    }
+
+    // test TRUNCATE_EXISTING option
+    static void truncateExistingTests(Path dir) throws Exception {
+        Path file = dir.resolve("foo");
+        try {
+            SeekableByteChannel sbc =
+                file.newByteChannel(CREATE_NEW, WRITE);
+            try {
+                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 {
+                write(sbc, "Hello there!");
+            } finally {
+                sbc.close();
+            }
+            Scanner s = new Scanner(file);
+            try {
+                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 {
+                long size = ((FileChannel)sbc).size();
+                if (size != 0L)
+                    throw new RuntimeException("File not truncated");
+            } finally {
+                sbc.close();
+            }
+
+        } finally {
+            // clean-up
+            TestUtil.deleteUnchecked(file);
+        }
+
+    }
+
+    // test NOFOLLOW_LINKS option
+    static void noFollowLinksTests(Path dir) throws Exception {
+        if (!supportsLinks)
+            return;
+        Path file = dir.resolve("foo").createFile();
+        try {
+            // ln -s foo link
+            Path link = dir.resolve("link").createSymbolicLink(file);
+
+            // open with NOFOLLOW_LINKS option
+            try {
+                link.newByteChannel(READ, LinkOption.NOFOLLOW_LINKS);
+                throw new RuntimeException();
+            } catch (IOException x) {
+            } finally {
+                TestUtil.deleteUnchecked(link);
+            }
+
+        } finally {
+            // clean-up
+            TestUtil.deleteUnchecked(file);
+        }
+    }
+
+    // test size/truncate/position methods
+    static void sizeTruncatePositionTests(Path dir) throws Exception {
+        Path file = dir.resolve("foo");
+        try {
+            SeekableByteChannel sbc = file
+                .newByteChannel(CREATE_NEW, READ, WRITE);
+            try {
+                if (sbc.size() != 0L)
+                    throw new RuntimeException("Unexpected size");
+
+                // check size
+                write(sbc, "hello");
+                if (sbc.size() != 5L)
+                    throw new RuntimeException("Unexpected size");
+
+                // truncate (size and position should change)
+                sbc.truncate(4L);
+                if (sbc.size() != 4L)
+                    throw new RuntimeException("Unexpected size");
+                if (sbc.position() != 4L)
+                    throw new RuntimeException("Unexpected position");
+
+                // truncate (position should not change)
+                sbc.position(2L).truncate(3L);
+                if (sbc.size() != 3L)
+                    throw new RuntimeException("Unexpected size");
+                if (sbc.position() != 2L)
+                    throw new RuntimeException("Unexpected position");
+            } finally {
+                sbc.close();
+            }
+        } finally {
+            TestUtil.deleteUnchecked(file);
+        }
+    }
+
+    // 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();
+        try {
+            SeekableByteChannel ch;
+
+            // no sharing
+            ch = file.newByteChannel(READ,
+                NOSHARE_READ, NOSHARE_WRITE, NOSHARE_DELETE);
+            try {
+                try {
+                    file.newByteChannel(READ);
+                    throw new RuntimeException("Sharing violation expected");
+                } catch (IOException ignore) { }
+                try {
+                    file.newByteChannel(WRITE);
+                    throw new RuntimeException("Sharing violation expected");
+                } catch (IOException ignore) { }
+                try {
+                    file.delete();
+                    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 {
+                    file.newByteChannel(WRITE);
+                    throw new RuntimeException("Sharing violation expected");
+                } catch (IOException ignore) { }
+                try {
+                    file.delete();
+                    throw new RuntimeException("Sharing violation expected");
+                } catch (IOException ignore) { }
+            } finally {
+                ch.close();
+            }
+
+            // write allowed
+            ch = file.newByteChannel(READ, NOSHARE_READ, NOSHARE_DELETE);
+            try {
+                try {
+                    file.newByteChannel(READ);
+                    throw new RuntimeException("Sharing violation expected");
+                } catch (IOException ignore) { }
+                file.newByteChannel(WRITE).close();
+                try {
+                    file.delete();
+                    throw new RuntimeException("Sharing violation expected");
+                } catch (IOException ignore) { }
+            } finally {
+                ch.close();
+            }
+
+            // delete allowed
+            ch = file.newByteChannel(READ, NOSHARE_READ, NOSHARE_WRITE);
+            try {
+                try {
+                    file.newByteChannel(READ);
+                    throw new RuntimeException("Sharing violation expected");
+                } catch (IOException ignore) { }
+                try {
+                    file.newByteChannel(WRITE);
+                    throw new RuntimeException("Sharing violation expected");
+                } catch (IOException ignore) { }
+                file.delete();
+            } finally {
+                ch.close();
+            }
+
+        } finally {
+            TestUtil.deleteUnchecked(file);
+        }
+    }
+
+    // invalid combinations of options
+    static void badCombinations(Path dir) throws Exception {
+        Path file = dir.resolve("bad");
+
+        try {
+            file.newByteChannel(READ, APPEND);
+            throw new RuntimeException("IllegalArgumentException expected");
+        } catch (IllegalArgumentException x) { }
+
+        try {
+            file.newByteChannel(WRITE, APPEND, TRUNCATE_EXISTING);
+            throw new RuntimeException("IllegalArgumentException expected");
+        } catch (IllegalArgumentException x) { }
+    }
+
+    // unsupported operations
+    static void unsupportedOptions(Path dir) throws Exception {
+        Path file = dir.resolve("bad");
+
+        OpenOption badOption = new OpenOption() { };
+        try {
+            file.newByteChannel(badOption);
+            throw new RuntimeException("UnsupportedOperationException expected");
+        } catch (UnsupportedOperationException e) { }
+        try {
+            file.newByteChannel(READ, WRITE, badOption);
+            throw new RuntimeException("UnsupportedOperationException expected");
+        } catch (UnsupportedOperationException e) { }
+    }
+
+    // null handling
+    static void nullTests(Path dir) throws Exception {
+        Path file = dir.resolve("foo");
+
+        try {
+            file.newByteChannel((OpenOption[])null);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException x) { }
+
+        try {
+            OpenOption[] opts = { READ, null };
+            file.newByteChannel(opts);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException x) { }
+
+        try {
+            file.newByteChannel((Set<OpenOption>)null);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException x) { }
+
+        try {
+            Set<OpenOption> opts = new HashSet<OpenOption>();
+            opts.add(READ);
+            opts.add(null);
+            file.newByteChannel(opts);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException x) { }
+
+        try {
+            EnumSet<StandardOpenOption> opts = EnumSet.of(READ);
+            file.newByteChannel(opts, (FileAttribute[])null);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException x) { }
+
+        try {
+            EnumSet<StandardOpenOption> opts = EnumSet.of(READ);
+            FileAttribute[] attrs = { null };
+            file.newByteChannel(opts, attrs);
+            throw new RuntimeException("NullPointerException expected");
+        } catch (NullPointerException x) { }
+    }
+
+    static void write(WritableByteChannel wbc, String msg) throws IOException {
+        ByteBuffer buf = ByteBuffer.wrap(msg.getBytes());
+        while (buf.hasRemaining())
+            wbc.write(buf);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Path/TemporaryFiles.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+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.io.OutputStream;
+import java.util.Set;
+
+public class TemporaryFiles {
+
+    static void checkFile(Path file) throws IOException {
+        // check file is in temporary directory
+        Path tmpdir = Paths.get(System.getProperty("java.io.tmpdir"));
+        if (!file.getParent().equals(tmpdir))
+            throw new RuntimeException("Not in temporary directory");
+
+        // 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<PosixFilePermission> 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");
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        Path file = File.createTempFile("blah", null, false).toPath();
+        try {
+            checkFile(file);
+        } finally {
+            TestUtil.deleteUnchecked(file);
+        }
+
+        // temporary file with deleteOnExit
+        file = File.createTempFile("blah", "tmp", true).toPath();
+        checkFile(file);
+        // write path to temporary file to file so that calling script can
+        // check that it is deleted
+        OutputStream out = Paths.get(args[0]).newOutputStream();
+        try {
+            out.write(file.toString().getBytes());
+        } finally {
+            out.close();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Path/UriImportExport.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.Path
+ */
+
+import java.nio.file.*;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.io.PrintStream;
+
+public class UriImportExport {
+
+    static final PrintStream log = System.out;
+    static int failures = 0;
+
+    static void test(String fn, String expected) {
+        log.println();
+        Path p = Paths.get(fn);
+        log.println(p);
+        URI u = p.toUri();
+        log.println("  --> " + u);
+        if (expected != null && !(u.toString().equals(expected))) {
+            log.println("FAIL: Expected " + expected);
+            failures++;
+            return;
+        }
+        Path q = Paths.get(u);
+        log.println("  --> " + q);
+        if (!p.toAbsolutePath().equals(q)) {
+            log.println("FAIL: Expected " + p + ", got " + q);
+            failures++;
+            return;
+        }
+    }
+
+    static void test(String fn) {
+        test(fn, null);
+    }
+
+    public static void main(String[] args) throws Exception {
+        test("foo");
+        test("/foo");
+        test("/foo bar");
+
+        String osname = System.getProperty("os.name");
+        if (osname.startsWith("Windows")) {
+            test("C:\\foo");
+            test("C:foo");
+            test("\\\\rialto.dublin.com\\share\\");
+            test("\\\\fe80--203-baff-fe5a-749ds1.ipv6-literal.net\\share\\missing",
+                "file://[fe80::203:baff:fe5a:749d%1]/share/missing");
+        }
+
+        if (failures > 0)
+            throw new RuntimeException(failures + " test(s) failed");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Path/delete_on_close.sh	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,61 @@
+#
+# Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+# @test
+# @bug 4313887
+# @summary Unit test for DELETE_ON_CLOSE open option
+# @library ..
+# @build DeleteOnClose
+# @run shell delete_on_close.sh
+
+# if TESTJAVA isn't set then we assume an interactive run.
+
+if [ -z "$TESTJAVA" ]; then
+    TESTSRC=.
+    TESTCLASSES=.
+    JAVA=java
+else
+    JAVA="${TESTJAVA}/bin/java"
+fi
+
+OS=`uname -s`
+case "$OS" in
+    Windows_* )
+        CLASSPATH="${TESTCLASSES};${TESTSRC}"
+        ;;
+    * )
+        CLASSPATH=${TESTCLASSES}:${TESTSRC}
+        ;;
+esac
+export CLASSPATH
+
+TMPFILE="$$.tmp"
+touch $TMPFILE
+$JAVA DeleteOnClose $TMPFILE 2>&1
+if [ $? != 0 ]; then exit 1; fi
+if [ -f $TMPFILE ]; then
+    echo "$TMPFILE was not deleted"
+    exit 1
+fi
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Path/temporary_files.sh	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,65 @@
+#
+# Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+# @test
+# @bug 4313887
+# @summary Unit test for File.createTempFile (to be be moved to test/java/io/File)
+# @library ..
+# @build TemporaryFiles
+# @run shell temporary_files.sh
+
+# if TESTJAVA isn't set then we assume an interactive run.
+
+if [ -z "$TESTJAVA" ]; then
+    TESTSRC=.
+    TESTCLASSES=.
+    JAVA=java
+else
+    JAVA="${TESTJAVA}/bin/java"
+fi
+
+OS=`uname -s`
+case "$OS" in
+    Windows_* )
+        CLASSPATH="${TESTCLASSES};${TESTSRC}"
+        ;;
+    * )
+        CLASSPATH=${TESTCLASSES}:${TESTSRC}
+        ;;
+esac
+export CLASSPATH
+
+TMPFILENAME="$$.tmp"
+$JAVA TemporaryFiles $TMPFILENAME 2>&1
+if [ $? != 0 ]; then exit 1; fi
+if [ ! -f $TMPFILENAME ]; then
+    echo "$TMPFILENAME not found"
+    exit 1
+fi
+TMPFILE=`cat $TMPFILENAME`
+if [ -f $TMPFILE ]; then
+    echo "$TMPFILE not deleted"
+    exit 1
+fi
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/PathMatcher/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.PathMatcher
+ */
+
+import java.nio.file.*;
+import java.util.regex.PatternSyntaxException;
+
+public class Basic {
+    static int failures;
+
+    static void match(String name, String pattern, boolean expectedToMatch) {
+        System.out.format("%s -> %s", name, pattern);
+        Path file = Paths.get(name);
+        boolean matched =  file.getFileSystem()
+            .getPathMatcher("glob:" + pattern).matches(file);
+        if (matched)
+            System.out.print(" (matched)");
+        else
+            System.out.print(" (no match)");
+        if (matched != expectedToMatch) {
+            System.out.println(" ==> UNEXPECTED RESULT!");
+            failures++;
+        } else {
+            System.out.println(" OKAY");
+        }
+    }
+
+    static void assertMatch(String path, String pattern) {
+        match(path, pattern, true);
+    }
+
+    static void assertNotMatch(String path, String pattern) {
+        match(path, pattern, false);
+    }
+
+    static void assertBadPattern(String path, String pattern) {
+        System.out.format("Compile bad pattern %s\t", pattern);
+        try {
+            FileSystems.getDefault().getPathMatcher("glob:" + pattern);
+            System.out.println("Compiled ==> UNEXPECTED RESULT!");
+            failures++;
+        } catch (PatternSyntaxException e) {
+            System.out.println("Failed to compile ==> OKAY");
+        }
+    }
+
+    public static void main(String[] args) {
+        // basic
+        assertMatch("foo.html", "foo.html");
+        assertNotMatch("foo.html", "foo.htm");
+        assertNotMatch("foo.html", "bar.html");
+
+        // match zero or more characters
+        assertMatch("foo.html", "f*");
+        assertMatch("foo.html", "*.html");
+        assertMatch("foo.html", "foo.html*");
+        assertMatch("foo.html", "*foo.html");
+        assertMatch("foo.html", "*foo.html*");
+        assertNotMatch("foo.html", "*.htm");
+        assertNotMatch("foo.html", "f.*");
+
+        // match one character
+        assertMatch("foo.html", "?oo.html");
+        assertMatch("foo.html", "??o.html");
+        assertMatch("foo.html", "???.html");
+        assertMatch("foo.html", "???.htm?");
+        assertNotMatch("foo.html", "foo.???");
+
+        // group of subpatterns
+        assertMatch("foo.html", "foo{.html,.class}");
+        assertMatch("foo.html", "foo.{class,html}");
+        assertNotMatch("foo.html", "foo{.htm,.class}");
+
+        // bracket expressions
+        assertMatch("foo.html", "[f]oo.html");
+        assertMatch("foo.html", "[e-g]oo.html");
+        assertMatch("foo.html", "[abcde-g]oo.html");
+        assertMatch("foo.html", "[abcdefx-z]oo.html");
+        assertMatch("foo.html", "[!a]oo.html");
+        assertMatch("foo.html", "[!a-e]oo.html");
+        assertMatch("foo-bar", "foo[-a-z]bar");     // match dash
+        assertMatch("foo.html", "foo[!-]html");     // match !dash
+
+        // groups of subpattern with bracket expressions
+        assertMatch("foo.html", "[f]oo.{[h]tml,class}");
+        assertMatch("foo.html", "foo.{[a-z]tml,class}");
+        assertMatch("foo.html", "foo.{[!a-e]tml,.class}");
+
+        // assume special characters are allowed in file names
+        assertMatch("{foo}.html", "\\{foo*");
+        assertMatch("{foo}.html", "*\\}.html");
+        assertMatch("[foo].html", "\\[foo*");
+        assertMatch("[foo].html", "*\\].html");
+
+        // errors
+        assertBadPattern("foo.html", "*[a--z]");            // bad range
+        assertBadPattern("foo.html", "*[a--]");             // bad range
+        assertBadPattern("foo.html", "*[a-z");              // missing ]
+        assertBadPattern("foo.html", "*{class,java");       // missing }
+        assertBadPattern("foo.html", "*.{class,{.java}}");  // nested group
+        assertBadPattern("foo.html", "*.html\\");           // nothing to escape
+
+        // platform specific
+        if (System.getProperty("os.name").startsWith("Windows")) {
+            assertMatch("C:\\foo", "C:\\\\f*");
+            assertMatch("C:\\FOO", "c:\\\\f*");
+            assertMatch("C:\\foo\\bar\\gus", "C:\\\\**\\\\gus");
+            assertMatch("C:\\foo\\bar\\gus", "C:\\\\**");
+        } else {
+            assertMatch("/tmp/foo", "/tmp/*");
+            assertMatch("/tmp/foo/bar", "/tmp/**");
+
+            // some special characters not allowed on Windows
+            assertMatch("myfile?", "myfile\\?");
+            assertMatch("one\\two", "one\\\\two");
+            assertMatch("one*two", "one\\*two");
+        }
+
+
+
+        // regex syntax
+        {
+            String pattern = ".*\\.html";
+            System.out.format("Test regex pattern: %s", pattern);
+            Path file = Paths.get("foo.html");
+            boolean matched =  file.getFileSystem()
+                .getPathMatcher("regex:" + pattern).matches(file);
+            if (matched) {
+                System.out.println(" OKAY");
+            } else {
+                System.out.println(" ==> UNEXPECTED RESULT!");
+                failures++;
+            }
+        }
+
+        // unknown syntax
+        try {
+            System.out.format("Test unknown syntax");
+            FileSystems.getDefault().getPathMatcher("grep:foo");
+            System.out.println(" ==> NOT EXPECTED TO COMPILE");
+            failures++;
+        } catch (UnsupportedOperationException e) {
+            System.out.println(" OKAY");
+        }
+
+        if (failures > 0)
+            throw new RuntimeException(failures +
+                " sub-test(s) failed - see log for details");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/TestUtil.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Random;
+import java.io.IOException;
+
+public class TestUtil {
+    private TestUtil() {
+    }
+
+    public static Path createTemporaryDirectory() throws IOException {
+        Path tmpdir = Paths.get(System.getProperty("java.io.tmpdir"));
+        Random r = new Random();
+
+        Path dir;
+        do {
+            dir = tmpdir.resolve("name" + r.nextInt());
+        } while (dir.exists());
+        return dir.createDirectory();
+    }
+
+    static void removeAll(Path dir) {
+        Files.walkFileTree(dir, new FileVisitor<Path>() {
+            @Override
+            public FileVisitResult preVisitDirectory(Path dir) {
+                return FileVisitResult.CONTINUE;
+            }
+            @Override
+            public FileVisitResult preVisitDirectoryFailed(Path dir, IOException exc) {
+                System.err.format("Error occured accessing directory %s\n", dir, exc);
+                return FileVisitResult.CONTINUE;
+            }
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+                try {
+                    file.delete(false);
+                } catch (IOException x) {
+                    System.err.format("Unable to delete %s: %s\n", file, x);
+                }
+                return FileVisitResult.CONTINUE;
+            }
+            @Override
+            public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
+                try {
+                    dir.delete(false);
+                } catch (IOException x) {
+                    System.err.format("Unable to delete %s: %s\n", dir, x);
+                }
+                return FileVisitResult.CONTINUE;
+            }
+            @Override
+            public FileVisitResult visitFileFailed(Path file, IOException exc) {
+                System.err.format("Unable to visit %s: %s\n", file, exc);
+                return FileVisitResult.CONTINUE;
+            }
+        });
+    }
+
+    static void deleteUnchecked(FileRef file) {
+        try {
+            file.delete();
+        } catch (IOException exc) {
+            System.err.format("Unable to delete %s: %s\n", file, exc);
+        }
+    }
+
+    /**
+     * Creates a directory tree in the given directory so that the total
+     * size of the path is more than 2k in size. This is used for long
+     * path tests on Windows.
+     */
+    static Path createDirectoryWithLongPath(Path dir)
+        throws IOException
+    {
+        StringBuilder sb = new StringBuilder();
+        for (int i=0; i<240; i++) {
+            sb.append('A');
+        }
+        String name = sb.toString();
+        do {
+            dir = dir.resolve(name).resolve(".");
+            dir.createDirectory();
+        } while (dir.toString().length() < 2048);
+        return dir;
+    }
+
+    /**
+     * Returns true if symbolic links are supported
+     */
+    static boolean supportsLinks(Path dir) {
+        Path link = dir.resolve("testlink");
+        Path target = dir.resolve("testtarget");
+        try {
+            link.createSymbolicLink(target);
+            target.delete(false);
+            return true;
+        } catch (UnsupportedOperationException x) {
+            return false;
+        } catch (IOException x) {
+            return false;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/WatchService/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,493 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.WatchService
+ * @library ..
+ * @run main/timeout=120 Basic
+ */
+
+import java.nio.file.*;
+import static java.nio.file.StandardWatchEventKind.*;
+import java.nio.file.attribute.*;
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Unit test for WatchService that exercises all methods in various scenarios.
+ */
+
+public class Basic {
+
+    static void createFile(Path file) throws IOException {
+        file.newOutputStream().close();
+    }
+
+    static void takeExpectedKey(WatchService watcher, WatchKey expected) {
+        System.out.println("take events...");
+        WatchKey key;
+        try {
+            key = watcher.take();
+        } catch (InterruptedException x) {
+            // not expected
+            throw new RuntimeException(x);
+        }
+        if (key != expected)
+            throw new RuntimeException("removed unexpected key");
+    }
+
+    static void checkExpectedEvent(Iterable<WatchEvent<?>> events,
+                                   WatchEvent.Kind<?> expectedKind,
+                                   Object expectedContext)
+    {
+        WatchEvent<?> event = events.iterator().next();
+        System.out.format("got event: type=%s, count=%d, context=%s\n",
+            event.kind(), event.count(), event.context());
+        if (event.kind() != expectedKind)
+            throw new RuntimeException("unexpected event");
+        if (!expectedContext.equals(event.context()))
+            throw new RuntimeException("unexpected context");
+    }
+
+    /**
+     * Simple test of each of the standard events
+     */
+    static void testEvents(Path dir) throws IOException {
+        System.out.println("-- Standard Events --");
+
+        FileSystem fs = FileSystems.getDefault();
+        Path name = fs.getPath("foo");
+
+        WatchService watcher = fs.newWatchService();
+        try {
+            // --- 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 });
+
+            // create file
+            Path file = dir.resolve("foo");
+            System.out.format("create %s\n", file);
+            createFile(file);
+
+            // remove key and check that we got the ENTRY_CREATE event
+            takeExpectedKey(watcher, myKey);
+            checkExpectedEvent(myKey.pollEvents(),
+                StandardWatchEventKind.ENTRY_CREATE, name);
+
+            System.out.println("reset key");
+            if (!myKey.reset())
+                throw new RuntimeException("key has been cancalled");
+
+            System.out.println("OKAY");
+
+            // --- ENTRY_DELETE ---
+
+            System.out.format("register %s for ENTRY_DELETE\n", dir);
+            WatchKey deleteKey = dir.register(watcher,
+                new WatchEvent.Kind<?>[]{ ENTRY_DELETE });
+            if (deleteKey != myKey)
+                throw new RuntimeException("register did not return existing key");
+
+            System.out.format("delete %s\n", file);
+            file.delete(false);
+            takeExpectedKey(watcher, myKey);
+            checkExpectedEvent(myKey.pollEvents(),
+                StandardWatchEventKind.ENTRY_DELETE, name);
+
+            System.out.println("reset key");
+            if (!myKey.reset())
+                throw new RuntimeException("key has been cancalled");
+
+            System.out.println("OKAY");
+
+            // create the file for the next test
+            createFile(file);
+
+            // --- ENTRY_MODIFY ---
+
+            System.out.format("register %s for ENTRY_MODIFY\n", dir);
+            WatchKey newKey = dir.register(watcher,
+                new WatchEvent.Kind<?>[]{ ENTRY_MODIFY });
+            if (newKey != myKey)
+                throw new RuntimeException("register did not return existing key");
+
+            System.out.format("update: %s\n", file);
+            OutputStream out = file.newOutputStream(EnumSet.of(StandardOpenOption.APPEND));
+            try {
+                out.write("I am a small file".getBytes("UTF-8"));
+            } finally {
+                out.close();
+            }
+
+            // remove key and check that we got the ENTRY_MODIFY event
+            takeExpectedKey(watcher, myKey);
+            checkExpectedEvent(myKey.pollEvents(),
+                StandardWatchEventKind.ENTRY_MODIFY, name);
+            System.out.println("OKAY");
+
+            // done
+            file.delete(false);
+
+        } finally {
+            watcher.close();
+        }
+    }
+
+    /**
+     * Check that a cancelled key will never be queued
+     */
+    static void testCancel(Path dir) throws IOException {
+        System.out.println("-- Cancel --");
+
+        WatchService watcher = FileSystems.getDefault().newWatchService();
+        try {
+
+            System.out.format("register %s for events\n", dir);
+            WatchKey myKey = dir.register(watcher,
+                new WatchEvent.Kind<?>[]{ ENTRY_CREATE });
+
+            System.out.println("cancel key");
+            myKey.cancel();
+
+            // create a file in the directory
+            Path file = dir.resolve("mars");
+            System.out.format("create: %s\n", file);
+            createFile(file);
+
+            // poll for keys - there will be none
+            System.out.println("poll...");
+            try {
+                WatchKey key = watcher.poll(3000, TimeUnit.MILLISECONDS);
+                if (key != null)
+                    throw new RuntimeException("key should not be queued");
+            } catch (InterruptedException x) {
+                throw new RuntimeException(x);
+            }
+
+            // done
+            file.delete(false);
+
+            System.out.println("OKAY");
+
+        } finally {
+            watcher.close();
+        }
+    }
+
+    /**
+     * Check that deleting a registered directory causes the key to be
+     * cancelled and queued.
+     */
+    static void testAutomaticCancel(Path dir) throws IOException {
+        System.out.println("-- Automatic Cancel --");
+
+        Path subdir = dir.resolve("bar").createDirectory();
+
+        WatchService watcher = FileSystems.getDefault().newWatchService();
+        try {
+
+            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(false);
+            takeExpectedKey(watcher, myKey);
+
+            System.out.println("reset key");
+            if (myKey.reset())
+                throw new RuntimeException("Key was not cancelled");
+            if (myKey.isValid())
+                throw new RuntimeException("Key is still valid");
+
+            System.out.println("OKAY");
+
+        } finally {
+            watcher.close();
+        }
+    }
+
+    /**
+     * Asynchronous close of watcher causes blocked threads to wakeup
+     */
+    static void testWakeup(Path dir) throws IOException {
+        System.out.println("-- Wakeup Tests --");
+        final WatchService watcher = FileSystems.getDefault().newWatchService();
+        Runnable r = new Runnable() {
+            public void run() {
+                try {
+                    Thread.sleep(5000);
+                    System.out.println("close WatchService...");
+                    watcher.close();
+                } catch (InterruptedException x) {
+                    x.printStackTrace();
+                } catch (IOException x) {
+                    x.printStackTrace();
+                }
+            }
+        };
+
+        // start thread to close watch service after delay
+        new Thread(r).start();
+
+        try {
+            System.out.println("take...");
+            watcher.take();
+            throw new RuntimeException("ClosedWatchServiceException not thrown");
+        } catch (InterruptedException x) {
+            throw new RuntimeException(x);
+        } catch (ClosedWatchServiceException  x) {
+            System.out.println("ClosedWatchServiceException thrown");
+        }
+
+        System.out.println("OKAY");
+    }
+
+    /**
+     * Simple test to check exceptions and other cases
+     */
+    @SuppressWarnings("unchecked")
+    static void testExceptions(Path dir) throws IOException {
+        System.out.println("-- Exceptions and other simple tests --");
+
+        WatchService watcher = FileSystems.getDefault().newWatchService();
+        try {
+
+            // Poll tests
+
+            WatchKey key;
+            System.out.println("poll...");
+            key = watcher.poll();
+            if (key != null)
+                throw new RuntimeException("no keys registered");
+
+            System.out.println("poll with timeout...");
+            try {
+                long start = System.currentTimeMillis();
+                key = watcher.poll(3000, TimeUnit.MILLISECONDS);
+                if (key != null)
+                    throw new RuntimeException("no keys registered");
+                long waited = System.currentTimeMillis() - start;
+                if (waited < 2900)
+                    throw new RuntimeException("poll was too short");
+            } catch (InterruptedException x) {
+                throw new RuntimeException(x);
+            }
+
+            // IllegalArgumentException
+            System.out.println("IllegalArgumentException tests...");
+            try {
+                dir.register(watcher, new WatchEvent.Kind<?>[]{ } );
+                throw new RuntimeException("IllegalArgumentException not thrown");
+            } catch (IllegalArgumentException x) {
+            }
+            try {
+                // OVERFLOW is ignored so this is equivalent to the empty set
+                dir.register(watcher, new WatchEvent.Kind<?>[]{ OVERFLOW });
+                throw new RuntimeException("IllegalArgumentException not thrown");
+            } catch (IllegalArgumentException x) {
+            }
+
+            // UnsupportedOperationException
+            try {
+                dir.register(watcher, new WatchEvent.Kind<?>[]{
+                             new WatchEvent.Kind<Object>() {
+                                @Override public String name() { return "custom"; }
+                                @Override public Class<Object> type() { return Object.class; }
+                             }});
+            } catch (UnsupportedOperationException x) {
+            }
+            try {
+                dir.register(watcher,
+                             new WatchEvent.Kind<?>[]{ ENTRY_CREATE },
+                             new WatchEvent.Modifier() {
+                                 @Override public String name() { return "custom"; }
+                             });
+                throw new RuntimeException("UnsupportedOperationException not thrown");
+            } catch (UnsupportedOperationException x) {
+            }
+
+            // NullPointerException
+            System.out.println("NullPointerException tests...");
+            try {
+                dir.register(null, new WatchEvent.Kind<?>[]{ ENTRY_CREATE });
+                throw new RuntimeException("NullPointerException not thrown");
+            } catch (NullPointerException x) {
+            }
+            try {
+                dir.register(watcher, new WatchEvent.Kind<?>[]{ null });
+                throw new RuntimeException("NullPointerException not thrown");
+            } catch (NullPointerException x) {
+            }
+            try {
+                dir.register(watcher, new WatchEvent.Kind<?>[]{ ENTRY_CREATE },
+                    (WatchEvent.Modifier)null);
+                throw new RuntimeException("NullPointerException not thrown");
+            } catch (NullPointerException x) {
+            }
+        } finally {
+            watcher.close();
+        }
+
+        // -- ClosedWatchServiceException --
+
+        System.out.println("ClosedWatchServiceException tests...");
+
+        try {
+            watcher.poll();
+            throw new RuntimeException("ClosedWatchServiceException not thrown");
+        } catch (ClosedWatchServiceException  x) {
+        }
+
+        // assume that poll throws exception immediately
+        long start = System.currentTimeMillis();
+        try {
+            watcher.poll(10000, TimeUnit.MILLISECONDS);
+            throw new RuntimeException("ClosedWatchServiceException not thrown");
+        } catch (InterruptedException x) {
+            throw new RuntimeException(x);
+        } catch (ClosedWatchServiceException  x) {
+            long waited = System.currentTimeMillis() - start;
+            if (waited > 5000)
+                throw new RuntimeException("poll was too long");
+        }
+
+        try {
+            watcher.take();
+            throw new RuntimeException("ClosedWatchServiceException not thrown");
+        } catch (InterruptedException x) {
+            throw new RuntimeException(x);
+        } catch (ClosedWatchServiceException  x) {
+        }
+
+        try {
+            dir.register(watcher, new WatchEvent.Kind<?>[]{ ENTRY_CREATE });
+             throw new RuntimeException("ClosedWatchServiceException not thrown");
+        } catch (ClosedWatchServiceException  x) {
+        }
+
+        System.out.println("OKAY");
+    }
+
+    /**
+     * Test that directory can be registered with more than one watch service
+     * and that events don't interfere with each other
+     */
+    static void testTwoWatchers(Path dir) throws IOException {
+        System.out.println("-- Two watchers test --");
+
+        FileSystem fs = FileSystems.getDefault();
+        WatchService watcher1 = fs.newWatchService();
+        WatchService watcher2 = fs.newWatchService();
+        try {
+            Path name1 = fs.getPath("gus1");
+            Path name2 = fs.getPath("gus2");
+
+            // create gus1
+            Path file1 = dir.resolve(name1);
+            System.out.format("create %s\n", file1);
+            createFile(file1);
+
+            // register with both watch services (different events)
+            System.out.println("register for different events");
+            WatchKey key1 = dir.register(watcher1,
+                new WatchEvent.Kind<?>[]{ ENTRY_CREATE });
+            WatchKey key2 = dir.register(watcher2,
+                new WatchEvent.Kind<?>[]{ ENTRY_DELETE });
+
+            if (key1 == key2)
+                throw new RuntimeException("keys should be different");
+
+            // create gus2
+            Path file2 = dir.resolve(name2);
+            System.out.format("create %s\n", file2);
+            createFile(file2);
+
+            // check that key1 got ENTRY_CREATE
+            takeExpectedKey(watcher1, key1);
+            checkExpectedEvent(key1.pollEvents(),
+                StandardWatchEventKind.ENTRY_CREATE, name2);
+
+            // check that key2 got zero events
+            WatchKey key = watcher2.poll();
+            if (key != null)
+                throw new RuntimeException("key not expected");
+
+            // delete gus1
+            file1.delete(false);
+
+            // check that key2 got ENTRY_DELETE
+            takeExpectedKey(watcher2, key2);
+            checkExpectedEvent(key2.pollEvents(),
+                StandardWatchEventKind.ENTRY_DELETE, name1);
+
+            // check that key1 got zero events
+            key = watcher1.poll();
+            if (key != null)
+                throw new RuntimeException("key not expected");
+
+            // reset for next test
+            key1.reset();
+            key2.reset();
+
+            // change registration with watcher2 so that they are both
+            // registered for the same event
+            System.out.println("register for same event");
+            key2 = dir.register(watcher2, new WatchEvent.Kind<?>[]{ ENTRY_CREATE });
+
+            // create file and key2 should be queued
+            System.out.format("create %s\n", file1);
+            createFile(file1);
+            takeExpectedKey(watcher2, key2);
+            checkExpectedEvent(key2.pollEvents(),
+                StandardWatchEventKind.ENTRY_CREATE, name1);
+
+            System.out.println("OKAY");
+
+        } finally {
+            watcher2.close();
+            watcher1.close();
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+
+            testEvents(dir);
+            testCancel(dir);
+            testAutomaticCancel(dir);
+            testWakeup(dir);
+            testExceptions(dir);
+            testTwoWatchers(dir);
+
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/WatchService/FileTreeModifier.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Sanity test for Sun-specific FILE_TREE watch event modifier
+ * @library ..
+ */
+
+import java.nio.file.*;
+import static java.nio.file.StandardWatchEventKind.*;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.*;
+import java.util.concurrent.*;
+import static com.sun.nio.file.ExtendedWatchEventModifier.*;
+
+public class FileTreeModifier {
+
+    static void checkExpectedEvent(WatchService watcher,
+                                   WatchEvent.Kind<?> expectedType,
+                                   Object expectedContext)
+    {
+        WatchKey key;
+        try {
+            key = watcher.take();
+        } catch (InterruptedException x) {
+            // should not happen
+            throw new RuntimeException(x);
+        }
+        WatchEvent<?> event = key.pollEvents().iterator().next();
+        System.out.format("Event: type=%s, count=%d, context=%s\n",
+            event.kind(), event.count(), event.context());
+        if (event.kind() != expectedType)
+            throw new RuntimeException("unexpected event");
+        if (!expectedContext.equals(event.context()))
+            throw new RuntimeException("unexpected context");
+    }
+
+    static void doTest(Path top) throws IOException {
+        FileSystem fs = top.getFileSystem();
+        WatchService watcher = fs.newWatchService();
+
+        // create directories
+        Path subdir = top
+           .resolve("a").createDirectory()
+           .resolve("b").createDirectory()
+           .resolve("c").createDirectory();
+
+        // Test ENTRY_CREATE with FILE_TREE modifier.
+
+        WatchKey key = top.register(watcher,
+            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();
+        checkExpectedEvent(watcher, ENTRY_CREATE, top.relativize(file));
+        key.reset();
+
+        // Test ENTRY_DELETE with FILE_TREE modifier.
+
+        WatchKey k = top.register(watcher,
+            new WatchEvent.Kind<?>[]{ ENTRY_DELETE }, FILE_TREE);
+        if (k != key)
+            throw new RuntimeException("Existing key not returned");
+
+        // delete a/b/c/foo and check we get delete event
+        file.delete(false);
+        checkExpectedEvent(watcher, ENTRY_DELETE, top.relativize(file));
+        key.reset();
+
+        // Test changing registration to ENTRY_CREATE without modifier
+
+        k = top.register(watcher, new WatchEvent.Kind<?>[]{ ENTRY_CREATE });
+        if (k != key)
+            throw new RuntimeException("Existing key not returned");
+
+        // create a/b/c/foo
+        file.createFile();
+
+        // check that key is not queued
+        try {
+            k = watcher.poll(3, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            throw new RuntimeException();
+        }
+        if (k != null)
+            throw new RuntimeException("WatchKey not expected to be polled");
+
+        // create bar and check we get create event
+        file = top.resolve("bar").createFile();
+        checkExpectedEvent(watcher, ENTRY_CREATE, top.relativize(file));
+        key.reset();
+
+        // Test changing registration to <all> with FILE_TREE modifier
+
+        k = top.register(watcher,
+            new WatchEvent.Kind<?>[]{ ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY },
+            FILE_TREE);
+        if (k != key)
+            throw new RuntimeException("Existing key not returned");
+
+        // modify bar and check we get modify event
+        OutputStream out = file.newOutputStream();
+        try {
+            out.write("Double shot expresso please".getBytes("UTF-8"));
+        } finally {
+            out.close();
+        }
+        checkExpectedEvent(watcher, ENTRY_MODIFY, top.relativize(file));
+        key.reset();
+    }
+
+
+    public static void main(String[] args) throws IOException {
+        if (!System.getProperty("os.name").startsWith("Windows")) {
+            System.out.println("This is Windows-only test at this time!");
+            return;
+        }
+
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            doTest(dir);
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/WatchService/SensitivityModifier.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Sanity test for Sun-specific sensitivyt level watch event modifier
+ * @library ..
+ * @run main/timeout=330 Basic
+ */
+
+import java.nio.file.*;
+import static java.nio.file.StandardWatchEventKind.*;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+import com.sun.nio.file.SensitivityWatchEventModifier;
+
+public class SensitivityModifier {
+
+    static final Random rand = new Random();
+
+    static void register(Path[] dirs, WatchService watcher) throws IOException {
+        SensitivityWatchEventModifier[] sensitivtives =
+            SensitivityWatchEventModifier.values();
+        for (int i=0; i<dirs.length; i++) {
+            SensitivityWatchEventModifier sensivity =
+                sensitivtives[ rand.nextInt(sensitivtives.length) ];
+            Path dir = dirs[i];
+            dir.register(watcher, new WatchEvent.Kind<?>[]{ ENTRY_MODIFY }, sensivity);
+        }
+    }
+
+    static void doTest(Path top) throws Exception {
+        FileSystem fs = top.getFileSystem();
+        WatchService watcher = fs.newWatchService();
+
+        // create directories and files
+        int nDirs = 5 + rand.nextInt(20);
+        int nFiles = 50 + rand.nextInt(50);
+        Path[] dirs = new Path[nDirs];
+        Path[] files = new Path[nFiles];
+        for (int i=0; i<nDirs; i++) {
+            dirs[i] = top.resolve("dir" + i).createDirectory();
+        }
+        for (int i=0; i<nFiles; i++) {
+            Path dir = dirs[rand.nextInt(nDirs)];
+            files[i] = dir.resolve("file" + i).createFile();
+        }
+
+        // register the directories (random sensitivity)
+        register(dirs, watcher);
+
+        // sleep a bit here to ensure that modification to the first file
+        // can be detected by polling implementations (ie: last modified time
+        // may not change otherwise).
+        try { Thread.sleep(1000); } catch (InterruptedException e) { }
+
+        // modify files and check that events are received
+        for (int i=0; i<10; i++) {
+            Path file = files[rand.nextInt(nFiles)];
+            System.out.println("Modify: " + file);
+            OutputStream out = file.newOutputStream();
+            try {
+                out.write(new byte[100]);
+            } finally {
+                out.close();
+            }
+            System.out.println("Waiting for event...");
+            WatchKey key = watcher.take();
+            WatchEvent<?> event = key.pollEvents().iterator().next();
+            if (event.kind() != ENTRY_MODIFY)
+                throw new RuntimeException("Unexpected event: " + event);
+            Path name = ((WatchEvent<Path>)event).context();
+            if (!name.equals(file.getName()))
+                throw new RuntimeException("Unexpected context: " + name);
+            System.out.println("Event OK");
+
+            // drain events (to avoid interference)
+            do {
+                key.reset();
+                key = watcher.poll(1, TimeUnit.SECONDS);
+            } while (key != null);
+
+            // re-register the directories to force changing their sensitivity
+            // level
+            register(dirs, watcher);
+        }
+
+        // done
+        watcher.close();
+    }
+
+    public static void main(String[] args) throws Exception {
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            doTest(dir);
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/WatchService/WithSecurityManager.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for Watchable#register's permission checks
+ * @build WithSecurityManager
+ * @run main/othervm WithSecurityManager denyAll.policy - fail
+ * @run main/othervm WithSecurityManager denyAll.policy tree fail
+ * @run main/othervm WithSecurityManager grantDirOnly.policy - pass
+ * @run main/othervm WithSecurityManager grantDirOnly.policy tree fail
+ * @run main/othervm WithSecurityManager grantDirAndOneLevel.policy - pass
+ * @run main/othervm WithSecurityManager grantDirAndOneLevel.policy tree fail
+ * @run main/othervm WithSecurityManager grantDirAndTree.policy - pass
+ * @run main/othervm WithSecurityManager grantDirAndTree.policy tree pass
+ */
+
+import java.nio.file.*;
+import java.io.IOException;
+import com.sun.nio.file.ExtendedWatchEventModifier;
+
+public class WithSecurityManager {
+
+    public static void main(String[] args) throws IOException {
+        String policyFile = args[0];
+        boolean recursive = args[1].equals("tree");
+        boolean expectedToFail = args[2].equals("fail");
+
+        // install security manager with the given policy file
+        String testSrc = System.getProperty("test.src");
+        if (testSrc == null)
+            throw new RuntimeException("This test must be run by jtreg");
+        Path dir = Paths.get(testSrc);
+        System.setProperty("java.security.policy", dir.resolve(policyFile).toString());
+        System.setSecurityManager(new SecurityManager());
+
+        // initialize optional modifier
+        WatchEvent.Modifier[] modifiers;
+        if (recursive) {
+            modifiers = new WatchEvent.Modifier[1];
+            modifiers[0] = ExtendedWatchEventModifier.FILE_TREE;
+        } else {
+            modifiers = new WatchEvent.Modifier[0];
+        }
+
+        // attempt to register directory
+        try {
+            dir.register(dir.getFileSystem().newWatchService(),
+                         new WatchEvent.Kind<?>[]{ StandardWatchEventKind.ENTRY_CREATE },
+                         modifiers);
+            if (expectedToFail)
+                throw new RuntimeException("SecurityException not thrown");
+        } catch (SecurityException e) {
+            if (!expectedToFail)
+                throw e;
+        } catch (UnsupportedOperationException e) {
+            // FILE_TREE modifier only supported on some platforms
+            if (!recursive)
+                throw new RuntimeException(e);
+            System.out.println("FILE_TREE option not supported");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/WatchService/denyAll.policy	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,3 @@
+// policy file that does not grant any permissions
+grant {
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/WatchService/grantDirAndOneLevel.policy	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,5 @@
+// policy file that grants read access to source directory and its entries
+grant {
+    permission java.io.FilePermission "${test.src}", "read";
+    permission java.io.FilePermission "${test.src}${file.separator}*", "read";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/WatchService/grantDirAndTree.policy	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,5 @@
+// policy file that grants read access to source directory and all descendants
+grant {
+    permission java.io.FilePermission "${test.src}", "read";
+    permission java.io.FilePermission "${test.src}${file.separator}-", "read";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/WatchService/grantDirOnly.policy	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,4 @@
+// policy file that grants read access to source directory
+grant {
+    permission java.io.FilePermission "${test.src}", "read";
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/attribute/AclFileAttributeView/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.attribute.AclFileAttribueView
+ * @library ../..
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+
+import static java.nio.file.attribute.AclEntryType.*;
+import static java.nio.file.attribute.AclEntryPermission.*;
+import static java.nio.file.attribute.AclEntryFlag.*;
+
+public class Basic {
+
+    static void printAcl(List<AclEntry> acl) {
+        for (AclEntry entry: acl) {
+            System.out.format("  %s%n", entry);
+        }
+    }
+
+    // sanity check read and writing ACL
+    static void testReadWrite(Path dir) throws IOException {
+        Path file = dir.resolve("foo");
+        if (file.notExists())
+            file.createFile();
+
+        AclFileAttributeView view = file
+            .getFileAttributeView(AclFileAttributeView.class);
+
+        // print existing ACL
+        List<AclEntry> acl = view.getAcl();
+        System.out.println(" -- current ACL --");
+        printAcl(acl);
+
+        // insert entry to grant owner read access
+        UserPrincipal owner = view.getOwner();
+        AclEntry entry = AclEntry.newBuilder()
+            .setType(ALLOW)
+            .setPrincipal(owner)
+            .setPermissions(READ_DATA, READ_ATTRIBUTES)
+            .build();
+        System.out.println(" -- insert (entry 0) --");
+        System.out.format("  %s%n", entry);
+        acl.add(0, entry);
+        view.setAcl(acl);
+
+        // re-ACL and check entry
+        List<AclEntry> newacl = view.getAcl();
+        System.out.println(" -- current ACL --");
+        printAcl(acl);
+        if (!newacl.get(0).equals(entry)) {
+            throw new RuntimeException("Entry 0 is not expected");
+        }
+
+        // if PosixFileAttributeView then repeat test with OWNER@
+        if (file.getFileStore().supportsFileAttributeView("posix")) {
+            owner = file.getFileSystem().getUserPrincipalLookupService()
+                .lookupPrincipalByName("OWNER@");
+            entry = AclEntry.newBuilder(entry).setPrincipal(owner).build();
+
+            System.out.println(" -- replace (entry 0) --");
+            System.out.format("  %s%n", entry);
+
+            acl.set(0, entry);
+            view.setAcl(acl);
+            newacl = view.getAcl();
+            System.out.println(" -- current ACL --");
+            printAcl(acl);
+            if (!newacl.get(0).equals(entry)) {
+                throw new RuntimeException("Entry 0 is not expected");
+            }
+        }
+    }
+
+    static FileAttribute<List<AclEntry>> asAclAttribute(final List<AclEntry> acl) {
+        return new FileAttribute<List<AclEntry>>() {
+            public String name() { return "acl:acl"; }
+            public List<AclEntry> value() { return acl; }
+        };
+    }
+
+    static void assertEquals(List<AclEntry> actual, List<AclEntry> expected) {
+        if (!actual.equals(expected)) {
+            System.err.format("Actual: %s\n", actual);
+            System.err.format("Expected: %s\n", expected);
+            throw new RuntimeException("ACL not expected");
+        }
+    }
+
+    // sanity check create a file or directory with initial ACL
+    static void testCreateFile(Path dir) throws IOException {
+        UserPrincipal user = Attributes.getOwner(dir);
+
+        // create file with initial ACL
+        System.out.println("-- create file with initial ACL --");
+        Path file = dir.resolve("gus");
+        List<AclEntry> fileAcl = Arrays.asList(
+            AclEntry.newBuilder()
+                .setType(AclEntryType.ALLOW)
+                .setPrincipal(user)
+                .setPermissions(SYNCHRONIZE, READ_DATA, WRITE_DATA,
+                    READ_ATTRIBUTES, READ_ACL, WRITE_ATTRIBUTES, DELETE)
+                .build());
+        file.createFile(asAclAttribute(fileAcl));
+        assertEquals(Attributes.getAcl(file), fileAcl);
+
+        // create directory with initial ACL
+        System.out.println("-- create directory with initial ACL --");
+        Path subdir = dir.resolve("stuff");
+        List<AclEntry> dirAcl = Arrays.asList(
+            AclEntry.newBuilder()
+                .setType(AclEntryType.ALLOW)
+                .setPrincipal(user)
+                .setPermissions(SYNCHRONIZE, ADD_FILE, DELETE)
+                .build(),
+            AclEntry.newBuilder(fileAcl.get(0))
+                .setFlags(FILE_INHERIT)
+                .build());
+        subdir.createDirectory(asAclAttribute(dirAcl));
+        assertEquals(Attributes.getAcl(subdir), dirAcl);
+    }
+
+    public static void main(String[] args) throws IOException {
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            if (!dir.getFileStore().supportsFileAttributeView("acl")) {
+                System.out.println("ACLs not supported - test skipped!");
+                return;
+            }
+            testReadWrite(dir);
+
+            // only currently feasible on Windows
+            if (System.getProperty("os.name").startsWith("Windows"))
+                testCreateFile(dir);
+
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/attribute/Attributes/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.attribute.Attributes
+ * @library ../..
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Exercises getAttribute/setAttribute/readAttributes methods.
+ */
+
+public class Basic {
+
+    static void assertTrue(boolean okay) {
+        if (!okay)
+            throw new RuntimeException("Assertion Failed");
+    }
+
+    static void checkEqual(Object o1, Object o2) {
+        if (o1 == null) {
+            assertTrue(o2 == null);
+        } else {
+            assertTrue (o1.equals(o2));
+        }
+    }
+
+    // Exercise getAttribute/setAttribute/readAttributes on basic attributes
+    static void checkBasicAttributes(FileRef file, BasicFileAttributes attrs)
+        throws IOException
+    {
+        // getAttribute
+        checkEqual(attrs.size(), Attributes.getAttribute(file, "size"));
+        checkEqual(attrs.lastModifiedTime(),
+                   Attributes.getAttribute(file, "basic:lastModifiedTime"));
+        checkEqual(attrs.lastAccessTime(),
+                   Attributes.getAttribute(file, "lastAccessTime"));
+        checkEqual(attrs.creationTime(),
+                   Attributes.getAttribute(file, "basic:creationTime"));
+        assertTrue((Boolean)Attributes.getAttribute(file, "isRegularFile"));
+        assertTrue(!(Boolean)Attributes.getAttribute(file, "basic:isDirectory"));
+        assertTrue(!(Boolean)Attributes.getAttribute(file, "isSymbolicLink"));
+        assertTrue(!(Boolean)Attributes.getAttribute(file, "basic:isOther"));
+        checkEqual(attrs.linkCount(),
+                   (Integer)Attributes.getAttribute(file, "linkCount"));
+        checkEqual(attrs.fileKey(), Attributes.getAttribute(file, "basic:fileKey"));
+
+        // setAttribute
+        if (attrs.resolution() == TimeUnit.MILLISECONDS) {
+            long modTime = attrs.lastModifiedTime();
+            Attributes.setAttribute(file, "basic:lastModifiedTime", 0L);
+            assertTrue(Attributes.readBasicFileAttributes(file).lastModifiedTime() == 0L);
+            Attributes.setAttribute(file, "lastModifiedTime", modTime);
+            assertTrue(Attributes.readBasicFileAttributes(file).lastModifiedTime() == modTime);
+        }
+
+        // readAttributes
+        Map<String,?> map;
+        map = Attributes.readAttributes(file, "*");
+        assertTrue(map.size() >= 11);
+        checkEqual(attrs.isRegularFile(), map.get("isRegularFile")); // check one
+
+        map = Attributes.readAttributes(file, "basic:*");
+        assertTrue(map.size() >= 11);
+        checkEqual(attrs.lastAccessTime(), map.get("lastAccessTime")); // check one
+
+        map = Attributes.readAttributes(file, "size,lastModifiedTime");
+        assertTrue(map.size() == 2);
+        checkEqual(attrs.size(), map.get("size"));
+        checkEqual(attrs.lastModifiedTime(), map.get("lastModifiedTime"));
+
+        map = Attributes.readAttributes(file,
+            "basic:lastModifiedTime,lastAccessTime,linkCount,ShouldNotExist");
+        assertTrue(map.size() == 3);
+        checkEqual(attrs.lastModifiedTime(), map.get("lastModifiedTime"));
+        checkEqual(attrs.lastAccessTime(), map.get("lastAccessTime"));
+        checkEqual(attrs.lastAccessTime(), map.get("lastAccessTime"));
+    }
+
+    // Exercise getAttribute/setAttribute/readAttributes on posix attributes
+    static void checkPosixAttributes(FileRef file, PosixFileAttributes attrs)
+        throws IOException
+    {
+        checkBasicAttributes(file, attrs);
+
+        // getAttribute
+        checkEqual(attrs.permissions(),
+                   Attributes.getAttribute(file, "posix:permissions"));
+        checkEqual(attrs.owner(),
+                   Attributes.getAttribute(file, "posix:owner"));
+        checkEqual(attrs.group(),
+                   Attributes.getAttribute(file, "posix:group"));
+
+        // setAttribute
+        Set<PosixFilePermission> orig = attrs.permissions();
+        Set<PosixFilePermission> newPerms = new HashSet<PosixFilePermission>(orig);
+        newPerms.remove(PosixFilePermission.OTHERS_READ);
+        newPerms.remove(PosixFilePermission.OTHERS_WRITE);
+        newPerms.remove(PosixFilePermission.OTHERS_EXECUTE);
+        Attributes.setAttribute(file, "posix:permissions", newPerms);
+        checkEqual(Attributes.readPosixFileAttributes(file).permissions(), newPerms);
+        Attributes.setAttribute(file, "posix:permissions", orig);
+        checkEqual(Attributes.readPosixFileAttributes(file).permissions(), orig);
+        Attributes.setAttribute(file, "posix:owner", attrs.owner());
+        Attributes.setAttribute(file, "posix:group", attrs.group());
+
+        // readAttributes
+        Map<String,?> map;
+        map = Attributes.readAttributes(file, "posix:*");
+        assertTrue(map.size() >= 14);
+        checkEqual(attrs.permissions(), map.get("permissions")); // check one
+
+        map = Attributes.readAttributes(file, "posix:size,owner,ShouldNotExist");
+        assertTrue(map.size() == 2);
+        checkEqual(attrs.size(), map.get("size"));
+        checkEqual(attrs.owner(), map.get("owner"));
+    }
+
+    // Exercise getAttribute/setAttribute/readAttributes on unix attributes
+    static void checkUnixAttributes(FileRef file) throws IOException {
+        // getAttribute
+        int mode = (Integer)Attributes.getAttribute(file, "unix:mode");
+        long ino = (Long)Attributes.getAttribute(file, "unix:ino");
+        long dev = (Long)Attributes.getAttribute(file, "unix:dev");
+        long rdev = (Long)Attributes.getAttribute(file, "unix:rdev");
+        int uid = (Integer)Attributes.getAttribute(file, "unix:uid");
+        int gid = (Integer)Attributes.getAttribute(file, "unix:gid");
+        long ctime = (Long)Attributes.getAttribute(file, "unix:ctime");
+
+        // readAttributes
+        Map<String,?> map;
+        map = Attributes.readAttributes(file, "unix:*");
+        assertTrue(map.size() >= 21);
+
+        map = Attributes.readAttributes(file, "unix:size,uid,gid,ShouldNotExist");
+        assertTrue(map.size() == 3);
+        checkEqual(map.get("size"),
+                   Attributes.readBasicFileAttributes(file).size());
+    }
+
+    // Exercise getAttribute/setAttribute/readAttributes on dos attributes
+    static void checkDosAttributes(FileRef file, DosFileAttributes attrs)
+        throws IOException
+    {
+        checkBasicAttributes(file, attrs);
+
+        // getAttribute
+        checkEqual(attrs.isReadOnly(),
+                   Attributes.getAttribute(file, "dos:readonly"));
+        checkEqual(attrs.isHidden(),
+                   Attributes.getAttribute(file, "dos:hidden"));
+        checkEqual(attrs.isSystem(),
+                   Attributes.getAttribute(file, "dos:system"));
+        checkEqual(attrs.isArchive(),
+                   Attributes.getAttribute(file, "dos:archive"));
+
+        // setAttribute
+        boolean value;
+
+        value = attrs.isReadOnly();
+        Attributes.setAttribute(file, "dos:readonly", !value);
+        checkEqual(Attributes.readDosFileAttributes(file).isReadOnly(), !value);
+        Attributes.setAttribute(file, "dos:readonly", value);
+        checkEqual(Attributes.readDosFileAttributes(file).isReadOnly(), value);
+
+        value = attrs.isHidden();
+        Attributes.setAttribute(file, "dos:hidden", !value);
+        checkEqual(Attributes.readDosFileAttributes(file).isHidden(), !value);
+        Attributes.setAttribute(file, "dos:hidden", value);
+        checkEqual(Attributes.readDosFileAttributes(file).isHidden(), value);
+
+        value = attrs.isSystem();
+        Attributes.setAttribute(file, "dos:system", !value);
+        checkEqual(Attributes.readDosFileAttributes(file).isSystem(), !value);
+        Attributes.setAttribute(file, "dos:system", value);
+        checkEqual(Attributes.readDosFileAttributes(file).isSystem(), value);
+
+        value = attrs.isArchive();
+        Attributes.setAttribute(file, "dos:archive", !value);
+        checkEqual(Attributes.readDosFileAttributes(file).isArchive(), !value);
+        Attributes.setAttribute(file, "dos:archive", value);
+        checkEqual(Attributes.readDosFileAttributes(file).isArchive(), value);
+
+        // readAttributes
+        Map<String,?> map;
+        map = Attributes.readAttributes(file, "dos:*");
+        assertTrue(map.size() >= 15);
+        checkEqual(attrs.isReadOnly(), map.get("readonly")); // check one
+
+        map = Attributes.readAttributes(file, "dos:size,hidden,ShouldNotExist");
+        assertTrue(map.size() == 2);
+        checkEqual(attrs.size(), map.get("size"));
+        checkEqual(attrs.isHidden(), map.get("hidden"));
+    }
+
+    static void doTests(Path dir) throws IOException {
+        Path file = dir.resolve("foo").createFile();
+        FileStore store = file.getFileStore();
+        try {
+            checkBasicAttributes(file,
+                Attributes.readBasicFileAttributes(file));
+
+            if (store.supportsFileAttributeView("posix"))
+                checkPosixAttributes(file,
+                    Attributes.readPosixFileAttributes(file));
+
+            if (store.supportsFileAttributeView("unix"))
+                checkUnixAttributes(file);
+
+            if (store.supportsFileAttributeView("dos"))
+                checkDosAttributes(file,
+                    Attributes.readDosFileAttributes(file));
+        } finally {
+            file.delete();
+        }
+    }
+
+
+    public static void main(String[] args) throws IOException {
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            doTests(dir);
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.attribute.BasicFileAttributeView
+ * @library ../..
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.io.*;
+
+public class Basic {
+
+    static void check(boolean okay, String msg) {
+        if (!okay)
+            throw new RuntimeException(msg);
+    }
+
+    static void checkAttributesOfDirectory(Path dir)
+        throws IOException
+    {
+        BasicFileAttributes attrs = Attributes.readBasicFileAttributes(dir);
+        check(attrs.isDirectory(), "is a directory");
+        check(!attrs.isRegularFile(), "is not a regular file");
+        check(!attrs.isSymbolicLink(), "is not a link");
+        check(!attrs.isOther(), "is not other");
+        check(attrs.linkCount() >= 1, "should be at least 1");
+
+        // last-modified-time should match java.io.File
+        if (attrs.resolution() == TimeUnit.MILLISECONDS) {
+            File f = new File(dir.toString());
+            check(f.lastModified() == attrs.lastModifiedTime(),
+                "last-modified time should be the same");
+        }
+    }
+
+    static void checkAttributesOfFile(Path dir, Path file)
+        throws IOException
+    {
+        BasicFileAttributes attrs = Attributes.readBasicFileAttributes(file);
+        check(attrs.isRegularFile(), "is a regular file");
+        check(!attrs.isDirectory(), "is not a directory");
+        check(!attrs.isSymbolicLink(), "is not a link");
+        check(!attrs.isOther(), "is not other");
+        check(attrs.linkCount() >= 1, "should be at least 1");
+
+        // size and last-modified-time should match java.io.File
+        File f = new File(file.toString());
+        check(f.length() == attrs.size(), "size should be the same");
+        if (attrs.resolution() == TimeUnit.MILLISECONDS) {
+            check(f.lastModified() == attrs.lastModifiedTime(),
+                "last-modified time should be the same");
+        }
+
+        // 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);
+        view.setTimes(dirAttrs.lastModifiedTime(), null, null, dirAttrs.resolution());
+        if (dirAttrs.creationTime() != -1L) {
+            view.setTimes(null, null, dirAttrs.creationTime(), dirAttrs.resolution());
+        }
+        attrs = view.readAttributes();
+        check(attrs.lastModifiedTime() == dirAttrs.lastModifiedTime(),
+            "last-modified time should be equal");
+        if (dirAttrs.creationTime() != -1L) {
+            check(attrs.creationTime() == dirAttrs.creationTime(),
+                "create time should be the same");
+        }
+
+        // security tests
+        check (!(attrs instanceof PosixFileAttributes),
+            "should not be able to cast to PosixFileAttributes");
+    }
+
+    static void checkAttributesOfLink(Path link)
+        throws IOException
+    {
+        BasicFileAttributes attrs = Attributes
+            .readBasicFileAttributes(link, LinkOption.NOFOLLOW_LINKS);
+        check(attrs.isSymbolicLink(), "is a link");
+        check(!attrs.isDirectory(), "is a directory");
+        check(!attrs.isRegularFile(), "is not a regular file");
+        check(!attrs.isOther(), "is not other");
+        check(attrs.linkCount() >= 1, "should be at least 1");
+    }
+
+    static void attributeReadWriteTests(Path dir)
+        throws IOException
+    {
+        // create file
+        Path file = dir.resolve("foo");
+        OutputStream out = file.newOutputStream();
+        try {
+            out.write("this is not an empty file".getBytes("UTF-8"));
+        } finally {
+            out.close();
+        }
+
+        // check attributes of directory and file
+        checkAttributesOfDirectory(dir);
+        checkAttributesOfFile(dir, file);
+
+        // symbolic links may be supported
+        Path link = dir.resolve("link");
+        try {
+            link.createSymbolicLink( file );
+        } catch (UnsupportedOperationException x) {
+            return;
+        } catch (IOException x) {
+            return;
+        }
+        checkAttributesOfLink(link);
+    }
+
+    public static void main(String[] args) throws IOException {
+        // create temporary directory to run tests
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            attributeReadWriteTests(dir);
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/attribute/DosFileAttributeView/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.attribute.DosFileAttributeView
+ * @library ../..
+ */
+
+import java.nio.file.*;
+import static java.nio.file.LinkOption.*;
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.io.IOException;
+
+public class Basic {
+
+    static void check(boolean okay) {
+        if (!okay)
+            throw new RuntimeException("Test failed");
+    }
+
+    // exercise each setter/getter method, leaving all attributes unset
+    static void testAttributes(DosFileAttributeView view) throws IOException {
+        view.setReadOnly(true);
+        check(view.readAttributes().isReadOnly());
+        view.setReadOnly(false);
+        check(!view.readAttributes().isReadOnly());
+        view.setHidden(true);
+        check(view.readAttributes().isHidden());
+        view.setHidden(false);
+        check(!view.readAttributes().isHidden());
+        view.setArchive(true);
+        check(view.readAttributes().isArchive());
+        view.setArchive(false);
+        check(!view.readAttributes().isArchive());
+        view.setSystem(true);
+        check(view.readAttributes().isSystem());
+        view.setSystem(false);
+        check(!view.readAttributes().isSystem());
+    }
+
+    // set the value of all attributes
+    static void setAll(DosFileAttributeView view, boolean value)
+        throws IOException
+    {
+        view.setReadOnly(value);
+        view.setHidden(value);
+        view.setArchive(value);
+        view.setSystem(value);
+    }
+
+    // read and write FAT attributes
+    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.newOutputStream().close();
+        try {
+            testAttributes(file
+                .getFileAttributeView(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);
+
+            // test following links
+            testAttributes(link
+                .getFileAttributeView(DosFileAttributeView.class));
+
+            // test not following links
+            try {
+                try {
+                    testAttributes(link
+                        .getFileAttributeView(DosFileAttributeView.class, NOFOLLOW_LINKS));
+                } catch (IOException x) {
+                    // access to link attributes not supported
+                    return;
+                }
+
+                // 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);
+                check(attrs.isReadOnly());
+                check(attrs.isHidden());
+                check(attrs.isArchive());
+                check(attrs.isSystem());
+                setAll(link
+                    .getFileAttributeView(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);
+                check(attrs.isReadOnly());
+                check(attrs.isHidden());
+                check(attrs.isArchive());
+                check(attrs.isSystem());
+                setAll(link
+                    .getFileAttributeView(DosFileAttributeView.class), false);
+            } finally {
+                TestUtil.deleteUnchecked(link);
+            }
+        } finally {
+            TestUtil.deleteUnchecked(file);
+        }
+    }
+
+    public static void main(String[] args) throws IOException {
+        // create temporary directory to run tests
+        Path dir = TestUtil.createTemporaryDirectory();
+
+        try {
+            // skip test if DOS file attributes not supported
+            if (!dir.getFileStore().supportsFileAttributeView("dos")) {
+                System.out.println("DOS file attribute not supported.");
+                return;
+            }
+            readWriteTests(dir);
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/attribute/FileStoreAttributeView/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @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 (and in bulk)
+        FileStoreAttributeView view = fs.getFileStoreAttributeView("space");
+        checkWithin1GB(total, (Long)view.getAttribute("totalSpace"));
+        checkWithin1GB(free, (Long)view.getAttribute("unallocatedSpace"));
+        checkWithin1GB(usable, (Long)view.getAttribute("usableSpace"));
+        Map<String,?> map = view.readAttributes("*");
+        checkWithin1GB(total, (Long)map.get("totalSpace"));
+        checkWithin1GB(free, (Long)map.get("unallocatedSpace"));
+        checkWithin1GB(usable, (Long)map.get("usableSpace"));
+        map = view.readAttributes("totalSpace", "unallocatedSpace", "usableSpace");
+        checkWithin1GB(total, (Long)map.get("totalSpace"));
+        checkWithin1GB(free, (Long)map.get("unallocatedSpace"));
+        checkWithin1GB(usable, (Long)map.get("usableSpace"));
+    }
+
+    /**
+     * Check (Windows-specific) volume attributes
+     */
+    static void checkVolumeAttributes() throws IOException {
+        System.out.println(" -- volumes -- ");
+        for (FileStore store: FileSystems.getDefault().getFileStores()) {
+            FileStoreAttributeView view = store.getFileStoreAttributeView("volume");
+            if (view == null)
+                continue;
+            Map<String,?> attrs = view.readAttributes("*");
+            int vsn = (Integer)attrs.get("vsn");
+            boolean compressed = (Boolean)attrs.get("compressed");
+            boolean removable = (Boolean)attrs.get("removable");
+            boolean cdrom = (Boolean)attrs.get("cdrom");
+            String type;
+            if (removable) type = "removable";
+            else if (cdrom) type = "cdrom";
+            else type = "unknown";
+            System.out.format("%s (%s) vsn:%x compressed:%b%n", store.name(),
+                type, vsn, compressed);
+        }
+
+    }
+
+    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);
+
+            // volume attributes (Windows specific)
+            checkVolumeAttributes();
+
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,398 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.attribute.PosixFileAttributeView
+ * @library ../..
+ */
+
+import java.nio.file.*;
+import static java.nio.file.LinkOption.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Unit test for PosixFileAttributeView, passing silently if this attribute
+ * view is not available.
+ */
+
+public class Basic {
+
+    /**
+     * Use view to update permission to the given mode and check that the
+     * permissions have been updated.
+     */
+    static void testPermissions(PosixFileAttributeView view, String mode)
+        throws IOException
+    {
+        System.out.format("change mode: %s\n", mode);
+        Set<PosixFilePermission> perms = PosixFilePermissions.fromString(mode);
+
+        // change permissions and re-read them.
+        view.setPermissions(perms);
+        Set<PosixFilePermission> current = view.readAttributes().permissions();
+        if (!current.equals(perms)) {
+            throw new RuntimeException("Actual permissions: " +
+                PosixFilePermissions.toString(current) + ", expected: " +
+                PosixFilePermissions.toString(perms));
+        }
+
+        // repeat test using setAttribute/getAttribute
+        view.setAttribute("permissions", perms);
+        current = (Set<PosixFilePermission>)view.getAttribute("permissions");
+        if (!current.equals(perms)) {
+            throw new RuntimeException("Actual permissions: " +
+                PosixFilePermissions.toString(current) + ", expected: " +
+                PosixFilePermissions.toString(perms));
+        }
+    }
+
+    /**
+     * Check that the actual permissions of a file match or make it more
+     * secure than requested
+     */
+    static void checkSecure(Set<PosixFilePermission> requested,
+                            Set<PosixFilePermission> actual)
+    {
+        for (PosixFilePermission perm: actual) {
+            if (!requested.contains(perm)) {
+                throw new RuntimeException("Actual permissions: " +
+                    PosixFilePermissions.toString(actual) + ", requested: " +
+                    PosixFilePermissions.toString(requested) +
+                    " - file is less secure than requested");
+            }
+        }
+    }
+
+    /**
+     * Create file with given mode and check that the file is created with a
+     * mode that is not less secure
+     */
+    static void createWithPermissions(Path file,
+                                      String mode)
+        throws IOException
+    {
+        Set<PosixFilePermission> requested = PosixFilePermissions.fromString(mode);
+        FileAttribute<Set<PosixFilePermission>> attr =
+            PosixFilePermissions.asFileAttribute(requested);
+        System.out.format("create file with mode: %s\n", mode);
+
+        EnumSet<StandardOpenOption> options = EnumSet.of(StandardOpenOption.CREATE_NEW,
+            StandardOpenOption.WRITE);
+        file.newOutputStream(options, attr).close();
+        try {
+            checkSecure(requested,  file
+                .getFileAttributeView(PosixFileAttributeView.class)
+                .readAttributes()
+                .permissions());
+        } finally {
+            file.delete(false);
+        }
+
+        System.out.format("create directory with mode: %s\n", mode);
+        file.createDirectory(attr);
+        try {
+            checkSecure(requested,  file
+                .getFileAttributeView(PosixFileAttributeView.class)
+                .readAttributes()
+                .permissions());
+        } finally {
+            file.delete(false);
+        }
+    }
+
+    /**
+     * Test the setPermissions/permissions methods.
+     */
+    static void permissionTests(Path dir)
+        throws IOException
+    {
+        System.out.println("-- Permission Tests  --");
+
+        // create file and test updating and reading its permissions
+        Path file = dir.resolve("foo");
+        System.out.format("create %s\n", file);
+        file.newOutputStream().close();
+        try {
+            // get initial permissions so that we can restore them later
+            PosixFileAttributeView view = file
+                .getFileAttributeView(PosixFileAttributeView.class);
+            Set<PosixFilePermission> save = view.readAttributes()
+                .permissions();
+
+            // test various modes
+            try {
+                testPermissions(view, "---------");
+                testPermissions(view, "r--------");
+                testPermissions(view, "-w-------");
+                testPermissions(view, "--x------");
+                testPermissions(view, "rwx------");
+                testPermissions(view, "---r-----");
+                testPermissions(view, "----w----");
+                testPermissions(view, "-----x---");
+                testPermissions(view, "---rwx---");
+                testPermissions(view, "------r--");
+                testPermissions(view, "-------w-");
+                testPermissions(view, "--------x");
+                testPermissions(view, "------rwx");
+                testPermissions(view, "r--r-----");
+                testPermissions(view, "r--r--r--");
+                testPermissions(view, "rw-rw----");
+                testPermissions(view, "rwxrwx---");
+                testPermissions(view, "rw-rw-r--");
+                testPermissions(view, "r-xr-x---");
+                testPermissions(view, "r-xr-xr-x");
+                testPermissions(view, "rwxrwxrwx");
+            } finally {
+                view.setPermissions(save);
+            }
+        } finally {
+            file.delete(false);
+        }
+
+        // create link (to file that doesn't exist) and test reading of
+        // permissions
+        if (TestUtil.supportsLinks(dir)) {
+            Path link = dir.resolve("link");
+            System.out.format("create link %s\n", link);
+            link.createSymbolicLink(file);
+            try {
+                PosixFileAttributes attrs = Attributes
+                    .readPosixFileAttributes(link, NOFOLLOW_LINKS);
+                if (!attrs.isSymbolicLink()) {
+                    throw new RuntimeException("not a link");
+                }
+            } finally {
+                link.delete(false);
+            }
+        }
+
+        System.out.println("OKAY");
+    }
+
+    /**
+     * Test creating a file and directory with initial permissios
+     */
+    static void createTests(Path dir)
+        throws IOException
+    {
+        System.out.println("-- Create Tests  --");
+
+        Path file = dir.resolve("foo");
+
+        createWithPermissions(file, "---------");
+        createWithPermissions(file, "r--------");
+        createWithPermissions(file, "-w-------");
+        createWithPermissions(file, "--x------");
+        createWithPermissions(file, "rwx------");
+        createWithPermissions(file, "---r-----");
+        createWithPermissions(file, "----w----");
+        createWithPermissions(file, "-----x---");
+        createWithPermissions(file, "---rwx---");
+        createWithPermissions(file, "------r--");
+        createWithPermissions(file, "-------w-");
+        createWithPermissions(file, "--------x");
+        createWithPermissions(file, "------rwx");
+        createWithPermissions(file, "r--r-----");
+        createWithPermissions(file, "r--r--r--");
+        createWithPermissions(file, "rw-rw----");
+        createWithPermissions(file, "rwxrwx---");
+        createWithPermissions(file, "rw-rw-r--");
+        createWithPermissions(file, "r-xr-x---");
+        createWithPermissions(file, "r-xr-xr-x");
+        createWithPermissions(file, "rwxrwxrwx");
+
+        System.out.println("OKAY");
+    }
+
+    /**
+     * Test setOwner/setGroup methods - this test simply exercises the
+     * methods to avoid configuration.
+     */
+    static void ownerTests(Path dir)
+        throws IOException
+    {
+        System.out.println("-- Owner Tests  --");
+
+        Path file = dir.resolve("gus");
+        System.out.format("create %s\n", file);
+
+        file.newOutputStream().close();
+        try {
+
+            // read attributes of directory to get owner/group
+            PosixFileAttributeView view = file
+                .getFileAttributeView(PosixFileAttributeView.class);
+            PosixFileAttributes attrs = view.readAttributes();
+
+            // set to existing owner/group
+            view.setOwner(attrs.owner());
+            view.setGroup(attrs.group());
+
+            // repeat test using setAttribute
+            Map<String,?> map = view.readAttributes("owner","group");
+            view.setAttribute("owner", map.get("owner"));
+            view.setAttribute("group", map.get("group"));
+
+        } finally {
+            file.delete(false);
+        }
+
+        System.out.println("OKAY");
+    }
+
+    /**
+     * Test the lookupPrincipalByName/lookupPrincipalByGroupName methods
+     */
+    static void lookupPrincipalTests(Path dir)
+        throws IOException
+    {
+        System.out.println("-- Lookup UserPrincipal Tests --");
+
+        UserPrincipalLookupService lookupService = dir.getFileSystem()
+            .getUserPrincipalLookupService();
+
+        // read attributes of directory to get owner/group
+        PosixFileAttributes attrs = Attributes.readPosixFileAttributes(dir);
+
+        // lookup owner and check it matches file's owner
+        System.out.format("lookup: %s\n", attrs.owner().getName());
+        try {
+            UserPrincipal owner = lookupService.lookupPrincipalByName(attrs.owner().getName());
+            if (owner instanceof GroupPrincipal)
+                throw new RuntimeException("owner is a group?");
+            if (!owner.equals(attrs.owner()))
+                throw new RuntimeException("owner different from file owner");
+        } catch (UserPrincipalNotFoundException x) {
+            System.out.println("user not found - test skipped");
+        }
+
+        // lookup group and check it matches file's group-owner
+        System.out.format("lookup group: %s\n", attrs.group().getName());
+        try {
+            GroupPrincipal group = lookupService.lookupPrincipalByGroupName(attrs.group().getName());
+            if (!group.equals(attrs.group()))
+                throw new RuntimeException("group different from file group-owner");
+        } catch (UserPrincipalNotFoundException x) {
+            System.out.println("group not found - test skipped");
+        }
+
+        // test that UserPrincipalNotFoundException is thrown
+        String invalidPrincipal = "scumbag99";
+        try {
+            System.out.format("lookup: %s\n", invalidPrincipal);
+            lookupService.lookupPrincipalByName(invalidPrincipal);
+            throw new RuntimeException("'" + invalidPrincipal + "' is a valid user?");
+        } catch (UserPrincipalNotFoundException x) {
+        }
+        try {
+            System.out.format("lookup group: %s\n", invalidPrincipal);
+            lookupService.lookupPrincipalByGroupName("idonotexist");
+            throw new RuntimeException("'" + invalidPrincipal + "' is a valid group?");
+        } catch (UserPrincipalNotFoundException x) {
+        }
+        System.out.println("OKAY");
+    }
+
+    /**
+     * Test various exceptions are thrown as expected
+     */
+    @SuppressWarnings("unchecked")
+    static void exceptionsTests(Path dir)
+        throws IOException
+    {
+        System.out.println("-- Exceptions --");
+
+        PosixFileAttributeView view = dir
+            .getFileAttributeView(PosixFileAttributeView.class);
+
+        // NullPointerException
+        try {
+            view.setOwner(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+        try {
+            view.setGroup(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+
+        UserPrincipalLookupService lookupService = dir.getFileSystem()
+            .getUserPrincipalLookupService();
+        try {
+            lookupService.lookupPrincipalByName(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+        try {
+            lookupService.lookupPrincipalByGroupName(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+        try {
+            view.setPermissions(null);
+            throw new RuntimeException("NullPointerException not thrown");
+        } catch (NullPointerException x) {
+        }
+        try {
+            Set<PosixFilePermission> perms = new HashSet<PosixFilePermission>();
+            perms.add(null);
+            view.setPermissions(perms);
+            throw new RuntimeException("NullPointerException not thrown");
+        }  catch (NullPointerException x) {
+        }
+
+        // ClassCastException
+        try {
+            Set perms = new HashSet();  // raw type
+            perms.add(new Object());
+            view.setPermissions(perms);
+            throw new RuntimeException("ClassCastException not thrown");
+        }  catch (ClassCastException x) {
+        }
+
+        System.out.println("OKAY");
+    }
+
+    public static void main(String[] args) throws IOException {
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            if (!dir.getFileStore().supportsFileAttributeView("posix")) {
+                System.out.println("PosixFileAttributeView not supported");
+                return;
+            }
+
+            permissionTests(dir);
+            createTests(dir);
+            ownerTests(dir);
+            lookupPrincipalTests(dir);
+            exceptionsTests(dir);
+
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.attribute.UserDefinedFileAttributeView
+ * @library ../..
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.file.*;
+import static java.nio.file.LinkOption.*;
+import java.nio.file.attribute.*;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Random;
+import java.io.IOException;
+
+public class Basic {
+
+    private static Random rand = new Random();
+
+    private static final String ATTR_NAME = "mime_type";
+    private static final String ATTR_VALUE = "text/plain";
+    private static final String ATTR_VALUE2 = "text/html";
+
+    static interface Task {
+        void run() throws Exception;
+    }
+
+    static void tryCatch(Class<? extends Throwable> ex, Task task) {
+        boolean caught = false;
+        try {
+            task.run();
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass())) {
+                caught = true;
+            } else {
+                throw new RuntimeException(x);
+            }
+        }
+        if (!caught)
+            throw new RuntimeException(ex.getName() + " expected");
+    }
+
+    static void expectNullPointerException(Task task) {
+        tryCatch(NullPointerException.class, task);
+    }
+
+    static boolean hasAttribute(UserDefinedFileAttributeView view, String attr)
+        throws IOException
+    {
+        for (String name: view.list()) {
+            if (name.equals(ATTR_NAME))
+                return true;
+        }
+        return false;
+    }
+
+    static void test(Path file, LinkOption... options) throws IOException {
+        final UserDefinedFileAttributeView view = file
+            .getFileAttributeView(UserDefinedFileAttributeView.class, options);
+        ByteBuffer buf = rand.nextBoolean() ?
+            ByteBuffer.allocate(100) : ByteBuffer.allocateDirect(100);
+
+        // Test: write
+        buf.put(ATTR_VALUE.getBytes()).flip();
+        int size = buf.remaining();
+        int nwrote = view.write(ATTR_NAME, buf);
+        if (nwrote != size)
+            throw new RuntimeException("Unexpected number of bytes written");
+
+        // Test: size
+        if (view.size(ATTR_NAME) != size)
+            throw new RuntimeException("Unexpected size");
+
+        // Test: read
+        buf.clear();
+        int nread = view.read(ATTR_NAME, buf);
+        if (nread != size)
+            throw new RuntimeException("Unexpected number of bytes read");
+        buf.flip();
+        String value = Charset.defaultCharset().decode(buf).toString();
+        if (!value.equals(ATTR_VALUE))
+            throw new RuntimeException("Unexpected attribute value");
+
+        // Test: read with insufficient space
+        tryCatch(IOException.class, new Task() {
+            public void run() throws IOException {
+                view.read(ATTR_NAME, ByteBuffer.allocateDirect(1));
+            }});
+
+        // Test: replace value
+        buf.clear();
+        buf.put(ATTR_VALUE2.getBytes()).flip();
+        size = buf.remaining();
+        view.write(ATTR_NAME, buf);
+        if (view.size(ATTR_NAME) != size)
+            throw new RuntimeException("Unexpected size");
+
+        // Test: list
+        if (!hasAttribute(view, ATTR_NAME))
+            throw new RuntimeException("Attribute name not in list");
+
+        // Test: delete
+        view.delete(ATTR_NAME);
+        if (hasAttribute(view, ATTR_NAME))
+            throw new RuntimeException("Attribute name in list");
+
+        // Test: dynamic access
+        byte[] valueAsBytes = ATTR_VALUE.getBytes();
+        view.setAttribute(ATTR_NAME, valueAsBytes);
+        byte[] actualAsBytes = (byte[])view.getAttribute(ATTR_NAME);
+        if (!Arrays.equals(valueAsBytes, actualAsBytes))
+            throw new RuntimeException("Unexpected attribute value");
+        Map<String,?> map = view.readAttributes(ATTR_NAME);
+        if (!Arrays.equals(valueAsBytes, (byte[])map.get(ATTR_NAME)))
+            throw new RuntimeException("Unexpected attribute value");
+        map = view.readAttributes(ATTR_NAME, "*");
+        if (!Arrays.equals(valueAsBytes, (byte[])map.get(ATTR_NAME)))
+            throw new RuntimeException("Unexpected attribute value");
+        map = view.readAttributes("DoesNotExist");
+        if (!map.isEmpty())
+            throw new RuntimeException("Map expected to be empty");
+    }
+
+    static void miscTests(Path file) throws IOException {
+        final UserDefinedFileAttributeView view = file
+            .getFileAttributeView(UserDefinedFileAttributeView.class);
+        view.write(ATTR_NAME, ByteBuffer.wrap(ATTR_VALUE.getBytes()));
+
+        // NullPointerException
+        final ByteBuffer buf = ByteBuffer.allocate(100);
+
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.read(null, buf);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.read(ATTR_NAME, null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.write(null, buf);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+               view.write(ATTR_NAME, null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.size(null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.delete(null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.getAttribute(null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.setAttribute(ATTR_NAME, null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.setAttribute(null, new byte[0]);
+            }});
+         expectNullPointerException(new Task() {
+            public void run() throws IOException {
+               view.readAttributes(null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.readAttributes("*", (String[])null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.readAttributes("*", ATTR_NAME, null);
+            }});
+
+        // Read-only buffer
+        tryCatch(IllegalArgumentException.class, new Task() {
+            public void run() throws IOException {
+                ByteBuffer buf = ByteBuffer.wrap(ATTR_VALUE.getBytes()).asReadOnlyBuffer();
+                view.write(ATTR_NAME, buf);
+                buf.flip();
+                view.read(ATTR_NAME, buf);
+            }});
+
+        // Zero bytes remaining
+        tryCatch(IOException.class, new Task() {
+            public void run() throws IOException {
+                ByteBuffer buf = buf = ByteBuffer.allocateDirect(100);
+                buf.position(buf.capacity());
+                view.read(ATTR_NAME, buf);
+            }});
+    }
+
+    public static void main(String[] args) throws IOException {
+        // create temporary directory to run tests
+        Path dir = TestUtil.createTemporaryDirectory();
+        try {
+            if (!dir.getFileStore().supportsFileAttributeView("xattr")) {
+                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();
+            try {
+                test(file);
+            } finally {
+                file.delete();
+            }
+
+            // test access to user define attributes of directory
+            file = dir.resolve("foo").createDirectory();
+            try {
+                test(file);
+            } finally {
+                file.delete();
+            }
+
+            // 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);
+                try {
+                    test(link, NOFOLLOW_LINKS);
+                } catch (IOException x) {
+                    // access to attributes of sym link may not be supported
+                } finally {
+                    link.delete();
+                }
+            }
+
+            // misc. tests
+            try {
+                file = dir.resolve("foo.txt").createFile();
+                miscTests(dir);
+            } finally {
+                file.delete();
+            }
+
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/spi/SetDefaultProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @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 {
+        Class<?> c = FileSystems.getDefault().provider().getClass();
+
+        Class<?> expected = Class.forName("TestProvider", false,
+            ClassLoader.getSystemClassLoader());
+
+        if (c != expected)
+            throw new RuntimeException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/spi/TestProvider.java	Sun Feb 15 12:25:54 2009 +0000
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.nio.file.spi.FileSystemProvider;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.net.URI;
+import java.util.*;
+import java.io.IOException;
+
+public class TestProvider extends FileSystemProvider {
+
+    private final FileSystem theFileSystem;
+
+    public TestProvider(FileSystemProvider defaultProvider) {
+        theFileSystem = new TestFileSystem(this);
+
+    }
+
+    @Override
+    public String getScheme() {
+        return "file";
+    }
+
+    @Override
+    public FileSystem newFileSystem(URI uri, Map<String,?> env) {
+        throw new RuntimeException("not implemented");
+    }
+
+    @Override
+    public FileSystem getFileSystem(URI uri) {
+        return theFileSystem;
+    }
+
+    @Override
+    public Path getPath(URI uri) {
+        throw new RuntimeException("not implemented");
+    }
+
+    static class TestFileSystem extends FileSystem {
+        private final TestProvider provider;
+
+        TestFileSystem(TestProvider provider) {
+            this.provider = provider;
+        }
+
+        @Override
+        public FileSystemProvider provider() {
+            return provider;
+        }
+
+        @Override
+        public void close() throws IOException {
+            throw new RuntimeException("not implemented");
+        }
+
+        @Override
+        public boolean isOpen() {
+            throw new RuntimeException("not implemented");
+        }
+
+        @Override
+        public boolean isReadOnly() {
+            throw new RuntimeException("not implemented");
+        }
+
+        @Override
+        public String getSeparator() {
+            throw new RuntimeException("not implemented");
+        }
+
+        @Override
+        public Iterable<Path> getRootDirectories() {
+            throw new RuntimeException("not implemented");
+        }
+
+        @Override
+        public Iterable<FileStore> getFileStores() {
+            throw new RuntimeException("not implemented");
+        }
+
+        @Override
+        public Set<String> supportedFileAttributeViews() {
+            throw new RuntimeException("not implemented");
+        }
+
+        @Override
+        public Path getPath(String path) {
+            throw new RuntimeException("not implemented");
+        }
+
+        @Override
+        public PathMatcher getPathMatcher(String syntaxAndPattern) {
+            throw new RuntimeException("not implemented");
+        }
+
+        @Override
+        public UserPrincipalLookupService getUserPrincipalLookupService() {
+            throw new RuntimeException("not implemented");
+        }
+
+        @Override
+        public WatchService newWatchService() throws IOException {
+            throw new RuntimeException("not implemented");
+        }
+    }
+
+}