--- a/jdk/make/common/Defs-windows.gmk Wed Jul 05 16:47:51 2017 +0200
+++ b/jdk/make/common/Defs-windows.gmk Thu Feb 19 18:04:30 2009 -0800
@@ -398,16 +398,7 @@
# SA will never be supported here.
INCLUDE_SA = false
else
- # Hopefully, SA will be supported here one of these days,
- # and these will be changed to true. Until then,
- # to build SA on windows, do a control build with
- # BUILD_WIN_SA=1
- # on the make command.
- ifdef BUILD_WIN_SA
- INCLUDE_SA = true
- else
- INCLUDE_SA = false
- endif
+ INCLUDE_SA = true
endif
# Settings for the VERSIONINFO tap on windows.
--- a/jdk/make/docs/CORE_PKGS.gmk Wed Jul 05 16:47:51 2017 +0200
+++ b/jdk/make/docs/CORE_PKGS.gmk Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/make/docs/NON_CORE_PKGS.gmk Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/make/java/nio/Exportedfiles.gmk Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/make/java/nio/FILES_c.gmk Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/make/java/nio/FILES_java.gmk Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/make/java/nio/Makefile Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/make/java/nio/mapfile-linux Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/make/java/nio/mapfile-solaris Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/make/mksample/nio/Makefile Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/io/File.java Thu Feb 19 18:04:30 2009 -0800
@@ -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, 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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/io/FilePermission.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/net/StandardProtocolFamily.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/net/StandardSocketOption.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 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 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 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 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 1349</a>
- * and <a href="http://www.ietf.org/rfc/rfc2474.txt">RFC 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 1349</a> and <a
+ * href="http://www.ietf.org/rfc/rfc2474.txt">RFC 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 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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> <tt><</tt> <i>n</i> <tt><=</tt> <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> <tt>+</tt> <i>n</i> <tt>-</tt> <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> <tt>+</tt> <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> <tt><</tt> <i>n</i> <tt><=</tt> <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> <tt>+</tt> <i>n</i> <tt>-</tt> <tt>1</tt>.
+ * Upon completion the buffer's position will be equal to
+ * <i>p</i> <tt>+</tt> <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 Thu Feb 19 18:04:30 2009 -0800
@@ -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}<V> <em>operation</em>(<em>...</em>)</pre></li>
+ * <li><pre>Future<V> <em>operation</em>(<em>...</em> A attachment, {@link CompletionHandler}<V,? super A> 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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<SocketAddress,ByteBuffer>() {
+ * 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, (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 Thu Feb 19 18:04:30 2009 -0800
@@ -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<?>[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} + {@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} + {@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 Thu Feb 19 18:04:30 2009 -0800
@@ -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<AsynchronousSocketChannel,Void>() {
+ * 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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> <tt><</tt> <i>n</i> <tt><=</tt> <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> <tt><</tt> <i>n</i> <tt><=</tt> <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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/nio/channels/Channels.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/nio/channels/DatagramChannel.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/nio/channels/FileChannel.java Thu Feb 19 18:04:30 2009 -0800
@@ -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<?>[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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/nio/channels/FileLock.java Thu Feb 19 18:04:30 2009 -0800
@@ -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> + <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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/nio/channels/MembershipKey.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/nio/channels/MulticastChannel.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/nio/channels/NetworkChannel.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/nio/channels/SocketChannel.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/nio/channels/exceptions Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/nio/channels/package-info.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 buffer</td></tr>
* <tr><td valign=top><tt> <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> <i>{@link java.nio.channels.AsynchronousChannel}</i></tt></td>
+ * <td>Supports asynchronous I/O operations.</td></tr>
+ * <tr><td valign=top><tt> <i>{@link java.nio.channels.AsynchronousByteChannel}</i></tt></td>
+ * <td>Can read and write bytes asynchronously</td></tr>
* <tr><td valign=top><tt> <i>{@link java.nio.channels.NetworkChannel}</i></tt></td>
* <td>A channel to a network socket</td></tr>
* <tr><td valign=top><tt> <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} </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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/nio/channels/spi/package.html Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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<Path> 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 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>'\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<FileRef> 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<DirectoryStream.Filter<? super Path>> filters = ...
+ * DirectoryStream.Filter<Path> 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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<Path>() {
+ * 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 (\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>/home/*/*</tt>
+ * <td>Matches <tt>/home/gus/data</tt> on UNIX platforms</td>
+ * </tr>
+ * <tr>
+ * <td><tt>/home/**</tt>
+ * <td>Matches <tt>/home/gus</tt> and
+ * <tt>/home/gus/data</tt> on UNIX platforms</td>
+ * </tr>
+ * <tr>
+ * <td><tt>C:\\*</tt>
+ * <td>Matches <tt>C:\foo</tt> and <tt>C:\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:\\\\*"</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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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<String,String> env = new HashMap<String,String>();
+ * 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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<Path>() {
+ * @Override
+ * public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ * try {
+ * file.delete(false);
+ * } catch (IOException exc) {
+ * // failed to delete
+ * }
+ * return FileVisitResult.CONTINUE;
+ * }
+ * @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<Path>() {
+ * @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;
+ * }
+ * @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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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, 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<Path> 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<Path> filter = new DirectoryStream.Filter<Path>() {
+ * 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<Path> 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<Set<PosixFilePermission>> 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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<?> 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 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 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 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 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<AclEntry> 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}<{@link AclEntry}> </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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 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 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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}<{@link PosixFilePermission}> </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<PosixFilePermission> 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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<PosixFilePermission> 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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> <i>{@link java.nio.file.attribute.FileAttributeView}</i></tt></td>
+ * <td>Can read or update file attributes</td></tr>
+ * <tr><td valign=top><tt> <i>{@link java.nio.file.attribute.BasicFileAttributeView} </i></tt></td>
+ * <td>Can read or update a basic set of file attributes</td></tr>
+ * <tr><td valign=top><tt> <i>{@link java.nio.file.attribute.PosixFileAttributeView} </i></tt></td>
+ * <td>Can read or update POSIX defined file attributes</td></tr>
+ * <tr><td valign=top><tt> <i>{@link java.nio.file.attribute.DosFileAttributeView} </i></tt></td>
+ * <td>Can read or update FAT file attributes</td></tr>
+ * <tr><td valign=top><tt>  <i>{@link java.nio.file.attribute.FileOwnerAttributeView} </i></tt></td>
+ * <td>Can read or update the owner of a file</td></tr>
+ * <tr><td valign=top><tt> <i>{@link java.nio.file.attribute.AclFileAttributeView} </i></tt></td>
+ * <td>Can read or update Access Control Lists</td></tr>
+ * <tr><td valign=top><tt> <i>{@link java.nio.file.attribute.UserDefinedFileAttributeView} </i></tt></td>
+ * <td>Can read or update user-defined file attributes</td></tr>
+ * <tr><td valign=top><tt> <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> <i>{@link java.nio.file.attribute.FileStoreSpaceAttributeView} </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 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/java/util/Scanner.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/ExtendedSocketOption.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/FileLockImpl.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/IOUtil.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/MembershipKeyImpl.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/MembershipRegistry.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/NativeThreadSet.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/Net.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/OptionKey.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/Reflect.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/nio/ch/Util.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/classes/sun/security/util/SecurityConstants.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/share/native/sun/nio/ch/genSocketOptionRegistry.c Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ /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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/solaris/classes/sun/nio/ch/SocketDispatcher.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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);
+ }
+}
--- a/jdk/src/solaris/native/java/net/Inet4AddressImpl.c Wed Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/solaris/native/java/net/Inet4AddressImpl.c Thu Feb 19 18:04:30 2009 -0800
@@ -165,16 +165,18 @@
hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE);
CHECK_NULL_RETURN(hostname, NULL);
+#ifdef __solaris__
/*
* Workaround for Solaris bug 4160367 - if a hostname contains a
* white space then 0.0.0.0 is returned
*/
- if (isspace(hostname[0])) {
+ if (isspace((unsigned char)hostname[0])) {
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
(char *)hostname);
JNU_ReleaseStringPlatformChars(env, host, hostname);
return NULL;
}
+#endif
/* Try once, with our static buffer. */
#ifdef __GLIBC__
@@ -325,7 +327,8 @@
ping4(JNIEnv *env, jint fd, struct sockaddr_in* him, jint timeout,
struct sockaddr_in* netif, jint ttl) {
jint size;
- jint n, len, hlen1, icmplen;
+ jint n, hlen1, icmplen;
+ socklen_t len;
char sendbuf[1500];
char recvbuf[1500];
struct icmp *icmp;
--- a/jdk/src/solaris/native/java/net/Inet6AddressImpl.c Wed Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/solaris/native/java/net/Inet6AddressImpl.c Thu Feb 19 18:04:30 2009 -0800
@@ -196,16 +196,18 @@
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC;
+#ifdef __solaris__
/*
* Workaround for Solaris bug 4160367 - if a hostname contains a
* white space then 0.0.0.0 is returned
*/
- if (isspace(hostname[0])) {
+ if (isspace((unsigned char)hostname[0])) {
JNU_ThrowByName(env, JNU_JAVANETPKG "UnknownHostException",
(char *)hostname);
JNU_ReleaseStringPlatformChars(env, host, hostname);
return NULL;
}
+#endif
error = (*getaddrinfo_ptr)(hostname, NULL, &hints, &res);
@@ -455,7 +457,8 @@
ping6(JNIEnv *env, jint fd, struct sockaddr_in6* him, jint timeout,
struct sockaddr_in6* netif, jint ttl) {
jint size;
- jint n, len;
+ jint n;
+ socklen_t len;
char sendbuf[1500];
unsigned char recvbuf[1500];
struct icmp6_hdr *icmp6;
--- a/jdk/src/solaris/native/java/net/NetworkInterface.c Wed Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/solaris/native/java/net/NetworkInterface.c Thu Feb 19 18:04:30 2009 -0800
@@ -969,13 +969,39 @@
// Got access to parent, so create it if necessary.
strcpy(vname, name);
*unit = '\0';
- }
- else {
+ } else {
+#if defined(__solaris__) && defined(AF_INET6)
+ struct lifreq lifr;
+ memset((char *) &lifr, 0, sizeof(lifr));
+ strcpy(lifr.lifr_name, vname);
+
+ /* Try with an IPv6 socket in case the interface has only IPv6
+ * addresses assigned to it */
+ close(sock);
+ sock = JVM_Socket(AF_INET6, SOCK_DGRAM, 0);
+
+ if (sock < 0) {
+ NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+ "Socket creation failed");
+ return ifs; /* return untouched list */
+ }
+
+ if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifr) >= 0) {
+ // Got access to parent, so create it if necessary.
+ strcpy(vname, name);
+ *unit = '\0';
+ } else {
+ // failed to access parent interface do not create parent.
+ // We are a virtual interface with no parent.
+ isVirtual = 1;
+ vname[0] = 0;
+ }
+#else
// failed to access parent interface do not create parent.
// We are a virtual interface with no parent.
isVirtual = 1;
-
vname[0] = 0;
+#endif
}
}
close(sock);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/ch/EPoll.c Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/solaris/native/sun/nio/ch/FileChannelImpl.c Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ /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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/solaris/native/sun/nio/ch/SocketDispatcher.c Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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, ×[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, ×[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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ /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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/src/windows/native/sun/nio/ch/FileChannelImpl.c Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ /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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Jul 05 16:47:51 2017 +0200
+++ b/jdk/test/java/nio/channels/etc/NetworkChannelTests.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -0,0 +1,1 @@
+SimpleFileTypeDetector
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/Files/Misc.java Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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 Thu Feb 19 18:04:30 2009 -0800
@@ -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");
+ }
+ }
+
+}