# HG changeset patch # User duke # Date 1499266101 -7200 # Node ID 5da0e6b9f4f18ef483c977337214b12ee0e1fc8f # Parent b86b8d6d48bd8b3b9f7f51bd1d142092300f04af# Parent 804c6c2cd89c70cf4aba7be523a59df536a015e0 Merge diff -r 804c6c2cd89c -r 5da0e6b9f4f1 .hgtags-top-repo --- a/.hgtags-top-repo Wed Jul 05 16:47:52 2017 +0200 +++ b/.hgtags-top-repo Wed Jul 05 16:48:21 2017 +0200 @@ -23,3 +23,4 @@ e8a2a4d187773a62f3309b0fa265c13425bc2258 jdk7-b46 d7744e86dedc21a8ecf6bdb73eb191b8eaf5b0da jdk7-b47 4ae9f4bfdb98f65bd957e3fe72471b320150b38e jdk7-b48 +aee93a8992d2389121eb610c00a86196f3e2b9b0 jdk7-b49 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 corba/.hgtags --- a/corba/.hgtags Wed Jul 05 16:47:52 2017 +0200 +++ b/corba/.hgtags Wed Jul 05 16:48:21 2017 +0200 @@ -23,3 +23,4 @@ 1691dbfc08f8ee3f4e23a1ff30cdff920718696c jdk7-b46 167ad0164301f318b069a947e1c9c07ed667748a jdk7-b47 0be222241fd405e48915647facfaa176621b39b9 jdk7-b48 +d70978bc64bc7a04be7797ab0dcd9b7b1b3a6bff jdk7-b49 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 hotspot/.hgtags --- a/hotspot/.hgtags Wed Jul 05 16:47:52 2017 +0200 +++ b/hotspot/.hgtags Wed Jul 05 16:48:21 2017 +0200 @@ -23,3 +23,4 @@ 16bb38eeda35b46268eefa4c1f829eb086e0ca46 jdk7-b46 fcb923bad68e2b10380a030ea83a723f4dc3d4d6 jdk7-b47 bcb33806d186561c781992e5f4d8a90bb033f9f0 jdk7-b48 +8b22ccb5aba2c6c11bddf6488a7bb7ef5b4bf2be jdk7-b49 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jaxp/.hgtags --- a/jaxp/.hgtags Wed Jul 05 16:47:52 2017 +0200 +++ b/jaxp/.hgtags Wed Jul 05 16:48:21 2017 +0200 @@ -23,3 +23,4 @@ b2271877894af809b7703767fe8d4e38591a02a2 jdk7-b46 d711ad1954b294957737ea386cfd4d3c05028a36 jdk7-b47 39de90eb4822cafaacc69edd67ab5547e55ae920 jdk7-b48 +5c1f24531903573c1830775432276da567243f9c jdk7-b49 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jaxws/.hgtags --- a/jaxws/.hgtags Wed Jul 05 16:47:52 2017 +0200 +++ b/jaxws/.hgtags Wed Jul 05 16:48:21 2017 +0200 @@ -23,3 +23,4 @@ af4a3eeb7812a5d09a241c50b51b3c648a9d45c1 jdk7-b46 223011570edbd49bb0fe51cdeb2089f95d305267 jdk7-b47 01e5dd31d0c10a2db3d50db346905d2d3db45e88 jdk7-b48 +18ca864890f3d4ed942ecbffb78c936a57759921 jdk7-b49 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/.hgtags --- a/jdk/.hgtags Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/.hgtags Wed Jul 05 16:48:21 2017 +0200 @@ -23,3 +23,4 @@ 4b03e27a44090d1f646af28dc58f9ead827e24c7 jdk7-b46 b4ac413b1f129eeef0acab3f31081c1b7dfe3b27 jdk7-b47 5fbd9ea7def17186693b6f7099b5d0dc73903eee jdk7-b48 +8311105ea7a3db7bcbcb2b696459127c7f2297a4 jdk7-b49 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/make/common/Defs-windows.gmk --- a/jdk/make/common/Defs-windows.gmk Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/make/common/Defs-windows.gmk Wed Jul 05 16:48:21 2017 +0200 @@ -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. diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/make/docs/CORE_PKGS.gmk --- a/jdk/make/docs/CORE_PKGS.gmk Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/make/docs/CORE_PKGS.gmk Wed Jul 05 16:48:21 2017 +0200 @@ -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 \ diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/make/docs/NON_CORE_PKGS.gmk --- a/jdk/make/docs/NON_CORE_PKGS.gmk Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/make/docs/NON_CORE_PKGS.gmk Wed Jul 05 16:48:21 2017 +0200 @@ -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) \ diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/make/java/nio/Exportedfiles.gmk --- a/jdk/make/java/nio/Exportedfiles.gmk Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/make/java/nio/Exportedfiles.gmk Wed Jul 05 16:48:21 2017 +0200 @@ -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 \ diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/make/java/nio/FILES_c.gmk --- a/jdk/make/java/nio/FILES_c.gmk Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/make/java/nio/FILES_c.gmk Wed Jul 05 16:48:21 2017 +0200 @@ -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 \ diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/make/java/nio/FILES_java.gmk --- a/jdk/make/java/nio/FILES_java.gmk Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/make/java/nio/FILES_java.gmk Wed Jul 05 16:48:21 2017 +0200 @@ -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,25 @@ 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/BasicFileAttributesHolder.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 +373,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 \ diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/make/java/nio/Makefile --- a/jdk/make/java/nio/Makefile Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/make/java/nio/Makefile Wed Jul 05 16:48:21 2017 +0200 @@ -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 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/make/java/nio/mapfile-linux --- a/jdk/make/java/nio/mapfile-linux Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/make/java/nio/mapfile-linux Wed Jul 05 16:48:21 2017 +0200 @@ -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: *; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/make/java/nio/mapfile-solaris --- a/jdk/make/java/nio/mapfile-solaris Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/make/java/nio/mapfile-solaris Wed Jul 05 16:48:21 2017 +0200 @@ -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: *; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/make/mksample/nio/Makefile --- a/jdk/make/mksample/nio/Makefile Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/make/mksample/nio/Makefile Wed Jul 05 16:48:21 2017 +0200 @@ -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) diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/make/mksample/nio/file/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/mksample/nio/file/Makefile Wed Jul 05 16:48:21 2017 +0200 @@ -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 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/com/sun/nio/file/ExtendedCopyOption.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/nio/file/ExtendedCopyOption.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 extended 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, +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/com/sun/nio/file/ExtendedOpenOption.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/nio/file/ExtendedOpenOption.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 extended 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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/com/sun/nio/file/ExtendedWatchEventModifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/nio/file/ExtendedWatchEventModifier.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 extended 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, +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/com/sun/nio/file/SensitivityWatchEventModifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/com/sun/nio/file/SensitivityWatchEventModifier.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 sensitivity levels 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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/io/File.java --- a/jdk/src/share/classes/java/io/File.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/io/File.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 File object * will never change. * + *

Interoperability with {@code java.nio.file} package

+ * + *

The {@code java.nio.file} + * 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. * + *

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 * "file", a path representing this abstract pathname, * and undefined authority, query, and fragment components @@ -764,6 +786,8 @@ * If a security manager exists and its {@link * java.lang.SecurityManager#checkRead(java.lang.String)} * 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 {@link * java.lang.SecurityManager#checkRead(java.lang.String)} * 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 {@link * java.lang.SecurityManager#checkRead(java.lang.String)} * 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 {@link * java.lang.SecurityManager#checkRead(java.lang.String)} * 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. * + *

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 true if and only if the file or directory is * successfully deleted; false otherwise * @@ -973,6 +1009,13 @@ * will appear in any specific order; they are not, in particular, * guaranteed to appear in alphabetical order. * + *

Note that the {@link Path} class defines the {@link + * Path#newDirectoryStream newDirectoryStream} method to open a directory + * and iterate over the names of the files in the directory. This may use + * less resources when working with very large directories. The {@link + * #toPath toPath} method may be used to obtain a {@code Path} representing + * this abstract pathname. + * * @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 v = new ArrayList(); 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. * + *

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. * + *

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

Note that the {@link Path} class defines the {@link Path#moveTo + * moveTo} method to move or rename a file in a platform independent manner. + * The {@link #toPath toPath} method may be used to obtain a {@code Path} + * representing this abstract pathname. + * * @param dest The new abstract pathname for the named file * * @return true 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. * + *

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 true, sets the access permission to allow write * operations; if false to disallow write operations @@ -1371,6 +1436,10 @@ * Sets the owner's or everybody's read permission for this abstract * pathname. * + *

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 true, sets the access permission to allow read * operations; if false to disallow read operations @@ -1440,6 +1509,10 @@ * Sets the owner's or everybody's execute permission for this abstract * pathname. * + *

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 true, sets the access permission to allow execute * operations; if false 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> defaultPosixFilePermissions = + PosixFilePermissions.asFileAttribute(EnumSet + .of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE)); + static final boolean isPosix = isPosix(); + static boolean isPosix() { + return AccessController.doPrivileged( + new PrivilegedAction() { + 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. + * + *

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. + * + *

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 prefix argument contains fewer than three + * characters + * @throws UnsupportedOperationException + * If the array contains an attribute that cannot be set atomically + * when creating the file + * @throws IOException + * If a file could not be created + * @throws SecurityException + * If a security manager exists and its {@link + * java.lang.SecurityManager#checkWrite(java.lang.String)} + * method does not allow a file to be created. 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[] 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: + *

+     * {@link FileSystems#getDefault FileSystems.getDefault}().{@link FileSystem#getPath getPath}(this.{@link #getPath getPath}());
+     * 
+ * Subsequent invocations of this method return the same {@code Path}. + * + *

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; + } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/io/FilePermission.java --- a/jdk/src/share/classes/java/io/FilePermission.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/io/FilePermission.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 @@ *

* 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: *

*

*
read
read permission @@ -69,6 +69,11 @@ *
delete *
delete permission. Allows File.delete to * be called. Corresponds to SecurityManager.checkDelete. + *
readlink + *
read link permission. Allows the target of a + * symbolic link + * to be read by invoking the {@link java.nio.file.Path#readSymbolicLink + * readSymbolicLink } method. *
*

* 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 @@ * path is the pathname of a file or directory, and actions * 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". * *

A pathname that ends in "/*" (where "/" is * the file separator character, File.separatorChar) @@ -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 getActions + * read, write, execute, delete, readlink. For example, if this FilePermission + * object allows both write and read actions, a call to getActions * 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 perms; /** * Create an empty FilePermissions object. @@ -686,7 +715,7 @@ */ public FilePermissionCollection() { - perms = new ArrayList(); + perms = new ArrayList(); } /** @@ -791,7 +820,7 @@ // Don't call out.defaultWriteObject() // Write out Vector - Vector permissions = new Vector(perms.size()); + Vector permissions = new Vector(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 permissions = (Vector)gfields.get("permissions", null); + perms = new ArrayList(permissions.size()); perms.addAll(permissions); } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/lang/Thread.java --- a/jdk/src/share/classes/java/lang/Thread.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/lang/Thread.java Wed Jul 05 16:48:21 2017 +0200 @@ -25,13 +25,17 @@ package java.lang; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; import java.security.AccessController; import java.security.AccessControlContext; import java.security.PrivilegedAction; import java.util.Map; import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.LockSupport; -import sun.misc.SoftCache; import sun.nio.ch.Interruptible; import sun.security.util.SecurityConstants; @@ -1640,8 +1644,17 @@ new RuntimePermission("enableContextClassLoaderOverride"); /** cache of subclass security audit results */ - private static final SoftCache subclassAudits = new SoftCache(10); + /* Replace with ConcurrentReferenceHashMap when/if it appears in a future + * release */ + private static class Caches { + /** cache of subclass security audit results */ + static final ConcurrentMap subclassAudits = + new ConcurrentHashMap(); + /** queue for WeakReferences to audited subclasses */ + static final ReferenceQueue> subclassAuditsQueue = + new ReferenceQueue>(); + } /** * Verifies that this (possibly subclass) instance can be constructed @@ -1652,19 +1665,15 @@ private static boolean isCCLOverridden(Class cl) { if (cl == Thread.class) return false; - Boolean result = null; - synchronized (subclassAudits) { - result = (Boolean) subclassAudits.get(cl); - if (result == null) { - /* - * Note: only new Boolean instances (i.e., not Boolean.TRUE or - * Boolean.FALSE) must be used as cache values, otherwise cache - * entry will pin associated class. - */ - result = new Boolean(auditSubclass(cl)); - subclassAudits.put(cl, result); - } + + processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits); + WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue); + Boolean result = Caches.subclassAudits.get(key); + if (result == null) { + result = Boolean.valueOf(auditSubclass(cl)); + Caches.subclassAudits.putIfAbsent(key, result); } + return result.booleanValue(); } @@ -1967,6 +1976,68 @@ getUncaughtExceptionHandler().uncaughtException(this, e); } + /** + * Removes from the specified map any keys that have been enqueued + * on the specified reference queue. + */ + static void processQueue(ReferenceQueue> queue, + ConcurrentMap>, ?> map) + { + Reference> ref; + while((ref = queue.poll()) != null) { + map.remove(ref); + } + } + + /** + * Weak key for Class objects. + **/ + static class WeakClassKey extends WeakReference> { + /** + * saved value of the referent's identity hash code, to maintain + * a consistent hash code after the referent has been cleared + */ + private final int hash; + + /** + * Create a new WeakClassKey to the given object, registered + * with a queue. + */ + WeakClassKey(Class cl, ReferenceQueue> refQueue) { + super(cl, refQueue); + hash = System.identityHashCode(cl); + } + + /** + * Returns the identity hash code of the original referent. + */ + @Override + public int hashCode() { + return hash; + } + + /** + * Returns true if the given object is this identical + * WeakClassKey instance, or, if this object's referent has not + * been cleared, if the given object is another WeakClassKey + * instance with the identical non-null referent as this one. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + + if (obj instanceof WeakClassKey) { + Object referent = get(); + return (referent != null) && + (referent == ((WeakClassKey) obj).get()); + } else { + return false; + } + } + } + /* Some private helper methods */ private native void setPriority0(int newPriority); private native void stop0(Object o); diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/net/StandardProtocolFamily.java --- a/jdk/src/share/classes/java/net/StandardProtocolFamily.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/net/StandardProtocolFamily.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 */ diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/net/StandardSocketOption.java --- a/jdk/src/share/classes/java/net/StandardSocketOption.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/net/StandardSocketOption.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 RFC 929: * Broadcasting Internet Datagrams + * @see DatagramSocket#setBroadcast */ public static final SocketOption SO_BROADCAST = new StdSocketOption("SO_BROADCAST", Boolean.class); @@ -78,6 +79,7 @@ * * @see RFC 1122 * Requirements for Internet Hosts -- Communication Layers + * @see Socket#setKeepAlive */ public static final SocketOption SO_KEEPALIVE = new StdSocketOption("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 SO_SNDBUF = new StdSocketOption("SO_SNDBUF", Integer.class); @@ -145,6 +149,8 @@ * * @see RFC 1323: TCP * Extensions for High Performance + * @see Socket#setReceiveBufferSize + * @see ServerSocket#setReceiveBufferSize */ public static final SocketOption SO_RCVBUF = new StdSocketOption("SO_RCVBUF", Integer.class); @@ -175,6 +181,7 @@ * * @see RFC 793: Transmission * Control Protocol + * @see ServerSocket#setReuseAddress */ public static final SocketOption SO_REUSEADDR = new StdSocketOption("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 SO_LINGER = new StdSocketOption("SO_LINGER", Integer.class); @@ -215,15 +224,15 @@ /** * The Type of Service (ToS) octet in the Internet Protocol (IP) header. * - *

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 RFC 1349 - * and RFC 2474. The - * value of the socket option is a hint. An implementation may - * ignore the value, or ignore specific values. + *

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 RFC 1349 and RFC 2474. The value + * of the socket option is a hint. An implementation may ignore the + * value, or ignore specific values. * *

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 @@ *

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 IP_TOS = new StdSocketOption("IP_TOS", Integer.class); @@ -257,6 +268,7 @@ * is system dependent. * * @see java.nio.channels.MulticastChannel + * @see MulticastSocket#setInterface */ public static final SocketOption IP_MULTICAST_IF = new StdSocketOption("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 IP_MULTICAST_TTL = new StdSocketOption("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 IP_MULTICAST_LOOP = new StdSocketOption("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 RFC 1122: * Requirements for Internet Hosts -- Communication Layers + * @see Socket#setTcpNoDelay */ public static final SocketOption TCP_NODELAY = new StdSocketOption("TCP_NODELAY", Boolean.class); diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/AsynchronousByteChannel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousByteChannel.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. + * + *

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. + * + *

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. + * + *

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. + * + *

This method initiates a read operation to read up to r bytes + * from the channel, where r is the number of bytes remaining in the + * buffer, that is, {@code dst.remaining()} at the time that the read is + * attempted. Where r is 0, the read operation completes immediately + * with a result of {@code 0} without initiating an I/O operation. + * + *

Suppose that a byte sequence of length n is read, where + * 0 < n <= r. + * This byte sequence will be transferred into the buffer so that the first + * byte in the sequence is at index p and the last byte is at index + * p + n - 1, + * where p is the buffer's position at the moment the read is + * performed. Upon completion the buffer's position will be equal to + * p + n; its limit will not have changed. + * + *

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. + * + *

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. + * + *

The handler 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 + */ + Future read(ByteBuffer dst, + A attachment, + CompletionHandler handler); + + /** + * Reads a sequence of bytes from this channel into the given buffer. + * + *

An invocation of this method of the form c.read(dst) + * behaves in exactly the same manner as the invocation + *

+     * c.read(dst, null, null);
+ * + * @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 read(ByteBuffer dst); + + /** + * Writes a sequence of bytes to this channel from the given buffer. + * + *

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 Future's {@link + * Future#get() get} method, is the number of bytes written, possibly zero. + * + *

This method initiates a write operation to write up to r bytes + * to the channel, where r is the number of bytes remaining in the + * buffer, that is, {@code src.remaining()} at the moment the write is + * attempted. Where r is 0, the write operation completes immediately + * with a result of {@code 0} without initiating an I/O operation. + * + *

Suppose that a byte sequence of length n is written, where + * 0 < n <= r. + * This byte sequence will be transferred from the buffer starting at index + * p, where p is the buffer's position at the moment the + * write is performed; the index of the last byte written will be + * p + n - 1. + * Upon completion the buffer's position will be equal to + * p + n; its limit will not have changed. + * + *

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. + * + *

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. + * + *

The handler 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 + */ + Future write(ByteBuffer src, + A attachment, + CompletionHandler handler); + + /** + * Writes a sequence of bytes to this channel from the given buffer. + * + *

An invocation of this method of the form c.write(src) + * behaves in exactly the same manner as the invocation + *

+     * c.write(src, null, null);
+ * + * @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 write(ByteBuffer src); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/AsynchronousChannel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousChannel.java Wed Jul 05 16:48:21 2017 +0200 @@ -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: + * + *
    + *
  1. {@link Future}<V> operation(...)
  2. + *
  3. Future<V> operation(... A attachment, {@link CompletionHandler}<V,? super A> handler)
  4. + *
+ * + * where operation is the name of the I/O operation (read or write for + * example), V is the result type of the I/O operation, and A 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 + * state-less {@code CompletionHandler} is used to consume the result + * of many I/O operations. + * + *

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. + * + *

A channel that implements this interface is asynchronously + * closeable: 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}. + * + *

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. + * + *

Cancellation

+ * + *

The {@code Future} interface defines the {@link Future#cancel cancel} + * method to cancel execution of a task. + * + *

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}. + * + *

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. + * + *

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 error state 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. + * + *

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. + * + *

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}. + * + *

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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/AsynchronousChannelGroup.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousChannelGroup.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. + * + *

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. + * + *

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 owned by the group; termination of the group results in the + * shutdown of the associated thread pool. + * + *

In addition to groups created explicitly, the Java virtual machine + * maintains a system-wide default group 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. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
System propertyDescription
{@code java.nio.channels.DefaultThreadPool.threadFactory} 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.
{@code java.nio.channels.DefaultThreadPool.initialSize} 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.
+ * + *

Threading

+ * + *

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 identity. + * + *

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}). + * + *

Shutdown and Termination

+ * + *

The {@link #shutdown() shutdown} method is used to initiate an orderly + * shutdown 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 terminates 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. + * + *

The {@link #shutdownNow() shutdownNow} method can be used to initiate a + * forceful shutdown 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. + * + *

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. + * + *

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. + * + *

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. + * + *

The {@code initialSize} parameter may be used by the implementation + * as a hint 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. + * + *

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. + * + *

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. + * + *

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. + * + *

Care should be taken when configuring the executor service. It + * should support direct handoff or unbounded queuing 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. + * + *

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. + * + *

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. + * + *

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. + * + *

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. + * + *

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. + + *

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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. + * + *

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. + * + *

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: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Option NameDescription
{@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF} The size of the socket send buffer
{@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} The size of the socket receive buffer
{@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} Re-use address
{@link java.net.StandardSocketOption#SO_BROADCAST SO_BROADCAST} Allow transmission of broadcast datagrams
{@link java.net.StandardSocketOption#IP_TOS IP_TOS} The Type of Service (ToS) octet in the Internet Protocol (IP) header
{@link java.net.StandardSocketOption#IP_MULTICAST_IF IP_MULTICAST_IF} The network interface for Internet Protocol (IP) multicast datagrams
{@link java.net.StandardSocketOption#IP_MULTICAST_TTL + * IP_MULTICAST_TTL} The time-to-live for Internet Protocol (IP) multicast + * datagrams
{@link java.net.StandardSocketOption#IP_MULTICAST_LOOP + * IP_MULTICAST_LOOP} Loopback for Internet Protocol (IP) multicast datagrams
+ *
+ * Additional (implementation specific) options may also be supported. + * + *

Asynchronous datagram channels allow more than one read/receive and + * write/send to be oustanding at any given time. + * + *

Usage Example: + *

+ *  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) {
+ *          ...
+ *      }
+ *  });
+ * 
+ * + * @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. + * + *

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}). + * + *

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. + * + *

This method returns an asynchronous datagram channel that is + * bound to the default group. This method is equivalent to evaluating + * the expression: + *

+     * open((ProtocolFamily)null, (AsynchronousChannelGroup)null);
+     * 
+ * + * @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 AsynchronousDatagramChannel setOption(SocketOption name, T value) + throws IOException; + + /** + * Returns the remote address to which this channel is connected. + * + *

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. + * + *

The channel's socket is configured so that it only receives + * datagrams from, and sends datagrams to, the given remote peer + * 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. + * + *

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. + * + *

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. + * + *

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. + * + *

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. + * + *

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. + * + *

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. + * + *

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. + * + *

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 Future receive(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); + + /** + * Receives a datagram via this channel. + * + *

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. + * + *

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 Future receive(ByteBuffer dst, + A attachment, + CompletionHandler handler) + { + return receive(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler); + } + + /** + * Receives a datagram via this channel. + * + *

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. + * + *

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 Future receive(ByteBuffer dst) { + return receive(dst, 0L, TimeUnit.MILLISECONDS, null, null); + } + + /** + * Sends a datagram via this channel. + * + *

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. + * + *

The datagram is transferred from the byte buffer as if by a regular + * {@link AsynchronousByteChannel#write write} operation. + * + *

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. + * + *

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 Future send(ByteBuffer src, + SocketAddress target, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); + + /** + * Sends a datagram via this channel. + * + *

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. + * + *

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 Future send(ByteBuffer src, + SocketAddress target, + A attachment, + CompletionHandler handler) + { + return send(src, target, 0L, TimeUnit.MILLISECONDS, attachment, handler); + } + + /** + * Sends a datagram via this channel. + * + *

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. + * + *

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 send(ByteBuffer src, SocketAddress target) { + return send(src, target, 0L, TimeUnit.MILLISECONDS, null, null); + } + + /** + * Receives a datagram via this channel. + * + *

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. + * + *

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. + * + *

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 Future read(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler 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 read(ByteBuffer dst, + A attachment, + CompletionHandler 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 read(ByteBuffer dst) { + return read(dst, 0L, TimeUnit.MILLISECONDS, null, null); + } + + /** + * Writes a datagram to this channel. + * + *

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. + * + *

The datagram is transferred from the byte buffer as if by a regular + * {@link AsynchronousByteChannel#write write} operation. + * + *

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. + * + *

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 Future write(ByteBuffer src, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler 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 write(ByteBuffer src, + A attachment, + CompletionHandler 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 write(ByteBuffer src) { + return write(src, 0L, TimeUnit.MILLISECONDS, null, null); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/AsynchronousFileChannel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousFileChannel.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. + * + *

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}. + * + *

An asynchronous file channel does not have a current position + * within the file. Instead, the file position is specified to each read and + * write operation. + * + *

In addition to read and write operations, this class defines the + * following operations:

+ * + *
    + * + *
  • Updates made to a file may be {@link #force forced + * out} to the underlying storage device, ensuring that data are not + * lost in the event of a system crash.

  • + * + *
  • A region of a file may be {@link FileLock locked} + * against access by other programs.

  • + * + *
+ * + *

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. + * + *

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 identity). + * 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. + * + *

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. + * + *

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. + * + *

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. + * + *

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. + * + *

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. + * + *

In addition to {@code READ} and {@code WRITE}, the following options + * may be present: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Option Description
{@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} 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.
{@link StandardOpenOption#CREATE_NEW CREATE_NEW} 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.
{@link StandardOpenOption#CREATE CREATE} 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.
{@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} When this option is present then the implementation makes a + * best effort attempt to delete the file when closed by the + * the {@link #close close} method. If the {@code close} method is not + * invoked then a best effort attempt is made to delete the file + * when the Java virtual machine terminates.
{@link StandardOpenOption#SPARSE SPARSE} When creating a new file this option is a hint that the + * new file will be sparse. This option is ignored when not creating + * a new file.
{@link StandardOpenOption#SYNC SYNC} Requires that every update to the file's content or metadata be + * written synchronously to the underlying storage device. (see Synchronized I/O file + * integrity).
{@link StandardOpenOption#DSYNC DSYNC} Requires that every update to the file's content be written + * synchronously to the underlying storage device. (see Synchronized I/O file + * integrity).
+ * + *

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

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. + * + *

The {@code attrs} parameter is an optional array of file {@link + * FileAttribute file-attributes} to set atomically when creating the file. + * + *

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 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. + * + *

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

+     *     ch.{@link #open(Path,Set,ExecutorService,FileAttribute[]) open}(file, opts, null, new FileAttribute<?>[0]);
+     * 
+ * where {@code opts} is a {@code Set} containing the options specified to + * this method. + * + *

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 set = new HashSet(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. + * + *

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.

+ * + * @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. + * + *

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. + * + *

If the file does not reside on a local device then no such guarantee + * is made. + * + *

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. + * + *

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. + * + *

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. + * + *

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. + * + *

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}. + * + *

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. + * + *

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. + * + *

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 Future lock(long position, + long size, + boolean shared, + A attachment, + CompletionHandler handler); + + /** + * Acquires an exclusive lock on this channel's file. + * + *

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. + * + *

An invocation of this method of the form {@code ch.lock(att,handler)} + * behaves in exactly the same way as the invocation + *

+     *     ch.{@link #lock(long,long,boolean,Object,CompletionHandler) lock}(0L, Long.MAX_VALUE, false, att, handler)
+     * 
+ * + * @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 Future lock(A attachment, + CompletionHandler handler) + { + return lock(0L, Long.MAX_VALUE, false, attachment, handler); + } + + /** + * Acquires an exclusive lock on this channel's file. + * + *

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. + * + *

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

+     *     ch.{@link #lock(long,long,boolean,Object,CompletionHandler) lock}(0L, Long.MAX_VALUE, false, null, 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 + */ + public final Future lock() { + return lock(0L, Long.MAX_VALUE, false, null, null); + } + + /** + * Attempts to acquire a lock on the given region of this channel's file. + * + *

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. + * + *

An invocation of this method of the form {@code ch.tryLock()} + * behaves in exactly the same way as the invocation + * + *

+     *     ch.{@link #tryLock(long,long,boolean) tryLock}(0L, Long.MAX_VALUE, false) 
+ * + * @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. + * + *

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. + * + *

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 Future read(ByteBuffer dst, + long position, + A attachment, + CompletionHandler handler); + + /** + * Reads a sequence of bytes from this channel into the given buffer, + * starting at the given file position. + * + *

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. + * + *

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 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. + * + *

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. + * + *

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 Future write(ByteBuffer src, + long position, + A attachment, + CompletionHandler handler); + + /** + * Writes a sequence of bytes to this channel from the given buffer, starting + * at the given file position. + * + *

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. + * + *

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 write(ByteBuffer src, long position) { + return write(src, position, null, null); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousServerSocketChannel.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. + * + *

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 accept method on an unbound channel will + * cause a {@link NotYetBoundException} to be thrown. + * + *

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. + * + *

Socket options are configured using the {@link #setOption(SocketOption,Object) + * setOption} method. Channels of this type support the following options: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *
Option NameDescription
{@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} The size of the socket receive buffer
{@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} Re-use address
+ *
+ * Additional (implementation specific) options may also be supported. + * + *

Usage Example: + *

+ *  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) {
+ *          ...
+ *      }
+ *  });
+ * 
+ * + * @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. + * + *

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 null then the + * resulting channel is created by the system-wide default provider, and + * bound to the default group. + * + * @param group + * The group to which the newly constructed channel should be bound, + * or null 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. + * + *

This method returns an asynchronous server socket channel that is + * bound to the default group. This method is equivalent to evaluating + * the expression: + *

+     * open((AsynchronousChannelGroup)null);
+     * 
+ * + * @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. + * + *

An invocation of this method is equivalent to the following: + *

+     * bind(local, 0);
+     * 
+ * + * @param local + * The local address to bind the socket, or null 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. + * + *

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. + * + *

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 AsynchronousServerSocketChannel setOption(SocketOption name, T value) + throws IOException; + + /** + * Accepts a connection. + * + *

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. + * + *

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}. + * + *

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 Threading). + * + *

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 Future 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 Future + accept(A attachment, CompletionHandler handler); + + /** + * Accepts a connection. + * + *

This method is equivalent to invoking {@link + * #accept(Object,CompletionHandler)} with the {@code attachment} + * and {@code handler} parameters set to {@code null}. + * + * @return an Future 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 accept() { + return accept(null, null); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/channels/AsynchronousSocketChannel.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. + * + *

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}. + * + *

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. + * + *

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}. + * + *

Socket options are configured using the {@link #setOption(SocketOption,Object) + * setOption} method. Asynchronous socket channels support the following options: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Option NameDescription
{@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF} The size of the socket send buffer
{@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} The size of the socket receive buffer
{@link java.net.StandardSocketOption#SO_KEEPALIVE SO_KEEPALIVE} Keep connection alive
{@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} Re-use address
{@link java.net.StandardSocketOption#TCP_NODELAY TCP_NODELAY} Disable the Nagle algorithm
+ *
+ * Additional (implementation specific) options may also be supported. + * + *

Timeouts

+ * + *

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 error state. 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. + * + *

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 default group. + * + * @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. + * + *

This method returns an asynchronous socket channel that is bound to + * the default group.This method is equivalent to evaluating the + * expression: + *

+     * open((AsynchronousChannelGroup)null);
+     * 
+ * + * @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 AsynchronousSocketChannel setOption(SocketOption name, T value) + throws IOException; + + /** + * Shutdown the connection for reading without closing the channel. + * + *

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. + * + *

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. + * + *

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. + * + *

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. + * + *

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 Future connect(SocketAddress remote, + A attachment, + CompletionHandler handler); + + /** + * Connects this channel. + * + *

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 connect(SocketAddress remote) { + return connect(remote, null, null); + } + + /** + * Reads a sequence of bytes from this channel into the given buffer. + * + *

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. + * + *

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. + * + *

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 Future read(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler 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 Future read(ByteBuffer dst, + A attachment, + CompletionHandler 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 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 scattering read, + * 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. + * + *

This method initiates a read of up to r bytes from this channel, + * where r is the total number of bytes remaining in the specified + * subsequence of the given buffer array, that is, + * + *

+     * dsts[offset].remaining()
+     *     + dsts[offset+1].remaining()
+     *     + ... + dsts[offset+length-1].remaining()
+ * + * at the moment that the read is attempted. + * + *

Suppose that a byte sequence of length n is read, where + * 0 < n <= r. + * Up to the first dsts[offset].remaining() bytes of this sequence + * are transferred into buffer dsts[offset], up to the next + * dsts[offset+1].remaining() bytes are transferred into buffer + * dsts[offset+1], 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. + * + *

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. + * + *

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 Future read(ByteBuffer[] dsts, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); + + /** + * Writes a sequence of bytes to this channel from the given buffer. + * + *

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. + * + *

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. + * + *

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 Future write(ByteBuffer src, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler 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 Future write(ByteBuffer src, + A attachment, + CompletionHandler 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 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 gathering write, 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. + * + *

This method initiates a write of up to r bytes to this channel, + * where r is the total number of bytes remaining in the specified + * subsequence of the given buffer array, that is, + * + *

+     * srcs[offset].remaining()
+     *     + srcs[offset+1].remaining()
+     *     + ... + srcs[offset+length-1].remaining()
+ * + * at the moment that the write is attempted. + * + *

Suppose that a byte sequence of length n is written, where + * 0 < n <= r. + * Up to the first srcs[offset].remaining() bytes of this sequence + * are written from buffer srcs[offset], up to the next + * srcs[offset+1].remaining() bytes are written from buffer + * srcs[offset+1], 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. + * + *

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. + * + *

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 Future write(ByteBuffer[] srcs, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/Channels.java --- a/jdk/src/share/classes/java/nio/channels/Channels.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/nio/channels/Channels.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. + * + *

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.

+ * + * @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. + * + *

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.

+ * + * @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); } - } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/CompletionHandler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/channels/CompletionHandler.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. + * + *

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 The result type of the I/O operation + * @param The type of the object attached to the I/O operation + * + * @since 1.7 + */ + +public interface CompletionHandler { + + /** + * 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); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/DatagramChannel.java --- a/jdk/src/share/classes/java/nio/channels/DatagramChannel.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/nio/channels/DatagramChannel.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. * *

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: *

* * @@ -211,6 +213,7 @@ throws IOException; /** + * @throws UnsupportedOperationException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @throws ClosedChannelException {@inheritDoc} * @throws IOException {@inheritDoc} @@ -220,7 +223,6 @@ public abstract DatagramChannel setOption(SocketOption 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. diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/FileChannel.java --- a/jdk/src/share/classes/java/nio/channels/FileChannel.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/nio/channels/FileChannel.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. * - *

A file channel has a current position within its file which can - * be both {@link #position() queried} and {@link #position(long) - * modified}. The file itself contains a variable-length sequence + *

{@note revised} + * A file channel is a {@link SeekableByteChannel} that is connected to + * a file. It has a current position within its file which can + * be both {@link #position() queried} and {@link #position(long) + * modified}. The file itself contains a variable-length sequence * of bytes that can be read and written and whose current {@link #size - * size} can be queried. The size of the file increases + * size} 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 truncated}. The * file may also have some associated metadata such as access @@ -50,27 +57,27 @@ * *

    * - *
  • Bytes may be {@link #read(ByteBuffer, long) read} or - * {@link #write(ByteBuffer, long) written} at an absolute + *

  • Bytes may be {@link #read(ByteBuffer, long) read} or + * {@link #write(ByteBuffer, long) written} at an absolute * position in a file in a way that does not affect the channel's current * position.

  • * - *
  • A region of a file may be {@link #map mapped} + *

  • A region of a file may be {@link #map mapped} * directly into memory; for large files this is often much more efficient * than invoking the usual read or write methods. *

  • * - *
  • Updates made to a file may be {@link #force forced - * out} to the underlying storage device, ensuring that data are not + *

  • Updates made to a file may be {@link #force forced + * out} to the underlying storage device, ensuring that data are not * lost in the event of a system crash.

  • * - *
  • Bytes can be transferred from a file {@link #transferTo to - * some other channel}, and {@link #transferFrom vice - * versa}, in a way that can be optimized by many operating systems + *

  • Bytes can be transferred from a file {@link #transferTo to + * some other channel}, and {@link #transferFrom vice + * versa}, in a way that can be optimized by many operating systems * into a very fast transfer directly to or from the filesystem cache. *

  • * - *
  • A region of a file may be {@link FileLock locked} + *

  • A region of a file may be {@link FileLock locked} * against access by other programs.

  • * *
@@ -96,25 +103,23 @@ * machine. The exact nature of any such inconsistencies are system-dependent * and are therefore unspecified. * - *

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 + *

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 getChannel 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 getChannel + * 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. * - *

The state of a file channel is intimately connected to that of the - * object whose getChannel 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. - * - *

At various points this class specifies that an + *

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 "r" and will be open for reading and writing * if the instance was created with mode "rw". * - *

A file channel that is open for writing may be in + *

A file channel that is open for writing may be in * append mode, 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. + * + *

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

In the addition to {@code READ} and {@code WRITE}, the following + * options may be present: + * + *

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

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

The {@code attrs} parameter is an optional array of file {@link + * FileAttribute file-attributes} to set atomically when creating the file. + * + *

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 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. + * + *

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

+     *     fc.{@link #open(Path,Set,FileAttribute[]) open}(file, options, new FileAttribute<?>[0]);
+     * 
+ * + * @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 set = new HashSet(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.

+ * Returns the current size of this channel's file.

* * @return The current size of this channel's file, * measured in bytes @@ -359,7 +535,7 @@ *

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 mapped byte buffer} obtained by + * {@link MappedByteBuffer mapped byte buffer} 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.

@@ -678,7 +854,7 @@ * reading; for a read/write or private mapping, this channel must have * been opened for both reading and writing. * - *

The {@link MappedByteBuffer mapped byte buffer} + *

The {@link MappedByteBuffer mapped byte buffer} * returned by this method will have a position of zero and a limit and * capacity of size; 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 mode is {@link MapMode#READ_ONLY READ_ONLY} but * this channel was not opened for reading diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/FileLock.java --- a/jdk/src/share/classes/java/nio/channels/FileLock.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/nio/channels/FileLock.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. * *

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. * *

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 @@ *

File-lock objects are safe for use by multiple concurrent threads. * * - * - *

Platform dependencies

+ *

Platform dependencies

* *

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 @@ * *

On some systems, acquiring a mandatory lock on a region of a file * prevents that region from being {@link java.nio.channels.FileChannel#map - * mapped into memory}, and vice versa. Programs that combine + * mapped into memory}, and vice versa. Programs that combine * locking and mapping should be prepared for this combination to fail. * *

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.

+ * {@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 + * position + size must be non-negative + * + * @param shared + * true if this lock is shared, + * false 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. + * + *

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; } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/MembershipKey.java --- a/jdk/src/share/classes/java/nio/channels/MembershipKey.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/nio/channels/MembershipKey.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 source-specific, 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. * *

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(); } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/MulticastChannel.java --- a/jdk/src/share/classes/java/nio/channels/MulticastChannel.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/nio/channels/MulticastChannel.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. + * + *

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}. + * + *

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}. * *

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}. * *

Membership is cumulative 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 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/NetworkChannel.java --- a/jdk/src/share/classes/java/nio/channels/NetworkChannel.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/nio/channels/NetworkChannel.java Wed Jul 05 16:48:21 2017 +0200 @@ -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> options(); + Set> supportedOptions(); } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/SeekableByteChannel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/channels/SeekableByteChannel.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 position and allows the + * position to be changed. + * + *

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() queried} and + * {@link #position(long) modified}. The channel also provides access to + * the current size 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 truncated}. + * + *

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. + * + *

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. + * + *

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. + * + *

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. + * + *

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. + * + *

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. + * + *

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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java --- a/jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/nio/channels/ServerSocketChannel.java Wed Jul 05 16:48:21 2017 +0200 @@ -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} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/SocketChannel.java --- a/jdk/src/share/classes/java/nio/channels/SocketChannel.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/nio/channels/SocketChannel.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 -- diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/exceptions --- a/jdk/src/share/classes/java/nio/channels/exceptions Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/nio/channels/exceptions Wed Jul 05 16:48:21 2017 +0200 @@ -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 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/package-info.java --- a/jdk/src/share/classes/java/nio/channels/package-info.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/nio/channels/package-info.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 @@ * Can read/write to/from a buffer *     {@link java.nio.channels.SeekableByteChannel} * A {@code ByteChannel} connected to an entity that contains a variable-length sequence of bytes + *   {@link java.nio.channels.AsynchronousChannel} + * Supports asynchronous I/O operations. + *     {@link java.nio.channels.AsynchronousByteChannel} + * Can read and write bytes asynchronously *   {@link java.nio.channels.NetworkChannel} * A channel to a network socket *     {@link java.nio.channels.MulticastChannel} @@ -218,12 +222,70 @@ * directly; custom channel classes should extend the appropriate {@link * java.nio.channels.SelectableChannel} subclasses defined in this package. * + * + * + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + *

Asynchronous I/O

Description

{@link java.nio.channels.AsynchronousFileChannel}An asynchronous channel for reading, writing, and manipulating a file
{@link java.nio.channels.AsynchronousSocketChannel}An asynchronous channel to a stream-oriented connecting socket
{@link java.nio.channels.AsynchronousServerSocketChannel}  An asynchronous channel to a stream-oriented listening socket
{@link java.nio.channels.AsynchronousDatagramChannel}An asynchronous channel to a datagram-oriented socket
{@link java.nio.channels.CompletionHandler}A handler for consuming the result of an asynchronous operation
{@link java.nio.channels.AsynchronousChannelGroup}A grouping of asynchronous channels for the purpose of resource sharing
+ * + *

{@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. + * + *

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. + * + *

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 default group. Sophisticated users may wish to create their + * own asynchronous channel groups or configure the {@code ExecutorService} + * that will be used for the default group. + * + *

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 + * {@link java.nio.channels.spi} 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. + * *


*

Unless otherwise noted, passing a null 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 */ diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. + * + *

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. + * + *

All of the methods in this class are safe for use by multiple concurrent + * threads.

+ * + * @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}("asynchronousChannelProvider") + */ + 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() { + 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 sl = + ServiceLoader.load(AsynchronousChannelProvider.class, + ClassLoader.getSystemClassLoader()); + Iterator 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. + * + *

The first invocation of this method locates the default provider + * object as follows:

+ * + *
    + * + *
  1. If the system property + * java.nio.channels.spi.AsynchronousChannelProvider 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.

  2. + * + *
  3. 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 + * java.nio.channels.spi.AsynchronousChannelProvider in the resource + * directory META-INF/services, 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.

  4. + * + *
  5. 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.

  6. + * + *
+ * + *

Subsequent invocations of this method return the provider that was + * returned by the first invocation.

+ * + * @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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java --- a/jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/nio/channels/spi/SelectorProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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) { diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/java/nio/channels/spi/package.html --- a/jdk/src/share/classes/java/nio/channels/spi/package.html Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/java/nio/channels/spi/package.html Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ * *   - * Special constructs (non-capturing) + * Special constructs (named-capturing and non-capturing) * + * (?<name>X) + * X, as a named-capturing group * (?:X) * X, as a non-capturing group * (?idmsux-idmsux)  @@ -449,6 +456,8 @@ * *

Groups and capturing

* + *
+ *
Group number
*

Capturing groups are numbered by counting their opening parentheses from * left to right. In the expression ((A)(B(C))), for example, there * are four such groups:

@@ -471,6 +480,24 @@ * subsequence may be used later in the expression, via a back reference, and * may also be retrieved from the matcher once the match operation is complete. * + *
+ *
Group name
+ *

A capturing group can also be assigned a "name", a named-capturing group, + * and then be back-referenced later by the "name". Group names are composed of + * the following characters: + * + *

    + *
  • The uppercase letters 'A' through 'Z' + * ('\u0041' through '\u005a'), + *
  • The lowercase letters 'a' through 'z' + * ('\u0061' through '\u007a'), + *
  • The digits '0' through '9' + * ('\u0030' through '\u0039'), + *
+ * + *

A named-capturing group is still numbered as described in + * Group number. + * *

The captured input associated with a group is always the subsequence * that the group most recently matched. If a group is evaluated a second time * because of quantification then its previously-captured value, if any, will @@ -479,9 +506,9 @@ * group two set to "b". All captured input is discarded at the * beginning of each match. * - *

Groups beginning with (? are pure, non-capturing groups - * that do not capture text and do not count towards the group total. - * + *

Groups beginning with (? are either pure, non-capturing groups + * that do not capture text and do not count towards the group total, or + * named-capturing group. * *

Unicode support

* @@ -795,6 +822,12 @@ transient int[] buffer; /** + * Map the "name" of the "named capturing group" to its group id + * node. + */ + transient volatile Map namedGroups; + + /** * Temporary storage used while parsing group references. */ transient GroupHead[] groupNodes; @@ -1467,6 +1500,7 @@ // Allocate all temporary objects here. buffer = new int[32]; groupNodes = new GroupHead[10]; + namedGroups = null; if (has(LITERAL)) { // Literal pattern handling @@ -1505,6 +1539,12 @@ compiled = true; } + Map namedGroups() { + if (namedGroups == null) + namedGroups = new HashMap(2); + return namedGroups; + } + /** * Used to print out a subtree of the Pattern to help with debugging. */ @@ -2156,7 +2196,22 @@ case 'h': case 'i': case 'j': + break; case 'k': + if (inclass) + break; + if (read() != '<') + throw error("\\k is not followed by '<' for named capturing group"); + String name = groupname(read()); + if (!namedGroups().containsKey(name)) + throw error("(named capturing group <"+ name+"> does not exit"); + if (create) { + if (has(CASE_INSENSITIVE)) + root = new CIBackRef(namedGroups().get(name), has(UNICODE_CASE)); + else + root = new BackRef(namedGroups().get(name)); + } + return -1; case 'l': case 'm': break; @@ -2456,6 +2511,24 @@ } /** + * Parses and returns the name of a "named capturing group", the trailing + * ">" is consumed after parsing. + */ + private String groupname(int ch) { + StringBuilder sb = new StringBuilder(); + sb.append(Character.toChars(ch)); + while (ASCII.isLower(ch=read()) || ASCII.isUpper(ch) || + ASCII.isDigit(ch)) { + sb.append(Character.toChars(ch)); + } + if (sb.length() == 0) + throw error("named capturing group has 0 length name"); + if (ch != '>') + throw error("named capturing group is missing trailing '>'"); + return sb.toString(); + } + + /** * Parses a group and returns the head node of a set of nodes that process * the group. Sometimes a double return system is used where the tail is * returned in root. @@ -2494,6 +2567,18 @@ break; case '<': // (? is already defined"); + capturingGroup = true; + head = createGroup(false); + tail = root; + namedGroups().put(name, capturingGroupCount-1); + head.next = expr(tail); + break; + } int start = cursor; head = createGroup(true); tail = root; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/AbstractFuture.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/AbstractFuture.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 + implements Future +{ + 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(); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousChannelGroupImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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(); + } 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() { + @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 0) { + task = bindToGroup(task); + try { + for (int i=0; i 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() { + 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() { + @Override + public Void run() { + delegate.run(); + return null; + } + }, acc); + } + }; + } + executeOnPooledThread(task); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousFileChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 AsynchronousServerSocketChannel setOption(SocketOption 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 getOption(SocketOption 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> defaultOptions = defaultOptions(); + + private static Set> defaultOptions() { + HashSet> set = new HashSet>(2); + set.add(StandardSocketOption.SO_RCVBUF); + set.add(StandardSocketOption.SO_REUSEADDR); + return Collections.unmodifiableSet(set); + } + } + + @Override + public final Set> 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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 Future readImpl(ByteBuffer[] dsts, + boolean isScatteringRead, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); + + @SuppressWarnings("unchecked") + private Future read(ByteBuffer[] dsts, + boolean isScatteringRead, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) + { + if (!isOpen()) { + CompletedFuture 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 result; + if (isScatteringRead) { + Long value = (shutdown) ? Long.valueOf(-1L) : Long.valueOf(0L); + result = (CompletedFuture)CompletedFuture.withResult(this, value, attachment); + } else { + int value = (shutdown) ? -1 : 0; + result = (CompletedFuture)CompletedFuture.withResult(this, value, attachment); + } + Invoker.invoke(handler, result); + return result; + } + + return readImpl(dsts, isScatteringRead, timeout, unit, attachment, handler); + } + + @Override + public final Future read(ByteBuffer dst, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler 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 Future read(ByteBuffer[] dsts, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler 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 Future writeImpl(ByteBuffer[] srcs, + boolean isGatheringWrite, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler); + + @SuppressWarnings("unchecked") + private Future write(ByteBuffer[] srcs, + boolean isGatheringWrite, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler 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 result = CompletedFuture + .withFailure(this, new ClosedChannelException(), attachment); + Invoker.invoke(handler, result); + return result; + } + + // nothing to write so complete immediately + if (!hasDataToWrite) { + CompletedFuture result; + if (isGatheringWrite) { + result = (CompletedFuture)CompletedFuture.withResult(this, 0L, attachment); + } else { + result = (CompletedFuture)CompletedFuture.withResult(this, 0, attachment); + } + Invoker.invoke(handler, result); + return result; + } + + return writeImpl(srcs, isGatheringWrite, timeout, unit, attachment, handler); + } + + @Override + public final Future write(ByteBuffer src, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) + { + ByteBuffer[] bufs = new ByteBuffer[1]; + bufs[0] = src; + return write(bufs, false, timeout, unit, attachment, handler); + } + + @Override + public final Future write(ByteBuffer[] srcs, + int offset, + int length, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler 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 AsynchronousSocketChannel setOption(SocketOption 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 getOption(SocketOption 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> defaultOptions = defaultOptions(); + + private static Set> defaultOptions() { + HashSet> set = new HashSet>(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> 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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/Cancellable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/Cancellable.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/CompletedFuture.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/CompletedFuture.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 + extends AbstractFuture +{ + 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 CompletedFuture withResult(AsynchronousChannel channel, + V result, + A attachment) + { + return new CompletedFuture(channel, result, null, attachment); + } + + @SuppressWarnings("unchecked") + static CompletedFuture 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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java --- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 DatagramChannel setOption(SocketOption 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> defaultOptions = defaultOptions(); private static Set> defaultOptions() { @@ -291,8 +295,8 @@ } @Override - public final Set> options() { - return LazyInitialization.defaultOptions; + public final Set> 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); } } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/ExtendedSocketOption.java --- a/jdk/src/share/classes/sun/nio/ch/ExtendedSocketOption.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/ch/ExtendedSocketOption.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java --- a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. - *

- * 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 lockList = new ArrayList(2); @@ -1080,207 +1039,8 @@ } } - /** - * A weak reference to a FileLock. - *

- * SharedFileLockTable uses a list of file lock references to avoid keeping the - * FileLock (and FileChannel) alive. - */ - private static class FileLockReference extends WeakReference { - private FileKey fileKey; - - FileLockReference(FileLock referent, - ReferenceQueue 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> lockMap = - new ConcurrentHashMap>(); - - // reference queue for cleared refs - private static ReferenceQueue queue = new ReferenceQueue(); - - // 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 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(2); - ArrayList 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 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 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 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 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 list = lockMap.get(fileKey); - assert list != null; - - synchronized (list) { - for (int index=0; index 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 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(); } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/FileDispatcher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/FileDispatcher.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/FileLockImpl.java --- a/jdk/src/share/classes/sun/nio/ch/FileLockImpl.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/ch/FileLockImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/FileLockTable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/FileLockTable.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. + *

+ * 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. + *

+ * SharedFileLockTable uses a list of file lock references to avoid keeping the + * FileLock (and FileChannel) alive. + */ + private static class FileLockReference extends WeakReference { + private FileKey fileKey; + + FileLockReference(FileLock referent, + ReferenceQueue 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> lockMap = + new ConcurrentHashMap>(); + + // reference queue for cleared refs + private static ReferenceQueue queue = new ReferenceQueue(); + + // 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 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(2); + List 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 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 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 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 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 list = lockMap.get(fileKey); + assert list != null; + + synchronized (list) { + for (int index=0; index 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 list = lockMap.get(fk); + if (list != null) { + synchronized (list) { + list.remove(ref); + removeKeyIfEmpty(fk, list); + } + } + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/Groupable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/Groupable.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/IOUtil.java --- a/jdk/src/share/classes/sun/nio/ch/IOUtil.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/ch/IOUtil.java Wed Jul 05 16:48:21 2017 +0200 @@ -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= 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= 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= 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= 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 myGroupAndInvokeCount = + new ThreadLocal() { + @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 void invokeUnchecked(CompletionHandler handler, + AbstractFuture 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 void invokeDirect(GroupAndInvokeCount myGroupAndInvokeCount, + CompletionHandler handler, + AbstractFuture 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 void invoke(CompletionHandler handler, + AbstractFuture 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 void invokeIndirectly(final CompletionHandler handler, + final AbstractFuture 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 void invokeIndirectly(final CompletionHandler handler, + final AbstractFuture 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(); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/MembershipKeyImpl.java --- a/jdk/src/share/classes/sun/nio/ch/MembershipKeyImpl.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/ch/MembershipKeyImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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"); diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/MembershipRegistry.java --- a/jdk/src/share/classes/sun/nio/ch/MembershipRegistry.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/ch/MembershipRegistry.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 keys; if (groups == null) { groups = new HashMap>(); @@ -100,7 +100,7 @@ * Remove a key from the registry */ void remove(MembershipKeyImpl key) { - InetAddress group = key.getGroup(); + InetAddress group = key.group(); List keys = groups.get(group); if (keys != null) { Iterator 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(); + } } } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/NativeThreadSet.java --- a/jdk/src/share/classes/sun/nio/ch/NativeThreadSet.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/ch/NativeThreadSet.java Wed Jul 05 16:48:21 2017 +0200 @@ -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) { } + } } } - } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/Net.java --- a/jdk/src/share/classes/sun/nio/ch/Net.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/ch/Net.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/OptionKey.java --- a/jdk/src/share/classes/sun/nio/ch/OptionKey.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/ch/OptionKey.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/PendingFuture.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/PendingFuture.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 + extends AbstractFuture +{ + private static final CancellationException CANCELLED = + new CancellationException(); + + private final CompletionHandler 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 handler, + A attachment, + Object context) + { + super(channel, attachment); + this.handler = handler; + this.context = context; + } + + PendingFuture(AsynchronousChannel channel, + CompletionHandler handler, + A attachment) + { + super(channel, attachment); + this.handler = handler; + } + + CompletionHandler 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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/Reflect.java --- a/jdk/src/share/classes/sun/nio/ch/Reflect.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/ch/Reflect.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java --- a/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/ch/ServerSocketChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 ServerSocketChannel setOption(SocketOption 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> defaultOptions = defaultOptions(); private static Set> defaultOptions() { @@ -166,8 +163,8 @@ } @Override - public final Set> options() { - return LazyInitialization.defaultOptions; + public final Set> supportedOptions() { + return DefaultOptionsHolder.defaultOptions; } public boolean isBound() { diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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(); + 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 Future send(ByteBuffer src, + SocketAddress target, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) + { + if (timeout < 0L) + throw new IllegalArgumentException("Negative timeout"); + if (unit == null) + throw new NullPointerException(); + + CompletedFuture 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 Future write(ByteBuffer src, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) + { + if (timeout < 0L) + throw new IllegalArgumentException("Negative timeout"); + if (unit == null) + throw new NullPointerException(); + + CompletedFuture 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() { + 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 Future receive(final ByteBuffer dst, + final long timeout, + final TimeUnit unit, + A attachment, + final CompletionHandler 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 result = CompletedFuture.withFailure(this, + new ClosedChannelException(), attachment); + Invoker.invoke(handler, result); + return result; + } + + final AccessControlContext acc = (System.getSecurityManager() == null) ? + null : AccessController.getContext(); + final PendingFuture result = + new PendingFuture(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 Future read(final ByteBuffer dst, + final long timeout, + final TimeUnit unit, + A attachment, + final CompletionHandler 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 result = CompletedFuture.withFailure(this, + new ClosedChannelException(), attachment); + Invoker.invoke(handler, result); + return result; + } + + final PendingFuture result = + new PendingFuture(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 AsynchronousDatagramChannel setOption(SocketOption name, T value) + throws IOException + { + dc.setOption(name, value); + return this; + } + + @Override + public T getOption(SocketOption name) throws IOException { + return dc.getOption(name); + } + + @Override + public Set> supportedOptions() { + return dc.supportedOptions(); + } + + @Override + public SocketAddress getRemoteAddress() throws IOException { + return dc.getRemoteAddress(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/SimpleAsynchronousFileChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + 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 Future lock(final long position, + final long size, + final boolean shared, + A attachment, + final CompletionHandler 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 result = CompletedFuture + .withFailure(this, new ClosedChannelException(), attachment); + Invoker.invokeIndirectly(handler, result, executor); + return result; + } + + final PendingFuture result = + new PendingFuture(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 Future read(final ByteBuffer dst, + final long position, + A attachment, + final CompletionHandler 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 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 result = + new PendingFuture(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 Future write(final ByteBuffer src, + final long position, + A attachment, + final CompletionHandler 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 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 result = + new PendingFuture(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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java --- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 SocketChannel setOption(SocketOption 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> defaultOptions = defaultOptions(); private static Set> defaultOptions() { @@ -212,8 +212,8 @@ } @Override - public final Set> options() { - return LazyInitialization.defaultOptions; + public final Set> supportedOptions() { + return DefaultOptionsHolder.defaultOptions; } private boolean ensureReadOpen() throws ClosedChannelException { diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/ThreadPool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/ch/ThreadPool.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(), + 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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/ch/Util.java --- a/jdk/src/share/classes/sun/nio/ch/Util.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/nio/ch/Util.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 { diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java Wed Jul 05 16:48:21 2017 +0200 @@ -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)value); + return; + } + throw new UnsupportedOperationException(); + } + + @Override + public final Map 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 result = new HashMap(2); + if (acl) + result.put(ACL_NAME, getAcl()); + if (owner) + result.put(OWNER_NAME, getOwner()); + return Collections.unmodifiableMap(result); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 set = new HashSet(); + private Map map = new HashMap(); + 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 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 readAttributes(String first, String[] rest) + throws IOException + { + AttributesBuilder builder = AttributesBuilder.create(first, rest); + addBasicAttributesToBuilder(readAttributes(), builder); + return builder.unmodifiableMap(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/AbstractFileStoreSpaceAttributeView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/AbstractFileStoreSpaceAttributeView.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 result = new HashMap(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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/AbstractFileTypeDetector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/AbstractFileTypeDetector.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/AbstractPoller.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/AbstractPoller.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 requestList; + + // set to true when shutdown + private boolean shutdown; + + protected AbstractPoller() { + this.requestList = new LinkedList(); + this.shutdown = false; + } + + /** + * Starts the poller thread + */ + public void start() { + final Runnable thisRunnable = this; + AccessController.doPrivileged(new PrivilegedAction() { + @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> 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> eventSet = new HashSet>(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> events = + (Set>)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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 readAttributes(String first, String... rest) + throws IOException + { + // names of attributes to return + List names = new ArrayList(); + + 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 result = new HashMap(); + for (String name: names) { + Object value = getAttribute(name); + if (value != null) + result.put(name, value); + } + + return result; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 OVERFLOW_EVENT = + new Event(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> events; + + protected AbstractWatchKey(AbstractWatchService watcher) { + this.watcher = watcher; + this.state = State.READY; + this.events = new ArrayList>(); + } + + 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((WatchEvent.Kind)kind, context)); + signal(); + } + } + + @Override + public final List> pollEvents() { + synchronized (this) { + List> result = events; + events = new ArrayList>(); + 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 extends WatchEvent { + private final WatchEvent.Kind kind; + private final T context; + + // synchronize on watch key to access/increment count + private int count; + + Event(WatchEvent.Kind type, T context) { + this.kind = type; + this.context = context; + this.count = 1; + } + + @Override + public WatchEvent.Kind kind() { + return kind; + } + + @Override + public T context() { + return context; + } + + @Override + public int count() { + return count; + } + + // for repeated events + void increment() { + count++; + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/AbstractWatchService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/AbstractWatchService.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 pendingKeys = + new LinkedBlockingDeque(); + + // 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/BasicFileAttributesHolder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/BasicFileAttributesHolder.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,46 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, 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.BasicFileAttributes; + +/** + * Implemented by objects that may hold or cache the attributes of a file. + */ + +public interface BasicFileAttributesHolder { + /** + * Returns cached attributes (may be null). If file is a symbolic link then + * the attributes are the link attributes and not the final target of the + * file. + */ + BasicFileAttributes get(); + + /** + * Invalidates cached attributes + */ + void invalidate(); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/Cancellable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/Cancellable.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 readAttributes(String first, String[] rest) throws IOException { + Map result = new HashMap(); + 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); + } + } + } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/Globs.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/Globs.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/MimeType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/MimeType.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/NativeBuffer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/NativeBuffer.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/NativeBuffers.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/NativeBuffers.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 threadLocal = + new ThreadLocal(); + + /** + * 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= 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= (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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/PollingWatchService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/PollingWatchService.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 map = + new HashMap(); + + // 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> eventSet = + new HashSet>(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() { + @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> 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 entry: map.entrySet()) { + PollingWatchKey watchKey = entry.getValue(); + watchKey.disable(); + watchKey.invalidate(); + } + map.clear(); + } + AccessController.doPrivileged(new PrivilegedAction() { + @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> 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 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(); + + // get the initial entries in the directory + DirectoryStream 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> 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 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> i = entries.entrySet().iterator(); + while (i.hasNext()) { + Map.Entry 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); + } + } + } + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/nio/fs/Reflect.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/nio/fs/Reflect.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + @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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/krb5/Realm.java --- a/jdk/src/share/classes/sun/security/krb5/Realm.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/security/krb5/Realm.java Wed Jul 05 16:48:21 2017 +0200 @@ -39,7 +39,6 @@ import sun.security.krb5.internal.Krb5; import sun.security.util.*; import java.io.IOException; -import java.io.OutputStream; import java.util.StringTokenizer; import java.util.Vector; import java.util.Stack; @@ -364,7 +363,6 @@ } String tempTarget = null, tempRealm = null; - StringTokenizer strTok = null; Stack iStack = new Stack (); /* @@ -382,7 +380,7 @@ tempTarget = sRealm; } - do { + out: do { if (DEBUG) { count++; System.out.println(">>> Realm parseCapaths: loop " + @@ -400,15 +398,21 @@ /* * We have one or more space-separated intermediary realms. - * Stack them. + * Stack them. A null is always added between intermedies of + * different targets. When this null is popped, it means none + * of the intermedies for this target is useful (because of + * infinite loop), the target is then removed from the partial + * tempList, and the next possible intermediary is tried. */ - strTok = new StringTokenizer(intermediaries, " "); - while (strTok.hasMoreTokens()) + iStack.push(null); + String[] ints = intermediaries.split("\\s+"); + for (int i = ints.length-1; i>=0; i--) { - tempRealm = strTok.nextToken(); - if (!tempRealm.equals(PrincipalName. - REALM_COMPONENT_SEPARATOR_STR) && - !iStack.contains(tempRealm)) { + tempRealm = ints[i]; + if (tempRealm.equals(PrincipalName.REALM_COMPONENT_SEPARATOR_STR)) { + break out; + } + if (!tempList.contains(tempRealm)) { iStack.push(tempRealm); if (DEBUG) { System.out.println(">>> Realm parseCapaths: loop " + @@ -418,16 +422,18 @@ } } else if (DEBUG) { System.out.println(">>> Realm parseCapaths: loop " + - count + ": ignoring realm: [" + tempRealm + "]"); } } - } else if (DEBUG) { - System.out.println(">>> Realm parseCapaths: loop " + - count + - ": no intermediaries"); + } else { + if (DEBUG) { + System.out.println(">>> Realm parseCapaths: loop " + + count + + ": no intermediaries"); + } + break; } /* @@ -435,7 +441,12 @@ */ try { - tempTarget = iStack.pop(); + while ((tempTarget = iStack.pop()) == null) { + tempList.removeElementAt(tempList.size()-1); + if (DEBUG) { + System.out.println(">>> Realm parseCapaths: backtrack, remove tail"); + } + } } catch (EmptyStackException exc) { tempTarget = null; } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/provider/X509Factory.java --- a/jdk/src/share/classes/sun/security/provider/X509Factory.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/security/provider/X509Factory.java Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -638,10 +638,15 @@ // First read all of the data that is found between // the "-----BEGIN" and "-----END" boundaries into a buffer. String temp; - if ((temp=readLine(br))==null || !temp.startsWith("-----BEGIN")) { - throw new IOException("Unsupported encoding"); - } else { + while (true) { + temp=readLine(br); + if (temp == null) { + throw new IOException("Unsupported encoding"); + } len += temp.length(); + if (temp.startsWith("-----BEGIN")) { + break; + } } StringBuffer strBuf = new StringBuffer(); while ((temp=readLine(br))!=null && !temp.startsWith("-----END")) { @@ -683,22 +688,11 @@ * Determines if input is binary or Base64 encoded. */ private boolean isBase64(InputStream is) throws IOException { - if (is.available() >= 10) { - is.mark(10); + if (is.available() >= 1) { + is.mark(1); int c1 = is.read(); - int c2 = is.read(); - int c3 = is.read(); - int c4 = is.read(); - int c5 = is.read(); - int c6 = is.read(); - int c7 = is.read(); - int c8 = is.read(); - int c9 = is.read(); - int c10 = is.read(); is.reset(); - if (c1 == '-' && c2 == '-' && c3 == '-' && c4 == '-' - && c5 == '-' && c6 == 'B' && c7 == 'E' && c8 == 'G' - && c9 == 'I' && c10 == 'N') { + if (c1 != DerValue.tag_Sequence) { return true; } else { return false; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/ssl/AppInputStream.java --- a/jdk/src/share/classes/sun/security/ssl/AppInputStream.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/security/ssl/AppInputStream.java Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,6 +81,14 @@ */ public synchronized int read(byte b[], int off, int len) throws IOException { + if (b == null) { + throw new NullPointerException(); + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return 0; + } + if (c.checkEOF()) { return -1; } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/ssl/AppOutputStream.java --- a/jdk/src/share/classes/sun/security/ssl/AppOutputStream.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/security/ssl/AppOutputStream.java Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,18 +58,25 @@ */ synchronized public void write(byte b[], int off, int len) throws IOException { + if (b == null) { + throw new NullPointerException(); + } else if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return; + } + // check if the Socket is invalid (error or closed) c.checkWrite(); - // + // Always flush at the end of each application level record. // This lets application synchronize read and write streams // however they like; if we buffered here, they couldn't. - // - // NOTE: *must* call c.writeRecord() even for len == 0 try { do { int howmuch = Math.min(len, r.availableDataBytes()); + // NOTE: *must* call c.writeRecord() even for howmuch == 0 if (howmuch > 0) { r.write(b, off, howmuch); off += howmuch; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/ssl/ByteBufferInputStream.java --- a/jdk/src/share/classes/sun/security/ssl/ByteBufferInputStream.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/security/ssl/ByteBufferInputStream.java Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 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 @@ -89,8 +89,7 @@ if (b == null) { throw new NullPointerException(); - } else if ((off < 0) || (off > b.length) || (len < 0) || - ((off + len) > b.length) || ((off + len) < 0)) { + } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/ssl/SSLSessionContextImpl.java --- a/jdk/src/share/classes/sun/security/ssl/SSLSessionContextImpl.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/security/ssl/SSLSessionContextImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,88 +41,112 @@ import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; -import sun.misc.Cache; +import sun.security.util.Cache; -final class SSLSessionContextImpl implements SSLSessionContext -{ - private Cache sessionCache = new Cache(); - private Cache sessionHostPortCache = new Cache(); - private int cacheLimit; - private long timeoutMillis; +final class SSLSessionContextImpl implements SSLSessionContext { + private Cache sessionCache; // session cache, session id as key + private Cache sessionHostPortCache; // session cache, "host:port" as key + private int cacheLimit; // the max cache size + private int timeout; // timeout in seconds + private static final Debug debug = Debug.getInstance("ssl"); - // file private - SSLSessionContextImpl() - { - cacheLimit = getCacheLimit(); - timeoutMillis = 86400000; // default, 24 hours + // package private + SSLSessionContextImpl() { + cacheLimit = getDefaultCacheLimit(); // default cache size + timeout = 86400; // default, 24 hours + + // use soft reference + sessionCache = Cache.newSoftMemoryCache(cacheLimit, timeout); + sessionHostPortCache = Cache.newSoftMemoryCache(cacheLimit, timeout); } /** - * Returns the SSL session object associated with the - * specific session ID passed. + * Returns the SSLSession bound to the specified session id. */ - public SSLSession getSession(byte[] id) - { - SSLSession sess = (SSLSession) sessionCache.get( - new SessionId(id)); - return checkTimeValidity(sess); + public SSLSession getSession(byte[] sessionId) { + if (sessionId == null) { + throw new NullPointerException("session id cannot be null"); + } + + SSLSessionImpl sess = + (SSLSessionImpl)sessionCache.get(new SessionId(sessionId)); + if (!isTimedout(sess)) { + return sess; + } + + return null; } /** * Returns an enumeration of the active SSL sessions. */ public Enumeration getIds() { - Vector v = new Vector(sessionCache.size()); - SessionId sessId; + SessionCacheVisitor scVisitor = new SessionCacheVisitor(); + sessionCache.accept(scVisitor); - for (Enumeration e = sessionCache.keys(); e.hasMoreElements(); ) { - sessId = (SessionId) e.nextElement(); - if (!isTimedout((SSLSession)sessionCache.get(sessId))) - v.addElement(sessId.getId()); - } - return v.elements(); + return scVisitor.getSessionIds(); } + /** + * Sets the timeout limit for cached SSLSession objects + * + * Note that after reset the timeout, the cached session before + * should be timed within the shorter one of the old timeout and the + * new timeout. + */ public void setSessionTimeout(int seconds) throws IllegalArgumentException { - if (seconds < 0) + if (seconds < 0) { throw new IllegalArgumentException(); - timeoutMillis = seconds * 1000L; + } + + if (timeout != seconds) { + sessionCache.setTimeout(seconds); + sessionHostPortCache.setTimeout(seconds); + timeout = seconds; + } } + /** + * Gets the timeout limit for cached SSLSession objects + */ public int getSessionTimeout() { - return (int) (timeoutMillis / 1000); + return timeout; } + /** + * Sets the size of the cache used for storing + * SSLSession objects. + */ public void setSessionCacheSize(int size) throws IllegalArgumentException { if (size < 0) throw new IllegalArgumentException(); - cacheLimit = size; - /** - * If cache size limit is reduced, when the cache is full to its - * previous limit, trim the cache before its contents - * are used. - */ - if ((cacheLimit != 0) && (sessionCache.size() > cacheLimit)) - adjustCacheSizeTo(cacheLimit); + if (cacheLimit != size) { + sessionCache.setCapacity(size); + sessionHostPortCache.setCapacity(size); + cacheLimit = size; + } } + /** + * Gets the size of the cache used for storing + * SSLSession objects. + */ public int getSessionCacheSize() { return cacheLimit; } + + // package-private method, used ONLY by ServerHandshaker SSLSessionImpl get(byte[] id) { - return (SSLSessionImpl) getSession(id); + return (SSLSessionImpl)getSession(id); } - /** - * Returns the SSL session object associated with the - * specific host name and port number passed. - */ + // package-private method, used ONLY by ClientHandshaker SSLSessionImpl get(String hostname, int port) { /* * If no session caching info is available, we won't @@ -131,96 +155,51 @@ if (hostname == null && port == -1) { return null; } - SSLSession sess = (SSLSessionImpl) sessionHostPortCache - .get(getKey(hostname, port)); - return (SSLSessionImpl) checkTimeValidity(sess); + + SSLSessionImpl sess = + (SSLSessionImpl)sessionHostPortCache.get(getKey(hostname, port)); + if (!isTimedout(sess)) { + return sess; + } + + return null; } private String getKey(String hostname, int port) { - return (hostname + ":" + String.valueOf(port)) - .toLowerCase(); + return (hostname + ":" + String.valueOf(port)).toLowerCase(); } + // cache a SSLSession + // + // In SunJSSE implementation, a session is created while getting a + // client hello or a server hello message, and cached while the + // handshaking finished. + // Here we time the session from the time it cached instead of the + // time it created, which is a little longer than the expected. So + // please do check isTimedout() while getting entry from the cache. void put(SSLSessionImpl s) { - // make space for the new session to be added - if ((cacheLimit != 0) && (sessionCache.size() >= cacheLimit)) - adjustCacheSizeTo(cacheLimit - 1); - - /* - * Can always add the session id. - */ sessionCache.put(s.getSessionId(), s); - /* - * If no hostname/port info is available, don't add this one. - */ + // If no hostname/port info is available, don't add this one. if ((s.getPeerHost() != null) && (s.getPeerPort() != -1)) { sessionHostPortCache.put( getKey(s.getPeerHost(), s.getPeerPort()), s); } + s.setContext(this); } - private void adjustCacheSizeTo(int targetSize) { - - int cacheSize = sessionCache.size(); - - if (targetSize < 0) - return; - - while (cacheSize > targetSize) { - SSLSessionImpl lru = null; - SSLSessionImpl s = null; - Enumeration e; - - if (debug != null && Debug.isOn("sessioncache")) { - System.out.println("exceeded cache limit of " + cacheLimit); - } - - /* - * Count the number of elements in the cache. The size() method - * does not reflect the cache entries that are no longer available, - * i.e entries that are garbage collected (the cache entries are - * held using soft references and are garbage collected when not - * in use). - */ - int count; - for (count = 0, e = sessionCache.elements(); - e.hasMoreElements(); count++) { - try { - s = (SSLSessionImpl)e.nextElement(); - } catch (NoSuchElementException nsee) { - break; - } - if (isTimedout(s)) { - lru = s; - break; - } else if ((lru == null) || (s.getLastAccessedTime() - < lru.getLastAccessedTime())) { - lru = s; - } - } - if ((lru != null) && (count > targetSize)) { - if (debug != null && Debug.isOn("sessioncache")) { - System.out.println("uncaching " + lru); - } - lru.invalidate(); - count--; // element removed from the cache - } - cacheSize = count; + // package-private method, remove a cached SSLSession + void remove(SessionId key) { + SSLSessionImpl s = (SSLSessionImpl)sessionCache.get(key); + if (s != null) { + sessionCache.remove(key); + sessionHostPortCache.remove( + getKey(s.getPeerHost(), s.getPeerPort())); } } - // file private - void remove(SessionId key) - { - SSLSessionImpl s = (SSLSessionImpl) sessionCache.get(key); - sessionCache.remove(key); - sessionHostPortCache.remove(getKey(s.getPeerHost(), - s.getPeerPort())); - } - - private int getCacheLimit() { + private int getDefaultCacheLimit() { int cacheLimit = 0; try { String s = java.security.AccessController.doPrivileged( @@ -237,21 +216,40 @@ return (cacheLimit > 0) ? cacheLimit : 0; } - SSLSession checkTimeValidity(SSLSession sess) { - if (isTimedout(sess)) { + boolean isTimedout(SSLSession sess) { + if (timeout == 0) { + return false; + } + + if ((sess != null) && ((sess.getCreationTime() + timeout * 1000L) + <= (System.currentTimeMillis()))) { sess.invalidate(); - return null; - } else - return sess; + return true; + } + + return false; } - boolean isTimedout(SSLSession sess) { - if (timeoutMillis == 0) - return false; - if ((sess != null) && - ((sess.getCreationTime() + timeoutMillis) - <= (System.currentTimeMillis()))) - return true; - return false; + final class SessionCacheVisitor + implements sun.security.util.Cache.CacheVisitor { + Vector ids = null; + + // public void visit(java.util.Map map) {} + public void visit(java.util.Map map) { + ids = new Vector(map.size()); + + for (Object key : map.keySet()) { + SSLSessionImpl value = (SSLSessionImpl)map.get(key); + if (!isTimedout(value)) { + ids.addElement(((SessionId)key).getId()); + } + } + } + + public Enumeration getSessionIds() { + return ids != null ? ids.elements() : + new Vector().elements(); + } } + } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java --- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -368,7 +368,9 @@ super(); this.host = host; init(context, false); - SocketAddress socketAddress = new InetSocketAddress(host, port); + SocketAddress socketAddress = + host != null ? new InetSocketAddress(host, port) : + new InetSocketAddress(InetAddress.getByName(null), port); connect(socketAddress, 0); } @@ -409,7 +411,9 @@ this.host = host; init(context, false); bind(new InetSocketAddress(localAddr, localPort)); - SocketAddress socketAddress = new InetSocketAddress(host, port); + SocketAddress socketAddress = + host != null ? new InetSocketAddress(host, port) : + new InetSocketAddress(InetAddress.getByName(null), port); connect(socketAddress, 0); } @@ -1829,7 +1833,8 @@ } synchronized String getHost() { - if (host == null) { + // Note that the host may be null or empty for localhost. + if (host == null || host.length() == 0) { host = getInetAddress().getHostName(); } return host; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/tools/KeyTool.java --- a/jdk/src/share/classes/sun/security/tools/KeyTool.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 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 @@ -69,6 +69,10 @@ import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; +import sun.misc.BASE64Decoder; +import sun.security.pkcs.PKCS10Attribute; +import sun.security.pkcs.PKCS9Attribute; +import sun.security.util.DerValue; import sun.security.x509.*; import static java.security.KeyStore.*; @@ -85,7 +89,6 @@ * * @since 1.2 */ - public final class KeyTool { private boolean debug = false; @@ -100,6 +103,8 @@ private String dname = null; private String dest = null; private String filename = null; + private String infilename = null; + private String outfilename = null; private String srcksfname = null; // User-specified providers are added before any command is called. @@ -117,7 +122,6 @@ private char[] storePassNew = null; private char[] keyPass = null; private char[] keyPassNew = null; - private char[] oldPass = null; private char[] newPass = null; private char[] destKeyPass = null; private char[] srckeyPass = null; @@ -140,6 +144,8 @@ private Set passwords = new HashSet (); private String startDate = null; + private List v3ext = new ArrayList (); + private static final int CERTREQ = 1; private static final int CHANGEALIAS = 2; private static final int DELETE = 3; @@ -156,6 +162,8 @@ private static final int PRINTCERT = 13; private static final int SELFCERT = 14; private static final int STOREPASSWD = 15; + private static final int GENCERT = 16; + private static final int PRINTCERTREQ = 17; private static final Class[] PARAM_STRING = { String.class }; @@ -184,7 +192,9 @@ private void run(String[] args, PrintStream out) throws Exception { try { parseArgs(args); - doCommands(out); + if (command != -1) { + doCommands(out); + } } catch (Exception e) { System.out.println(rb.getString("keytool error: ") + e); if (verbose) { @@ -214,7 +224,10 @@ */ void parseArgs(String[] args) { - if (args.length == 0) usage(); + if (args.length == 0) { + usage(); + return; + } int i=0; @@ -260,6 +273,10 @@ command = IMPORTKEYSTORE; } else if (collator.compare(flags, "-genseckey") == 0) { command = GENSECKEY; + } else if (collator.compare(flags, "-gencert") == 0) { + command = GENCERT; + } else if (collator.compare(flags, "-printcertreq") == 0) { + command = PRINTCERTREQ; } /* @@ -337,9 +354,18 @@ } else if (collator.compare(flags, "-validity") == 0) { if (++i == args.length) errorNeedArgument(flags); validity = Long.parseLong(args[i]); + } else if (collator.compare(flags, "-ext") == 0) { + if (++i == args.length) errorNeedArgument(flags); + v3ext.add(args[i]); } else if (collator.compare(flags, "-file") == 0) { if (++i == args.length) errorNeedArgument(flags); filename = args[i]; + } else if (collator.compare(flags, "-infile") == 0) { + if (++i == args.length) errorNeedArgument(flags); + infilename = args[i]; + } else if (collator.compare(flags, "-outfile") == 0) { + if (++i == args.length) errorNeedArgument(flags); + outfilename = args[i]; } else if (collator.compare(flags, "-sslserver") == 0) { if (++i == args.length) errorNeedArgument(flags); sslserver = args[i]; @@ -364,7 +390,7 @@ } } providers.add( - new Pair(providerClass, providerArg)); + Pair.of(providerClass, providerArg)); } /* @@ -404,6 +430,10 @@ } } + boolean isKeyStoreRelated(int cmd) { + return cmd != PRINTCERT && cmd != PRINTCERTREQ; + } + /** * Execute the commands. */ @@ -568,7 +598,7 @@ // the default, which is located in $HOME/.keystore. // If the command is "genkey", "identitydb", "import", or "printcert", // it is OK not to have a keystore. - if (command != PRINTCERT) { + if (isKeyStoreRelated(command)) { if (ksfname == null) { ksfname = System.getProperty("user.home") + File.separator + ".keystore"; @@ -721,7 +751,7 @@ } } else if (!protectedPath && !KeyStoreUtil.isWindowsKeyStore(storetype) - && !(command == PRINTCERT)) { + && isKeyStoreRelated(command)) { // here we have EXPORTCERT and LIST (info valid until STOREPASSWD) System.err.print(rb.getString("Enter keystore password: ")); System.err.flush(); @@ -763,7 +793,7 @@ // Create a certificate factory if (command == PRINTCERT || command == IMPORTCERT - || command == IDENTITYDB) { + || command == IDENTITYDB) { cf = CertificateFactory.getInstance("X509"); } @@ -930,6 +960,41 @@ storePassNew = getNewPasswd("keystore password", storePass); } kssave = true; + } else if (command == GENCERT) { + if (alias == null) { + alias = keyAlias; + } + InputStream inStream = System.in; + if (infilename != null) { + inStream = new FileInputStream(infilename); + } + PrintStream ps = null; + if (outfilename != null) { + ps = new PrintStream(new FileOutputStream(outfilename)); + out = ps; + } + try { + doGenCert(alias, sigAlgName, inStream, out); + } finally { + if (inStream != System.in) { + inStream.close(); + } + if (ps != null) { + ps.close(); + } + } + } else if (command == PRINTCERTREQ) { + InputStream inStream = System.in; + if (filename != null) { + inStream = new FileInputStream(filename); + } + try { + doPrintCertReq(inStream, out); + } finally { + if (inStream != System.in) { + inStream.close(); + } + } } // If we need to save the keystore, do so. @@ -962,6 +1027,91 @@ } /** + * Generate a certificate: Read PKCS10 request from in, and print + * certificate to out. Use alias as CA, sigAlgName as the signature + * type. + */ + private void doGenCert(String alias, String sigAlgName, InputStream in, PrintStream out) + throws Exception { + + + Certificate signerCert = keyStore.getCertificate(alias); + byte[] encoded = signerCert.getEncoded(); + X509CertImpl signerCertImpl = new X509CertImpl(encoded); + X509CertInfo signerCertInfo = (X509CertInfo)signerCertImpl.get( + X509CertImpl.NAME + "." + X509CertImpl.INFO); + X500Name owner = (X500Name)signerCertInfo.get(X509CertInfo.SUBJECT + "." + + CertificateSubjectName.DN_NAME); + + Date firstDate = getStartDate(startDate); + Date lastDate = new Date(); + lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L); + CertificateValidity interval = new CertificateValidity(firstDate, + lastDate); + + PrivateKey privateKey = (PrivateKey)recoverKey(alias, storePass, keyPass).fst; + if (sigAlgName == null) { + sigAlgName = getCompatibleSigAlgName(privateKey.getAlgorithm()); + } + Signature signature = Signature.getInstance(sigAlgName); + signature.initSign(privateKey); + + X500Signer signer = new X500Signer(signature, owner); + + X509CertInfo info = new X509CertInfo(); + info.set(X509CertInfo.VALIDITY, interval); + info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber + ((int)(firstDate.getTime()/1000))); + info.set(X509CertInfo.VERSION, + new CertificateVersion(CertificateVersion.V3)); + info.set(X509CertInfo.ALGORITHM_ID, + new CertificateAlgorithmId(signer.getAlgorithmId())); + info.set(X509CertInfo.ISSUER, + new CertificateIssuerName(signer.getSigner())); + + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + boolean canRead = false; + StringBuffer sb = new StringBuffer(); + while (true) { + String s = reader.readLine(); + if (s == null) break; + // OpenSSL does not use NEW + //if (s.startsWith("-----BEGIN NEW CERTIFICATE REQUEST-----")) { + if (s.startsWith("-----BEGIN") && s.indexOf("REQUEST") >= 0) { + canRead = true; + //} else if (s.startsWith("-----END NEW CERTIFICATE REQUEST-----")) { + } else if (s.startsWith("-----END") && s.indexOf("REQUEST") >= 0) { + break; + } else if (canRead) { + sb.append(s); + } + } + byte[] rawReq = new BASE64Decoder().decodeBuffer(new String(sb)); + PKCS10 req = new PKCS10(rawReq); + + info.set(X509CertInfo.KEY, new CertificateX509Key(req.getSubjectPublicKeyInfo())); + info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(req.getSubjectName())); + CertificateExtensions reqex = null; + Iterator attrs = req.getAttributes().getAttributes().iterator(); + while (attrs.hasNext()) { + PKCS10Attribute attr = attrs.next(); + if (attr.getAttributeId().equals(PKCS9Attribute.EXTENSION_REQUEST_OID)) { + reqex = (CertificateExtensions)attr.getAttributeValue(); + } + } + CertificateExtensions ext = createV3Extensions( + reqex, + null, + v3ext, + req.getSubjectPublicKeyInfo(), + signerCert.getPublicKey()); + info.set(X509CertInfo.EXTENSIONS, ext); + X509CertImpl cert = new X509CertImpl(info); + cert.sign(privateKey, sigAlgName); + dumpCert(cert, out); + } + + /** * Creates a PKCS#10 cert signing request, corresponding to the * keys (and name) associated with a given alias. */ @@ -972,10 +1122,10 @@ alias = keyAlias; } - Object[] objs = recoverKey(alias, storePass, keyPass); - PrivateKey privKey = (PrivateKey)objs[0]; + Pair objs = recoverKey(alias, storePass, keyPass); + PrivateKey privKey = (PrivateKey)objs.fst; if (keyPass == null) { - keyPass = (char[])objs[1]; + keyPass = objs.snd; } Certificate cert = keyStore.getCertificate(alias); @@ -986,21 +1136,14 @@ throw new Exception(form.format(source)); } PKCS10 request = new PKCS10(cert.getPublicKey()); + CertificateExtensions ext = createV3Extensions(null, null, v3ext, cert.getPublicKey(), null); + // Attribute name is not significant + request.getAttributes().setAttribute(X509CertInfo.EXTENSIONS, + new PKCS10Attribute(PKCS9Attribute.EXTENSION_REQUEST_OID, ext)); // Construct an X500Signer object, so that we can sign the request if (sigAlgName == null) { - // If no signature algorithm was specified at the command line, - // we choose one that is compatible with the selected private key - String keyAlgName = privKey.getAlgorithm(); - if ("DSA".equalsIgnoreCase(keyAlgName) - || "DSS".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1WithDSA"; - } else if ("RSA".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1WithRSA"; - } else { - throw new Exception(rb.getString - ("Cannot derive signature algorithm")); - } + sigAlgName = getCompatibleSigAlgName(privKey.getAlgorithm()); } Signature signature = Signature.getInstance(sigAlgName); @@ -1153,6 +1296,23 @@ } /** + * If no signature algorithm was specified at the command line, + * we choose one that is compatible with the selected private key + */ + private static String getCompatibleSigAlgName(String keyAlgName) + throws Exception { + if ("DSA".equalsIgnoreCase(keyAlgName)) { + return "SHA1WithDSA"; + } else if ("RSA".equalsIgnoreCase(keyAlgName)) { + return "SHA1WithRSA"; + } else if ("EC".equalsIgnoreCase(keyAlgName)) { + return "SHA1withECDSA"; + } else { + throw new Exception(rb.getString + ("Cannot derive signature algorithm")); + } + } + /** * Creates a new key pair and self-signed certificate. */ private void doGenKeyPair(String alias, String dname, String keyAlgName, @@ -1179,16 +1339,7 @@ } if (sigAlgName == null) { - if ("DSA".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1WithDSA"; - } else if ("RSA".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1WithRSA"; - } else if ("EC".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1withECDSA"; - } else { - throw new Exception(rb.getString - ("Cannot derive signature algorithm")); - } + sigAlgName = getCompatibleSigAlgName(keyAlgName); } CertAndKeyGen keypair = new CertAndKeyGen(keyAlgName, sigAlgName, providerName); @@ -1225,6 +1376,9 @@ keyPass = promptForKeyPass(alias, null, storePass); } keyStore.setKeyEntry(alias, privKey, keyPass, chain); + + // resign so that -ext are applied. + doSelfCert(alias, null, sigAlgName); } /** @@ -1247,9 +1401,9 @@ throw new Exception(form.format(source)); } - Object[] objs = recoverEntry(keyStore, orig, storePass, keyPass); - Entry entry = (Entry)objs[0]; - keyPass = (char[])objs[1]; + Pair objs = recoverEntry(keyStore, orig, storePass, keyPass); + Entry entry = objs.fst; + keyPass = objs.snd; PasswordProtection pp = null; @@ -1275,10 +1429,10 @@ if (alias == null) { alias = keyAlias; } - Object[] objs = recoverKey(alias, storePass, keyPass); - Key privKey = (Key)objs[0]; + Pair objs = recoverKey(alias, storePass, keyPass); + Key privKey = objs.fst; if (keyPass == null) { - keyPass = (char[])objs[1]; + keyPass = objs.snd; } if (keyPassNew == null) { @@ -1629,8 +1783,8 @@ } } - Object[] objs = recoverEntry(srckeystore, alias, srcstorePass, srckeyPass); - Entry entry = (Entry)objs[0]; + Pair objs = recoverEntry(srckeystore, alias, srcstorePass, srckeyPass); + Entry entry = objs.fst; PasswordProtection pp = null; @@ -1640,8 +1794,8 @@ // so always try to protect with destKeyPass. if (destKeyPass != null) { pp = new PasswordProtection(destKeyPass); - } else if (objs[1] != null) { - pp = new PasswordProtection((char[])objs[1]); + } else if (objs.snd != null) { + pp = new PasswordProtection(objs.snd); } try { @@ -1726,9 +1880,50 @@ } } + private void doPrintCertReq(InputStream in, PrintStream out) + throws Exception { + + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + StringBuffer sb = new StringBuffer(); + boolean started = false; + while (true) { + String s = reader.readLine(); + if (s == null) break; + if (!started) { + if (s.startsWith("-----")) { + started = true; + } + } else { + if (s.startsWith("-----")) { + break; + } + sb.append(s); + } + } + PKCS10 req = new PKCS10(new BASE64Decoder().decodeBuffer(new String(sb))); + + PublicKey pkey = req.getSubjectPublicKeyInfo(); + out.printf(rb.getString("PKCS #10 Certificate Request (Version 1.0)\n" + + "Subject: %s\nPublic Key: %s format %s key\n"), + req.getSubjectName(), pkey.getFormat(), pkey.getAlgorithm()); + for (PKCS10Attribute attr: req.getAttributes().getAttributes()) { + ObjectIdentifier oid = attr.getAttributeId(); + if (oid.equals(PKCS9Attribute.EXTENSION_REQUEST_OID)) { + CertificateExtensions exts = (CertificateExtensions)attr.getAttributeValue(); + printExtensions(rb.getString("Extension Request:"), exts, out); + } else { + out.println(attr.getAttributeId()); + out.println(attr.getAttributeValue()); + } + } + if (debug) { + out.println(req); // Just to see more, say, public key length... + } + } + /** * Reads a certificate (or certificate chain) and prints its contents in - * a human readbable format. + * a human readable format. */ private void printCertFromStream(InputStream in, PrintStream out) throws Exception @@ -1840,7 +2035,18 @@ inStream = new FileInputStream(filename); } try { - printCertFromStream(inStream, out); + // Read the full stream before feeding to X509Factory, + // otherwise, keytool -gencert | keytool -printcert + // might not work properly, since -gencert is slow + // and there's no data in the pipe at the beginning. + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + byte[] b = new byte[4096]; + while (true) { + int len = inStream.read(b); + if (len < 0) break; + bout.write(b, 0, len); + } + printCertFromStream(new ByteArrayInputStream(bout.toByteArray()), out); } finally { if (inStream != System.in) { inStream.close(); @@ -1859,27 +2065,14 @@ alias = keyAlias; } - Object[] objs = recoverKey(alias, storePass, keyPass); - PrivateKey privKey = (PrivateKey)objs[0]; + Pair objs = recoverKey(alias, storePass, keyPass); + PrivateKey privKey = (PrivateKey)objs.fst; if (keyPass == null) - keyPass = (char[])objs[1]; + keyPass = objs.snd; // Determine the signature algorithm if (sigAlgName == null) { - // If no signature algorithm was specified at the command line, - // we choose one that is compatible with the selected private key - String keyAlgName = privKey.getAlgorithm(); - if ("DSA".equalsIgnoreCase(keyAlgName) - || "DSS".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1WithDSA"; - } else if ("RSA".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1WithRSA"; - } else if ("EC".equalsIgnoreCase(keyAlgName)) { - sigAlgName = "SHA1withECDSA"; - } else { - throw new Exception - (rb.getString("Cannot derive signature algorithm")); - } + sigAlgName = getCompatibleSigAlgName(privKey.getAlgorithm()); } // Get the old certificate @@ -1943,11 +2136,16 @@ certInfo.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, sigAlgid); - // first upgrade to version 3 - certInfo.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3)); + CertificateExtensions ext = createV3Extensions( + null, + (CertificateExtensions)certInfo.get(X509CertInfo.EXTENSIONS), + v3ext, + oldCert.getPublicKey(), + null); + certInfo.set(X509CertInfo.EXTENSIONS, ext); // Sign the new certificate newCert = new X509CertImpl(certInfo); newCert.sign(privKey, sigAlgName); @@ -1985,10 +2183,10 @@ alias = keyAlias; } - Object[] objs = recoverKey(alias, storePass, keyPass); - PrivateKey privKey = (PrivateKey)objs[0]; + Pair objs = recoverKey(alias, storePass, keyPass); + PrivateKey privKey = (PrivateKey)objs.fst; if (keyPass == null) { - keyPass = (char[])objs[1]; + keyPass = objs.snd; } Certificate userCert = keyStore.getCertificate(alias); @@ -2290,36 +2488,40 @@ }; out.println(form.format(source)); - int extnum = 0; if (cert instanceof X509CertImpl) { X509CertImpl impl = (X509CertImpl)cert; - if (cert.getCriticalExtensionOIDs() != null) { - for (String extOID : cert.getCriticalExtensionOIDs()) { - if (extnum == 0) { - out.println(); - out.println(rb.getString("Extensions: ")); - out.println(); - } - out.println("#"+(++extnum)+": "+ - impl.getExtension(new ObjectIdentifier(extOID))); + X509CertInfo certInfo = (X509CertInfo)impl.get(X509CertImpl.NAME + + "." + + X509CertImpl.INFO); + CertificateExtensions exts = (CertificateExtensions) + certInfo.get(X509CertInfo.EXTENSIONS); + printExtensions(rb.getString("Extensions: "), exts, out); + } + } + + private static void printExtensions(String title, CertificateExtensions exts, PrintStream out) + throws Exception { + int extnum = 0; + Iterator i1 = exts.getAllExtensions().iterator(); + Iterator i2 = exts.getUnparseableExtensions().values().iterator(); + while (i1.hasNext() || i2.hasNext()) { + Extension ext = i1.hasNext()?i1.next():i2.next(); + if (extnum == 0) { + out.println(); + out.println(title); + out.println(); + } + out.print("#"+(++extnum)+": "+ ext); + if (ext.getClass() == Extension.class) { + byte[] v = ext.getExtensionValue(); + if (v.length == 0) { + out.println(rb.getString("(Empty value)")); + } else { + new sun.misc.HexDumpEncoder().encode(ext.getExtensionValue(), out); + out.println(); } } - if (cert.getNonCriticalExtensionOIDs() != null) { - for (String extOID : cert.getNonCriticalExtensionOIDs()) { - if (extnum == 0) { - out.println(); - out.println(rb.getString("Extensions: ")); - out.println(); - } - Extension ext = impl.getExtension(new ObjectIdentifier(extOID)); - if (ext != null) { - out.println("#"+(++extnum)+": "+ ext); - } else { - out.println("#"+(++extnum)+": "+ - impl.getUnparseableExtension(new ObjectIdentifier(extOID))); - } - } - } + out.println(); } } @@ -2470,7 +2672,7 @@ * recovered private key, and the 2nd element is the password used to * recover it. */ - private Object[] recoverKey(String alias, char[] storePass, + private Pair recoverKey(String alias, char[] storePass, char[] keyPass) throws Exception { @@ -2510,7 +2712,7 @@ key = keyStore.getKey(alias, keyPass); } - return new Object[] {key, keyPass}; + return Pair.of(key, keyPass); } /** @@ -2520,7 +2722,7 @@ * recovered entry, and the 2nd element is the password used to * recover it (null if no password). */ - private Object[] recoverEntry(KeyStore ks, + private Pair recoverEntry(KeyStore ks, String alias, char[] pstore, char[] pkey) throws Exception { @@ -2585,7 +2787,7 @@ } } - return new Object[] {entry, pkey}; + return Pair.of(entry, pkey); } /** * Gets the requested finger print of the certificate. @@ -3027,6 +3229,443 @@ } /** + * Match a command (may be abbreviated) with a command set. + * @param s the command provided + * @param list the legal command set + * @return the position of a single match, or -1 if none matched + * @throws Exception if s is ambiguous + */ + private static int oneOf(String s, String... list) throws Exception { + int[] match = new int[list.length]; + int nmatch = 0; + for (int i = 0; iextstr argument. + * + * @param reqex the requested extensions, can be null, used for -gencert + * @param ext the original extensions, can be null, used for -selfcert + * @param extstrs -ext values, Read keytool doc + * @param pkey the public key for the certificate + * @param akey the public key for the authority (issuer) + * @return the created CertificateExtensions + */ + private CertificateExtensions createV3Extensions( + CertificateExtensions reqex, + CertificateExtensions ext, + List extstrs, + PublicKey pkey, + PublicKey akey) throws Exception { + + if (ext != null && reqex != null) { + // This should not happen + throw new Exception("One of request and original should be null."); + } + if (ext == null) ext = new CertificateExtensions(); + try { + // name{:critical}{=value} + // Honoring requested extensions + if (reqex != null) { + for(String extstr: extstrs) { + if (extstr.toLowerCase().startsWith("honored=")) { + List list = Arrays.asList( + extstr.toLowerCase().substring(8).split(",")); + // First check existence of "all" + if (list.contains("all")) { + ext = reqex; // we know ext was null + } + // one by one for others + for (String item: list) { + if (item.equals("all")) continue; + + // add or remove + boolean add = true; + // -1, unchanged, 0 crtical, 1 non-critical + int action = -1; + String type = null; + if (item.startsWith("-")) { + add = false; + type = item.substring(1); + } else { + int colonpos = item.indexOf(':'); + if (colonpos >= 0) { + type = item.substring(0, colonpos); + action = oneOf(item.substring(colonpos+1), + "critical", "non-critical"); + if (action == -1) { + throw new Exception(rb.getString + ("Illegal value: ") + item); + } + } + } + String n = reqex.getNameByOid(findOidForExtName(type)); + if (add) { + Extension e = (Extension)reqex.get(n); + if (!e.isCritical() && action == 0 + || e.isCritical() && action == 1) { + e = Extension.newExtension( + e.getExtensionId(), + !e.isCritical(), + e.getExtensionValue()); + ext.set(n, e); + } + } else { + ext.delete(n); + } + } + break; + } + } + } + for(String extstr: extstrs) { + String name, value; + boolean isCritical = false; + + int eqpos = extstr.indexOf('='); + if (eqpos >= 0) { + name = extstr.substring(0, eqpos); + value = extstr.substring(eqpos+1); + } else { + name = extstr; + value = null; + } + + int colonpos = name.indexOf(':'); + if (colonpos >= 0) { + if (name.substring(colonpos+1).equalsIgnoreCase("critical")) { + isCritical = true; + } + name = name.substring(0, colonpos); + } + + if (name.equalsIgnoreCase("honored")) { + continue; + } + int exttype = oneOf(name, extSupported); + switch (exttype) { + case 0: // BC + int pathLen = -1; + boolean isCA = false; + if (value == null) { + isCA = true; + } else { + try { // the abbr format + pathLen = Integer.parseInt(value); + isCA = true; + } catch (NumberFormatException ufe) { + // ca:true,pathlen:1 + for (String part: value.split(",")) { + String[] nv = part.split(":"); + if (nv.length != 2) { + throw new Exception(rb.getString + ("Illegal value: ") + extstr); + } else { + if (nv[0].equalsIgnoreCase("ca")) { + isCA = Boolean.parseBoolean(nv[1]); + } else if (nv[0].equalsIgnoreCase("pathlen")) { + pathLen = Integer.parseInt(nv[1]); + } else { + throw new Exception(rb.getString + ("Illegal value: ") + extstr); + } + } + } + } + } + ext.set(BasicConstraintsExtension.NAME, + new BasicConstraintsExtension(isCritical, isCA, + pathLen)); + break; + case 1: // KU + if(value != null) { + boolean[] ok = new boolean[9]; + for (String s: value.split(",")) { + int p = oneOf(s, + "digitalSignature", // (0), + "nonRepudiation", // (1) + "keyEncipherment", // (2), + "dataEncipherment", // (3), + "keyAgreement", // (4), + "keyCertSign", // (5), + "cRLSign", // (6), + "encipherOnly", // (7), + "decipherOnly", // (8) + "contentCommitment" // also (1) + ); + if (p < 0) { + throw new Exception(rb.getString("Unknown keyUsage type: ") + s); + } + if (p == 9) p = 1; + ok[p] = true; + } + KeyUsageExtension kue = new KeyUsageExtension(ok); + // The above KeyUsageExtension constructor does not + // allow isCritical value, so... + ext.set(KeyUsageExtension.NAME, Extension.newExtension( + kue.getExtensionId(), + isCritical, + kue.getExtensionValue())); + } else { + throw new Exception(rb.getString + ("Illegal value: ") + extstr); + } + break; + case 2: // EKU + if(value != null) { + Vector v = + new Vector (); + for (String s: value.split(",")) { + int p = oneOf(s, + "anyExtendedKeyUsage", + "serverAuth", //1 + "clientAuth", //2 + "codeSigning", //3 + "emailProtection", //4 + "", //5 + "", //6 + "", //7 + "timeStamping", //8 + "OCSPSigning" //9 + ); + if (p < 0) { + try { + v.add(new ObjectIdentifier(s)); + } catch (Exception e) { + throw new Exception(rb.getString( + "Unknown extendedkeyUsage type: ") + s); + } + } else if (p == 0) { + v.add(new ObjectIdentifier("2.5.29.37.0")); + } else { + v.add(new ObjectIdentifier("1.3.6.1.5.5.7.3." + p)); + } + } + ext.set(ExtendedKeyUsageExtension.NAME, + new ExtendedKeyUsageExtension(isCritical, v)); + } else { + throw new Exception(rb.getString + ("Illegal value: ") + extstr); + } + break; + case 3: // SAN + case 4: // IAN + if(value != null) { + String[] ps = value.split(","); + GeneralNames gnames = new GeneralNames(); + for(String item: ps) { + colonpos = item.indexOf(':'); + if (colonpos < 0) { + throw new Exception("Illegal item " + item + " in " + extstr); + } + String t = item.substring(0, colonpos); + String v = item.substring(colonpos+1); + gnames.add(createGeneralName(t, v)); + } + if (exttype == 3) { + ext.set(SubjectAlternativeNameExtension.NAME, + new SubjectAlternativeNameExtension( + isCritical, gnames)); + } else { + ext.set(IssuerAlternativeNameExtension.NAME, + new IssuerAlternativeNameExtension( + isCritical, gnames)); + } + } else { + throw new Exception(rb.getString + ("Illegal value: ") + extstr); + } + break; + case 5: // SIA, always non-critical + case 6: // AIA, always non-critical + if (isCritical) { + throw new Exception(rb.getString( + "This extension cannot be marked as critical. ") + extstr); + } + if(value != null) { + List accessDescriptions = + new ArrayList(); + String[] ps = value.split(","); + for(String item: ps) { + colonpos = item.indexOf(':'); + int colonpos2 = item.indexOf(':', colonpos+1); + if (colonpos < 0 || colonpos2 < 0) { + throw new Exception(rb.getString + ("Illegal value: ") + extstr); + } + String m = item.substring(0, colonpos); + String t = item.substring(colonpos+1, colonpos2); + String v = item.substring(colonpos2+1); + int p = oneOf(m, + "", + "ocsp", //1 + "caIssuers", //2 + "timeStamping", //3 + "", + "caRepository" //5 + ); + ObjectIdentifier oid; + if (p < 0) { + try { + oid = new ObjectIdentifier(m); + } catch (Exception e) { + throw new Exception(rb.getString( + "Unknown AccessDescription type: ") + m); + } + } else { + oid = new ObjectIdentifier("1.3.6.1.5.5.7.48." + p); + } + accessDescriptions.add(new AccessDescription( + oid, createGeneralName(t, v))); + } + if (exttype == 5) { + ext.set(SubjectInfoAccessExtension.NAME, + new SubjectInfoAccessExtension(accessDescriptions)); + } else { + ext.set(AuthorityInfoAccessExtension.NAME, + new AuthorityInfoAccessExtension(accessDescriptions)); + } + } else { + throw new Exception(rb.getString + ("Illegal value: ") + extstr); + } + break; + case -1: + ObjectIdentifier oid = new ObjectIdentifier(name); + byte[] data = null; + if (value != null) { + data = new byte[value.length() / 2 + 1]; + int pos = 0; + for (char c: value.toCharArray()) { + int hex; + if (c >= '0' && c <= '9') { + hex = c - '0' ; + } else if (c >= 'A' && c <= 'F') { + hex = c - 'A' + 10; + } else if (c >= 'a' && c <= 'f') { + hex = c - 'a' + 10; + } else { + continue; + } + if (pos % 2 == 0) { + data[pos/2] = (byte)(hex << 4); + } else { + data[pos/2] += hex; + } + pos++; + } + if (pos % 2 != 0) { + throw new Exception(rb.getString( + "Odd number of hex digits found: ") + extstr); + } + data = Arrays.copyOf(data, pos/2); + } else { + data = new byte[0]; + } + ext.set(oid.toString(), new Extension(oid, isCritical, + new DerValue(DerValue.tag_OctetString, data) + .toByteArray())); + break; + } + } + // always non-critical + ext.set(SubjectKeyIdentifierExtension.NAME, + new SubjectKeyIdentifierExtension( + new KeyIdentifier(pkey).getIdentifier())); + if (akey != null && !pkey.equals(akey)) { + ext.set(AuthorityKeyIdentifierExtension.NAME, + new AuthorityKeyIdentifierExtension( + new KeyIdentifier(akey), null, null)); + } + } catch(IOException e) { + throw new RuntimeException(e); + } + return ext; + } + + /** * Prints the usage of this tool. */ private void usage() { @@ -3099,6 +3738,32 @@ System.err.println(rb.getString ("\t [-startdate ]")); System.err.println(rb.getString + ("\t [-ext [:critical][=]]...")); + System.err.println(rb.getString + ("\t [-validity ] [-keypass ]")); + System.err.println(rb.getString + ("\t [-keystore ] [-storepass ]")); + System.err.println(rb.getString + ("\t [-storetype ] [-providername ]")); + System.err.println(rb.getString + ("\t [-providerclass [-providerarg ]] ...")); + System.err.println(rb.getString + ("\t [-providerpath ]")); + System.err.println(); + + System.err.println(rb.getString + ("-gencert [-v] [-rfc] [-protected]")); + System.err.println(rb.getString + ("\t [-infile ] [-outfile ]")); + System.err.println(rb.getString + ("\t [-alias ]")); + System.err.println(rb.getString + ("\t [-sigalg ]")); + System.err.println(rb.getString + ("\t [-startdate ]")); + System.err.println(rb.getString + ("\t [-ext [:critical][=]]...")); + System.err.println(rb.getString ("\t [-validity ] [-keypass ]")); System.err.println(rb.getString ("\t [-keystore ] [-storepass ]")); @@ -3202,6 +3867,10 @@ System.err.println(); System.err.println(rb.getString + ("-printcertreq [-v] [-file ]")); + System.err.println(); + + System.err.println(rb.getString ("-storepasswd [-v] [-new ]")); System.err.println(rb.getString ("\t [-keystore ] [-storepass ]")); @@ -3211,12 +3880,6 @@ ("\t [-providerclass [-providerarg ]] ...")); System.err.println(rb.getString ("\t [-providerpath ]")); - - if (debug) { - throw new RuntimeException("NO ERROR, SORRY"); - } else { - System.exit(1); - } } private void tinyHelp() { @@ -3270,4 +3933,8 @@ else if (snd == null) return fst.hashCode() + 2; else return fst.hashCode() * 17 + snd.hashCode(); } + + public static Pair of(A a, B b) { + return new Pair(a,b); + } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/util/Cache.java --- a/jdk/src/share/classes/sun/security/util/Cache.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/security/util/Cache.java Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006 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 @@ -101,6 +101,21 @@ public abstract void remove(Object key); /** + * Set the maximum size. + */ + public abstract void setCapacity(int size); + + /** + * Set the timeout(in seconds). + */ + public abstract void setTimeout(int timeout); + + /** + * accept a visitor + */ + public abstract void accept(CacheVisitor visitor); + + /** * Return a new memory cache with the specified maximum size, unlimited * lifetime for entries, with the values held by SoftReferences. */ @@ -178,6 +193,10 @@ } } + public interface CacheVisitor { + public void visit(Map map); + } + } class NullCache extends Cache { @@ -208,6 +227,18 @@ // empty } + public void setCapacity(int size) { + // empty + } + + public void setTimeout(int timeout) { + // empty + } + + public void accept(CacheVisitor visitor) { + // empty + } + } class MemoryCache extends Cache { @@ -218,8 +249,8 @@ private final static boolean DEBUG = false; private final Map cacheMap; - private final int maxSize; - private final int lifetime; + private int maxSize; + private long lifetime; private final ReferenceQueue queue; public MemoryCache(boolean soft, int maxSize) { @@ -328,7 +359,7 @@ oldEntry.invalidate(); return; } - if (cacheMap.size() > maxSize) { + if (maxSize > 0 && cacheMap.size() > maxSize) { expungeExpiredEntries(); if (cacheMap.size() > maxSize) { // still too large? Iterator t = cacheMap.values().iterator(); @@ -368,6 +399,55 @@ } } + public synchronized void setCapacity(int size) { + expungeExpiredEntries(); + if (size > 0 && cacheMap.size() > size) { + Iterator t = cacheMap.values().iterator(); + for (int i = cacheMap.size() - size; i > 0; i--) { + CacheEntry lruEntry = t.next(); + if (DEBUG) { + System.out.println("** capacity reset removal " + + lruEntry.getKey() + " | " + lruEntry.getValue()); + } + t.remove(); + lruEntry.invalidate(); + } + } + + maxSize = size > 0 ? size : 0; + + if (DEBUG) { + System.out.println("** capacity reset to " + size); + } + } + + public synchronized void setTimeout(int timeout) { + emptyQueue(); + lifetime = timeout > 0 ? timeout * 1000L : 0L; + + if (DEBUG) { + System.out.println("** lifetime reset to " + timeout); + } + } + + // it is a heavyweight method. + public synchronized void accept(CacheVisitor visitor) { + expungeExpiredEntries(); + Map cached = getCachedEntries(); + + visitor.visit(cached); + } + + private Map getCachedEntries() { + Map kvmap = new HashMap(cacheMap.size()); + + for (CacheEntry entry : cacheMap.values()) { + kvmap.put(entry.getKey(), entry.getValue()); + } + + return kvmap; + } + protected CacheEntry newEntry(Object key, Object value, long expirationTime, ReferenceQueue queue) { if (queue != null) { diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/util/DerValue.java --- a/jdk/src/share/classes/sun/security/util/DerValue.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/security/util/DerValue.java Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved. * 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,7 +65,7 @@ protected DerInputBuffer buffer; /** - * The DER-encoded data of the value. + * The DER-encoded data of the value, never null */ public final DerInputStream data; @@ -378,8 +378,6 @@ ("Indefinite length encoding not supported"); length = DerInputStream.getLength(in); } - if (length == 0) - return null; if (fullyBuffered && in.available() != length) throw new IOException("extra data given to DerValue constructor"); @@ -477,6 +475,11 @@ "DerValue.getOctetString, not an Octet String: " + tag); } bytes = new byte[length]; + // Note: do not tempt to call buffer.read(bytes) at all. There's a + // known bug that it returns -1 instead of 0. + if (length == 0) { + return bytes; + } if (buffer.read(bytes) != length) throw new IOException("short read on DerValue buffer"); if (isConstructed()) { diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/util/Resources.java --- a/jdk/src/share/classes/sun/security/util/Resources.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/security/util/Resources.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 @@ -49,6 +49,7 @@ // keytool {"keytool error: ", "keytool error: "}, {"Illegal option: ", "Illegal option: "}, + {"Illegal value: ", "Illegal value: "}, {"Try keytool -help","Try keytool -help"}, {"Command option needs an argument.", "Command option {0} needs an argument."}, {"Warning: Different store and key passwords not supported for PKCS12 KeyStores. Ignoring user-specified value.", @@ -281,6 +282,20 @@ {"keytool usage:\n", "keytool usage:\n"}, {"Extensions: ", "Extensions: "}, + {"(Empty value)", "(Empty value)"}, + {"Extension Request:", "Extension Request:"}, + {"PKCS #10 Certificate Request (Version 1.0)\n" + + "Subject: %s\nPublic Key: %s format %s key\n", + "PKCS #10 Certificate Request (Version 1.0)\n" + + "Subject: %s\nPublic Key: %s format %s key\n"}, + {"Unknown keyUsage type: ", "Unknown keyUsage type: "}, + {"Unknown extendedkeyUsage type: ", "Unknown extendedkeyUsage type: "}, + {"Unknown AccessDescription type: ", "Unknown AccessDescription type: "}, + {"Unrecognized GeneralName type: ", "Unrecognized GeneralName type: "}, + {"This extension cannot be marked as critical. ", + "This extension cannot be marked as critical. "}, + {"Odd number of hex digits found: ", "Odd number of hex digits found: "}, + {"command {0} is ambiguous:", "command {0} is ambiguous:"}, {"-certreq [-v] [-protected]", "-certreq [-v] [-protected]"}, @@ -322,6 +337,14 @@ {"\t [-validity ] [-keypass ]", "\t [-validity ] [-keypass ]"}, /** rest is same as -certreq starting from -keystore **/ + {"-gencert [-v] [-rfc] [-protected]", + "-gencert [-v] [-rfc] [-protected]"}, + {"\t [-infile ] [-outfile ]", + "\t [-infile ] [-outfile ]"}, + {"\t [-sigalg ]", + "\t [-sigalg ]"}, + {"\t [-ext [:critical][=]]...", + "\t [-ext [:critical][=]]..."}, {"-genseckey [-v] [-protected]", "-genseckey [-v] [-protected]"}, @@ -388,6 +411,8 @@ {"-printcert [-v] [-rfc] [-file | -sslserver ]", "-printcert [-v] [-rfc] [-file | -sslserver ]"}, + {"-printcertreq [-v] [-file ]", + "-printcertreq [-v] [-file ]"}, {"No certificate from the SSL server", "No certificate from the SSL server"}, diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/util/SecurityConstants.java --- a/jdk/src/share/classes/sun/security/util/SecurityConstants.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/security/util/SecurityConstants.java Wed Jul 05 16:48:21 2017 +0200 @@ -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"; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/x509/AccessDescription.java --- a/jdk/src/share/classes/sun/security/x509/AccessDescription.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/security/x509/AccessDescription.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 @@ -48,6 +48,17 @@ public static final ObjectIdentifier Ad_CAISSUERS_Id = ObjectIdentifier.newInternal(new int[] {1, 3, 6, 1, 5, 5, 7, 48, 2}); + public static final ObjectIdentifier Ad_TIMESTAMPING_Id = + ObjectIdentifier.newInternal(new int[] {1, 3, 6, 1, 5, 5, 7, 48, 3}); + + public static final ObjectIdentifier Ad_CAREPOSITORY_Id = + ObjectIdentifier.newInternal(new int[] {1, 3, 6, 1, 5, 5, 7, 48, 5}); + + public AccessDescription(ObjectIdentifier accessMethod, GeneralName accessLocation) { + this.accessMethod = accessMethod; + this.accessLocation = accessLocation; + } + public AccessDescription(DerValue derValue) throws IOException { DerInputStream derIn = derValue.getData(); accessMethod = derIn.getOID(); @@ -90,7 +101,19 @@ } public String toString() { - return ("accessMethod: " + accessMethod.toString() + - "\n accessLocation: " + accessLocation.toString()); + String method = null; + if (accessMethod.equals(Ad_CAISSUERS_Id)) { + method = "caIssuers"; + } else if (accessMethod.equals(Ad_CAREPOSITORY_Id)) { + method = "caRepository"; + } else if (accessMethod.equals(Ad_TIMESTAMPING_Id)) { + method = "timeStamping"; + } else if (accessMethod.equals(Ad_OCSP_Id)) { + method = "ocsp"; + } else { + method = accessMethod.toString(); + } + return ("accessMethod: " + method + + "\n accessLocation: " + accessLocation.toString() + "\n"); } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/x509/AuthorityInfoAccessExtension.java --- a/jdk/src/share/classes/sun/security/x509/AuthorityInfoAccessExtension.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/classes/sun/security/x509/AuthorityInfoAccessExtension.java Wed Jul 05 16:48:21 2017 +0200 @@ -43,8 +43,9 @@ * certificate that identifies the specific OCSP Responder to use when * performing on-line validation of that certificate. *

- * This extension is defined in - * Internet X.509 PKI Certificate and Certificate Revocation List (CRL) Profile. The profile permits + * This extension is defined in + * Internet X.509 PKI Certificate and Certificate Revocation List + * (CRL) Profile. The profile permits * the extension to be included in end-entity or CA certificates, * and it must be marked as non-critical. Its ASN.1 definition is as follows: *

diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/x509/AuthorityKeyIdentifierExtension.java
--- a/jdk/src/share/classes/sun/security/x509/AuthorityKeyIdentifierExtension.java	Wed Jul 05 16:47:52 2017 +0200
+++ b/jdk/src/share/classes/sun/security/x509/AuthorityKeyIdentifierExtension.java	Wed Jul 05 16:48:21 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2006 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
@@ -198,7 +198,7 @@
     public String toString() {
         String s = super.toString() + "AuthorityKeyIdentifier [\n";
         if (id != null) {
-            s += id.toString() + "\n";
+            s += id.toString();     // id already has a newline
         }
         if (names != null) {
             s += names.toString() + "\n";
diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/x509/BasicConstraintsExtension.java
--- a/jdk/src/share/classes/sun/security/x509/BasicConstraintsExtension.java	Wed Jul 05 16:47:52 2017 +0200
+++ b/jdk/src/share/classes/sun/security/x509/BasicConstraintsExtension.java	Wed Jul 05 16:48:21 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2006 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
@@ -70,18 +70,15 @@
 
     // Encode this extension value
     private void encodeThis() throws IOException {
-        if (ca == false && pathLen < 0) {
-            this.extensionValue = null;
-            return;
-        }
         DerOutputStream out = new DerOutputStream();
         DerOutputStream tmp = new DerOutputStream();
 
         if (ca) {
             tmp.putBoolean(ca);
-        }
-        if (pathLen >= 0) {
-            tmp.putInteger(pathLen);
+            // Only encode pathLen when ca == true
+            if (pathLen >= 0) {
+                tmp.putInteger(pathLen);
+            }
         }
         out.write(DerValue.tag_Sequence, tmp);
         this.extensionValue = out.toByteArray();
@@ -134,7 +131,7 @@
              throw new IOException("Invalid encoding of BasicConstraints");
          }
 
-         if (val.data == null) {
+         if (val.data == null || val.data.available() == 0) {
              // non-CA cert ("cA" field is FALSE by default), return -1
              return;
          }
diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/x509/CertAndKeyGen.java
--- a/jdk/src/share/classes/sun/security/x509/CertAndKeyGen.java	Wed Jul 05 16:47:52 2017 +0200
+++ b/jdk/src/share/classes/sun/security/x509/CertAndKeyGen.java	Wed Jul 05 16:48:21 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1996-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1996-2009 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -276,12 +276,6 @@
             info.set(X509CertInfo.ISSUER,
                      new CertificateIssuerName(issuer.getSigner()));
 
-            CertificateExtensions ext = new CertificateExtensions();
-                ext.set(SubjectKeyIdentifierExtension.NAME,
-                        new SubjectKeyIdentifierExtension(
-                            new KeyIdentifier(publicKey).getIdentifier()));
-            info.set(X509CertInfo.EXTENSIONS, ext);
-
             cert = new X509CertImpl(info);
             cert.sign(privateKey, this.sigAlg);
 
diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/x509/CertificateExtensions.java
--- a/jdk/src/share/classes/sun/security/x509/CertificateExtensions.java	Wed Jul 05 16:47:52 2017 +0200
+++ b/jdk/src/share/classes/sun/security/x509/CertificateExtensions.java	Wed Jul 05 16:48:21 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2006 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
@@ -231,6 +231,15 @@
         map.remove(name);
     }
 
+    public String getNameByOid(ObjectIdentifier oid) throws IOException {
+        for (String name: map.keySet()) {
+            if (map.get(name).getExtensionId().equals(oid)) {
+                return name;
+            }
+        }
+        return null;
+    }
+
     /**
      * Return an enumeration of names of attributes existing within this
      * attribute.
diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/x509/IssuerAlternativeNameExtension.java
--- a/jdk/src/share/classes/sun/security/x509/IssuerAlternativeNameExtension.java	Wed Jul 05 16:47:52 2017 +0200
+++ b/jdk/src/share/classes/sun/security/x509/IssuerAlternativeNameExtension.java	Wed Jul 05 16:48:21 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2006 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
@@ -90,6 +90,22 @@
     }
 
     /**
+     * Create a IssuerAlternativeNameExtension with the passed criticality
+     * and GeneralNames.
+     *
+     * @param critical true if the extension is to be treated as critical.
+     * @param names the GeneralNames for the issuer.
+     * @exception IOException on error.
+     */
+    public IssuerAlternativeNameExtension(Boolean critical, GeneralNames names)
+    throws IOException {
+        this.names = names;
+        this.extensionId = PKIXExtensions.IssuerAlternativeName_Id;
+        this.critical = critical.booleanValue();
+        encodeThis();
+    }
+
+    /**
      * Create a default IssuerAlternativeNameExtension.
      */
     public IssuerAlternativeNameExtension() {
diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/x509/OIDMap.java
--- a/jdk/src/share/classes/sun/security/x509/OIDMap.java	Wed Jul 05 16:47:52 2017 +0200
+++ b/jdk/src/share/classes/sun/security/x509/OIDMap.java	Wed Jul 05 16:48:21 2017 +0200
@@ -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
@@ -90,6 +90,8 @@
 
     private static final String CERT_ISSUER = ROOT + "." +
                                         CertificateIssuerExtension.NAME;
+    private static final String SUBJECT_INFO_ACCESS = ROOT + "." +
+                                          SubjectInfoAccessExtension.NAME;
     private static final String AUTH_INFO_ACCESS = ROOT + "." +
                                           AuthorityInfoAccessExtension.NAME;
     private static final String ISSUING_DIST_POINT = ROOT + "." +
@@ -148,6 +150,8 @@
                     "sun.security.x509.CRLDistributionPointsExtension");
         addInternal(CERT_ISSUER, PKIXExtensions.CertificateIssuer_Id,
                     "sun.security.x509.CertificateIssuerExtension");
+        addInternal(SUBJECT_INFO_ACCESS, PKIXExtensions.SubjectInfoAccess_Id,
+                    "sun.security.x509.SubjectInfoAccessExtension");
         addInternal(AUTH_INFO_ACCESS, PKIXExtensions.AuthInfoAccess_Id,
                     "sun.security.x509.AuthorityInfoAccessExtension");
         addInternal(ISSUING_DIST_POINT,
diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/classes/sun/security/x509/SubjectInfoAccessExtension.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/security/x509/SubjectInfoAccessExtension.java	Wed Jul 05 16:48:21 2017 +0200
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, 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.security.x509;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.util.*;
+
+import sun.security.util.DerOutputStream;
+import sun.security.util.DerValue;
+
+/**
+ * The Subject Information Access Extension (OID = 1.3.6.1.5.5.7.1.11).
+ * 

+ * The subject information access extension indicates how to access + * information and services for the subject of the certificate in which + * the extension appears. When the subject is a CA, information and + * services may include certificate validation services and CA policy + * data. When the subject is an end entity, the information describes + * the type of services offered and how to access them. In this case, + * the contents of this extension are defined in the protocol + * specifications for the supported services. This extension may be + * included in end entity or CA certificates. Conforming CAs MUST mark + * this extension as non-critical. + *

+ * This extension is defined in + * Internet X.509 PKI Certificate and Certificate Revocation List + * (CRL) Profile. The profile permits + * the extension to be included in end-entity or CA certificates, + * and it must be marked as non-critical. Its ASN.1 definition is as follows: + *

+ *   id-pe-subjectInfoAccess OBJECT IDENTIFIER ::= { id-pe 11 }
+ *
+ *   SubjectInfoAccessSyntax  ::=
+ *          SEQUENCE SIZE (1..MAX) OF AccessDescription
+ *
+ *   AccessDescription  ::=  SEQUENCE {
+ *          accessMethod          OBJECT IDENTIFIER,
+ *          accessLocation        GeneralName  }
+ * 
+ *

+ * @see Extension + * @see CertAttrSet + */ + +public class SubjectInfoAccessExtension extends Extension + implements CertAttrSet { + + /** + * Identifier for this attribute, to be used with the + * get, set, delete methods of Certificate, x509 type. + */ + public static final String IDENT = + "x509.info.extensions.SubjectInfoAccess"; + + /** + * Attribute name. + */ + public static final String NAME = "SubjectInfoAccess"; + public static final String DESCRIPTIONS = "descriptions"; + + /** + * The List of AccessDescription objects. + */ + private List accessDescriptions; + + /** + * Create an SubjectInfoAccessExtension from a List of + * AccessDescription; the criticality is set to false. + * + * @param accessDescriptions the List of AccessDescription + * @throws IOException on error + */ + public SubjectInfoAccessExtension( + List accessDescriptions) throws IOException { + this.extensionId = PKIXExtensions.SubjectInfoAccess_Id; + this.critical = false; + this.accessDescriptions = accessDescriptions; + encodeThis(); + } + + /** + * Create the extension from the passed DER encoded value of the same. + * + * @param critical true if the extension is to be treated as critical. + * @param value Array of DER encoded bytes of the actual value. + * @exception IOException on error. + */ + public SubjectInfoAccessExtension(Boolean critical, Object value) + throws IOException { + this.extensionId = PKIXExtensions.SubjectInfoAccess_Id; + this.critical = critical.booleanValue(); + + if (!(value instanceof byte[])) { + throw new IOException("Illegal argument type"); + } + + extensionValue = (byte[])value; + DerValue val = new DerValue(extensionValue); + if (val.tag != DerValue.tag_Sequence) { + throw new IOException("Invalid encoding for " + + "SubjectInfoAccessExtension."); + } + accessDescriptions = new ArrayList(); + while (val.data.available() != 0) { + DerValue seq = val.data.getDerValue(); + AccessDescription accessDescription = new AccessDescription(seq); + accessDescriptions.add(accessDescription); + } + } + + /** + * Return the list of AccessDescription objects. + */ + public List getAccessDescriptions() { + return accessDescriptions; + } + + /** + * Return the name of this attribute. + */ + public String getName() { + return NAME; + } + + /** + * Write the extension to the DerOutputStream. + * + * @param out the DerOutputStream to write the extension to. + * @exception IOException on encoding errors. + */ + public void encode(OutputStream out) throws IOException { + DerOutputStream tmp = new DerOutputStream(); + if (this.extensionValue == null) { + this.extensionId = PKIXExtensions.SubjectInfoAccess_Id; + this.critical = false; + encodeThis(); + } + super.encode(tmp); + out.write(tmp.toByteArray()); + } + + /** + * Set the attribute value. + */ + public void set(String name, Object obj) throws IOException { + if (name.equalsIgnoreCase(DESCRIPTIONS)) { + if (!(obj instanceof List)) { + throw new IOException("Attribute value should be of type List."); + } + accessDescriptions = (List)obj; + } else { + throw new IOException("Attribute name [" + name + + "] not recognized by " + + "CertAttrSet:SubjectInfoAccessExtension."); + } + encodeThis(); + } + + /** + * Get the attribute value. + */ + public Object get(String name) throws IOException { + if (name.equalsIgnoreCase(DESCRIPTIONS)) { + return accessDescriptions; + } else { + throw new IOException("Attribute name [" + name + + "] not recognized by " + + "CertAttrSet:SubjectInfoAccessExtension."); + } + } + + /** + * Delete the attribute value. + */ + public void delete(String name) throws IOException { + if (name.equalsIgnoreCase(DESCRIPTIONS)) { + accessDescriptions = new ArrayList(); + } else { + throw new IOException("Attribute name [" + name + + "] not recognized by " + + "CertAttrSet:SubjectInfoAccessExtension."); + } + encodeThis(); + } + + /** + * Return an enumeration of names of attributes existing within this + * attribute. + */ + public Enumeration getElements() { + AttributeNameEnumeration elements = new AttributeNameEnumeration(); + elements.addElement(DESCRIPTIONS); + return elements.elements(); + } + + // Encode this extension value + private void encodeThis() throws IOException { + if (accessDescriptions.isEmpty()) { + this.extensionValue = null; + } else { + DerOutputStream ads = new DerOutputStream(); + for (AccessDescription accessDescription : accessDescriptions) { + accessDescription.encode(ads); + } + DerOutputStream seq = new DerOutputStream(); + seq.write(DerValue.tag_Sequence, ads); + this.extensionValue = seq.toByteArray(); + } + } + + /** + * Return the extension as user readable string. + */ + public String toString() { + return super.toString() + "SubjectInfoAccess [\n " + + accessDescriptions + "\n]\n"; + } + +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/native/java/util/zip/zip_util.c --- a/jdk/src/share/native/java/util/zip/zip_util.c Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/native/java/util/zip/zip_util.c Wed Jul 05 16:48:21 2017 +0200 @@ -135,11 +135,6 @@ #endif } -static jlong -ZFILE_Lseek(ZFILE zfd, off_t offset, int whence) { - return IO_Lseek(zfd, offset, whence); -} - static int ZFILE_read(ZFILE zfd, char *buf, jint nbytes) { #ifdef WIN32 @@ -216,7 +211,7 @@ static int readFullyAt(ZFILE zfd, void *buf, jlong len, jlong offset) { - if (ZFILE_Lseek(zfd, (off_t) offset, SEEK_SET) == -1) { + if (IO_Lseek(zfd, offset, SEEK_SET) == -1) { return -1; /* lseek failure. */ } @@ -476,7 +471,7 @@ unsigned char *cp; #ifdef USE_MMAP static jlong pagesize; - off_t offset; + jlong offset; #endif unsigned char endbuf[ENDHDR]; jzcell *entries; @@ -534,7 +529,7 @@ */ zip->mlen = cenpos - offset + cenlen + ENDHDR; zip->offset = offset; - mappedAddr = mmap(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, offset); + mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset); zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL : (unsigned char*)mappedAddr; @@ -720,7 +715,7 @@ return NULL; } - len = zip->len = ZFILE_Lseek(zfd, 0, SEEK_END); + len = zip->len = IO_Lseek(zfd, 0, SEEK_END); if (len <= 0) { if (len == 0) { /* zip file is empty */ if (pmsg) { diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/native/java/util/zip/zip_util.h --- a/jdk/src/share/native/java/util/zip/zip_util.h Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/native/java/util/zip/zip_util.h Wed Jul 05 16:48:21 2017 +0200 @@ -174,7 +174,7 @@ #ifdef USE_MMAP unsigned char *maddr; /* beginning address of the CEN & ENDHDR */ jlong mlen; /* length (in bytes) mmaped */ - off_t offset; /* offset of the mmapped region from the + jlong offset; /* offset of the mmapped region from the start of the file. */ #else cencache cencache; /* CEN header cache */ diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/native/sun/nio/ch/genSocketOptionRegistry.c --- a/jdk/src/share/native/sun/nio/ch/genSocketOptionRegistry.c Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/share/native/sun/nio/ch/genSocketOptionRegistry.c Wed Jul 05 16:48:21 2017 +0200 @@ -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(" } "); diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/sample/nio/file/AclEdit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/sample/nio/file/AclEdit.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 parsePermissions(String permsString) { + Set perms = new HashSet(); + 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 parseFlags(String flagsString) { + Set flags = new HashSet(); + 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:]:[:flags]: + */ + 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 perms = parsePermissions(permsString); + Set 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 acl = view.getAcl(); + + switch (action) { + // print ACL + case PRINT : { + for (int i=0; i= 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; + } + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/sample/nio/file/Chmod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/sample/nio/file/Chmod.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 symbolic mode expressions 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 chmod program. + * + *

The {@code exprs} parameter is a comma separated list of expressions + * where each takes the form: + *

+ * who operator [permissions] + *
+ * where who 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. + * + *

operator 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. + * + *

permissions 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 permissions is omitted + * when assigned absolutely, then the permissions are cleared for + * the owner, group, or others as identified by who. When omitted + * when adding or removing then the expression is ignored. + * + *

The following examples demonstrate possible values for the {@code + * exprs} parameter: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
{@code u=rw} Sets the owner permissions to be read and write.
{@code ug+w} Sets the owner write and group write permissions.
{@code u+w,o-rwx} Sets the owner write, and removes the others read, others write + * and others execute permissions.
{@code o=} Sets the others permission to none (others read, others write and + * others execute permissions are removed if set)
+ * + * @param exprs + * List of one or more symbolic mode expressions + * + * @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 toAdd = new HashSet(); + final Set toRemove = new HashSet(); + + // 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 change(Set perms) { + perms.addAll(toAdd); + perms.removeAll(toRemove); + return perms; + } + }; + } + + /** + * A task that changes 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 change(Set perms); + } + + /** + * Changes the permissions of the file using the given Changer. + */ + static void chmod(FileRef file, Changer changer) { + try { + Set 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 { + 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 opts = Collections.emptySet(); + while (argi < args.length) { + Path file = Paths.get(args[argi]); + Files.walkFileTree(file, opts, maxDepth, visitor); + argi++; + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/sample/nio/file/Copy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/sample/nio/file/Copy.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 { + 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 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 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); + } + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/sample/nio/file/DiskUsage.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/sample/nio/file/DiskUsage.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); + } + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/sample/nio/file/FileType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/sample/nio/file/FileType.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 = ""; + } + System.out.format("%s\t%s%n", file, type); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/sample/nio/file/WatchDir.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/sample/nio/file/WatchDir.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 keys; + private final boolean recursive; + private boolean trace = false; + + @SuppressWarnings("unchecked") + static WatchEvent cast(WatchEvent event) { + return (WatchEvent)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() { + @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(); + 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 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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/share/sample/nio/file/Xdd.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/sample/nio/file/Xdd.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 "); + System.out.println(" java Xdd -set = "); + System.out.println(" java Xdd -get "); + System.out.println(" java Xdd -del "); + 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(); + } + } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java --- a/jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/solaris/classes/sun/nio/ch/DatagramDispatcher.java Wed Jul 05 16:48:21 2017 +0200 @@ -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) diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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"); + } + +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java --- a/jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java --- a/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/EPoll.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/ch/EPoll.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java --- a/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/solaris/classes/sun/nio/ch/EPollArrayWrapper.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/EPollPort.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/ch/EPollPort.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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(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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java --- a/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/FileDispatcher.java --- a/jdk/src/solaris/classes/sun/nio/ch/FileDispatcher.java Wed Jul 05 16:47:52 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(); - -} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/ch/FileDispatcherImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); + +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/LinuxAsynchronousChannelProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/ch/LinuxAsynchronousChannelProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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)); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java --- a/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/Port.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/ch/Port.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 fdToChannel = + new HashMap(); + + + 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 0); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java --- a/jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/solaris/classes/sun/nio/ch/SinkChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/SocketDispatcher.java --- a/jdk/src/solaris/classes/sun/nio/ch/SocketDispatcher.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/solaris/classes/sun/nio/ch/SocketDispatcher.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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)); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java --- a/jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/solaris/classes/sun/nio/ch/SourceChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 grabPendingAccept() { + synchronized (updateLock) { + PendingFuture 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 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 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() { + 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 Future accept(A attachment, + final CompletionHandler handler) + { + // complete immediately if channel is closed + if (!isOpen()) { + CompletedFuture 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 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(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)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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 pendingConnect; + + // pending remote address (statLock) + private SocketAddress pendingRemote; + + // pending read (updateLock) + private ByteBuffer[] readBuffers; + private boolean scatteringRead; + private PendingFuture pendingRead; + + // pending write (updateLock) + private ByteBuffer[] writeBuffers; + private boolean gatheringWrite; + private PendingFuture 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 connectResult = null; + PendingFuture readResult = null; + PendingFuture 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 grabPendingRead() { + synchronized (updateLock) { + PendingFuture result = pendingRead; + pendingRead = null; + return result; + } + } + + // returns and clears the result of a pending write + PendingFuture grabPendingWrite() { + synchronized (updateLock) { + PendingFuture 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 readyToConnect; + final PendingFuture readyToRead; + final PendingFuture 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 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 Future connect(SocketAddress remote, + A attachment, + CompletionHandler handler) + { + if (!isOpen()) { + CompletedFuture 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 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(this, handler, attachment, OpType.CONNECT); + synchronized (updateLock) { + this.pendingConnect = (PendingFuture)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 result, + boolean invokeDirect) + { + int n = -1; + PendingFuture 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 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") + Future readImpl(ByteBuffer[] dsts, + boolean isScatteringRead, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler 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 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(this, handler, attachment, OpType.READ); + + // update evetns so that read will complete asynchronously + synchronized (updateLock) { + this.readBuffers = dsts; + this.scatteringRead = isScatteringRead; + this.pendingRead = (PendingFuture)result; + updateEvents(); + } + + // schedule timeout + if (timeout > 0L) { + Future timeoutTask = + port.schedule(readTimeoutTask, timeout, unit); + ((PendingFuture)result).setTimeoutTask(timeoutTask); + } + return result; + } + + // data available + enableReading(); + + // result type is Long or Integer + if (isScatteringRead) { + result = (CompletedFuture)CompletedFuture + .withResult(this, Long.valueOf(n), attachment); + } else { + result = (CompletedFuture)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 result, + boolean invokeDirect) + { + PendingFuture 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 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") + Future writeImpl(ByteBuffer[] srcs, + boolean isGatheringWrite, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler 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 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(this, handler, attachment, OpType.WRITE); + + // update evetns so that read will complete asynchronously + synchronized (updateLock) { + this.writeBuffers = srcs; + this.gatheringWrite = isGatheringWrite; + this.pendingWrite = (PendingFuture)result; + updateEvents(); + } + + // schedule timeout + if (timeout > 0L) { + Future timeoutTask = + port.schedule(writeTimeoutTask, timeout, unit); + ((PendingFuture)result).setTimeoutTask(timeoutTask); + } + return result; + } + + // data available + enableWriting(); + if (isGatheringWrite) { + result = (CompletedFuture)CompletedFuture + .withResult(this, Long.valueOf(n), attachment); + } else { + result = (CompletedFuture)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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + public FileSystemProvider run() { + Class c; + try { + c = (Class)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"); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/DefaultFileTypeDetector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/DefaultFileTypeDetector.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/LinuxFileStore.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxFileStore.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 newFileAttributeView(Class view, + UnixPath file, + LinkOption... options) + { + if (view == DosFileAttributeView.class) + return (V) new LinuxDosFileAttributeView(file, followLinks(options)); + if (view == UserDefinedFileAttributeView.class) + return (V) new LinuxUserDefinedFileAttributeView(file, followLinks(options)); + return super.newFileAttributeView(view, file, options); + } + + @Override + @SuppressWarnings("unchecked") + public 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 supportedFileAttributeViews = + supportedFileAttributeViews(); + private static Set supportedFileAttributeViews() { + Set result = new HashSet(); + result.addAll(UnixFileSystem.standardFileAttributeViews()); + // additional Linux-specific views + result.add("dos"); + result.add("xattr"); + return Collections.unmodifiableSet(result); + } + } + + @Override + public Set 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 getMountEntries() { + ArrayList entries = new ArrayList(); + 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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystemProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystemProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/LinuxNativeDispatcher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxNativeDispatcher.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + init(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 asList(long address, int size) { + final List list = new ArrayList(); + 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 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 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(); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/LinuxWatchService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxWatchService.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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(); + 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> 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 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 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() { + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + init(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 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 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 decode(long address, int n) { + ArrayList acl = new ArrayList(n); + for (int i=0; i 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 aceMask = new HashSet(); + 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 aceFlags = new HashSet(); + 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 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 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(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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/SolarisFileStore.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisFileStore.java Wed Jul 05 16:48:21 2017 +0200 @@ -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"); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 newFileAttributeView(Class view, + UnixPath file, LinkOption... options) + { + if (view == AclFileAttributeView.class) + return (V) new SolarisAclFileAttributeView(file, followLinks(options)); + if (view == UserDefinedFileAttributeView.class) { + return(V) new SolarisUserDefinedFileAttributeView(file, followLinks(options)); + } + return super.newFileAttributeView(view, file, options); + } + + @Override + protected 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 supportedFileAttributeViews = + supportedFileAttributeViews(); + private static Set supportedFileAttributeViews() { + Set result = new HashSet(); + result.addAll(UnixFileSystem.standardFileAttributeViews()); + // additional Solaris-specific views + result.add("acl"); + result.add("xattr"); + return Collections.unmodifiableSet(result); + } + } + + @Override + public Set 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 getMountEntries() { + ArrayList entries = new ArrayList(); + 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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + init(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 list = new ArrayList(); + 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/SolarisWatchService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisWatchService.java Wed Jul 05 16:48:21 2017 +0200 @@ -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> events; + + // map of entries in directory; created lazily; accessed only by + // poller thread. + private Map children; + + SolarisWatchKey(SolarisWatchService watcher, + UnixPath dir, + UnixFileKey fileKey, + long object, + Set> 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> events() { + return events; + } + + void setEvents(Set> 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(); + 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 fileKey2WatchKey; + + // maps file_obj object to Node + private final Map 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(); + this.object2Node = new HashMap(); + } + + @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> 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 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 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; iportev_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> 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 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> 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 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() { + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + init(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixChannelFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixChannelFactory.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 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 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 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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixCopyFile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixCopyFile.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + @Override + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + } + +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 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 iterator; + + /** + * Initializes a new instance + */ + UnixDirectoryStream(UnixPath dir, long dp, DirectoryStream.Filter 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 iterator(DirectoryStream 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 iterator() { + return iterator(this); + } + + /** + * Iterator implementation + */ + private class UnixDirectoryIterator implements Iterator { + private final DirectoryStream 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 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; + } + +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixException.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java Wed Jul 05 16:48:21 2017 +0200 @@ -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)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 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 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 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)); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 permissions() { + int bits = (st_mode & UnixConstants.S_IAMB); + HashSet perms = new HashSet(); + + 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(); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixFileKey.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileKey.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixFileModeAttribute.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileModeAttribute.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 perms; + + UnixFileModeAttribute() { + perms = Collections.emptySet(); + } + + static int toUnixMode(Set 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)attr.value()); + } + return mode; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixFileStore.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileStore.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 getFileStoreAttributeView(Class 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 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() { + @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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixFileStoreAttributes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileStoreAttributes.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; + } + +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixFileSystem.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystem.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 getRootDirectories() { + final List allowedList = + Collections.unmodifiableList(Arrays.asList((Path)rootDirectory)); + return new Iterable() { + public Iterator iterator() { + try { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkRead(rootDirectory.toString()); + return allowedList.iterator(); + } catch (SecurityException x) { + List disallowed = Collections.emptyList(); + return disallowed.iterator(); + } + } + }; + } + + /** + * Returns object to iterate over entries in mounttab or equivalent + */ + abstract Iterable getMountEntries(); + + /** + * Returns a FileStore to represent the file system where the given file + * reside. + */ + abstract FileStore getFileStore(UnixPath path) throws IOException; + + /** + * Returns a FileStore to represent the file system for the given mount + * mount. + */ + abstract FileStore getFileStore(UnixMountEntry entry) throws IOException; + + /** + * Iterator returned by getFileStores method. + */ + private class FileStoreIterator implements Iterator { + private final Iterator 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 getFileStores() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + try { + sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); + } catch (SecurityException se) { + return Collections.emptyList(); + } + } + return new Iterable() { + public Iterator 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 newFileAttributeView(Class view, + UnixPath file, + LinkOption... options) + { + if (view == null) + throw new NullPointerException(); + boolean followLinks = followLinks(options); + Class c = view; + if (c == BasicFileAttributeView.class) + return (V) UnixFileAttributeViews.createBasicView(file, followLinks); + if (c == PosixFileAttributeView.class) + return (V) UnixFileAttributeViews.createPosixView(file, followLinks); + if (c == FileOwnerAttributeView.class) + return (V) UnixFileAttributeViews.createOwnerView(file, followLinks); + return (V) null; + } + + static List standardFileAttributeViews() { + return Arrays.asList("basic", "posix", "unix", "owner"); + } + + protected 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); + } + }; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 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 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; + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixMountEntry.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixMountEntry.java Wed Jul 05 16:48:21 2017 +0200 @@ -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"); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + public Void run() { + System.loadLibrary("nio"); + return null; + }}); + initIDs(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixPath.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java Wed Jul 05 16:48:21 2017 +0200 @@ -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> encoder = + new ThreadLocal>(); + + // 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 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(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= 0) { + // name//.. found so mark name and ".." to be + // ignored + ignore[prevName] = true; + ignore[i] = true; + remaining = remaining - 2; + prevName = -1; + } else { + // Case: //.. so mark ".." as ignored + if (isAbsolute) { + boolean hasPrevious = false; + for (int j=0; j 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 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 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 iterator() { + initOffsets(); + return new Iterator() { + int i = 0; + @Override + public boolean hasNext() { + return (i < offsets.length); + } + @Override + public Path next() { + if (i < offsets.length) { + Path result = getName(i); + i++; + return result; + } else { + throw new NoSuchElementException(); + } + } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + // -- file operations -- + + // package-private + 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 newDirectoryStream(DirectoryStream.Filter 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 + getFileAttributeView(Class 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 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 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 options, + FileAttribute... attrs) + throws IOException + { + // need to copy options to add WRITE + Set opts = new HashSet(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[] 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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixSecureDirectoryStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixSecureDirectoryStream.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 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 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 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 getFileAttributeViewImpl(UnixPath file, + Class 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 getFileAttributeView(Class type) { + return getFileAttributeViewImpl(null, type, false); + } + + /** + * Returns file attribute view bound to dfd/filename. + */ + @Override + public V getFileAttributeView(Path obj, + Class 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)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 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 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixUriUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixUriUtils.java Wed Jul 05 16:48:21 2017 +0200 @@ -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> 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' + }; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/classes/sun/nio/fs/UnixUserPrincipals.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixUserPrincipals.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/java/net/Inet4AddressImpl.c --- a/jdk/src/solaris/native/java/net/Inet4AddressImpl.c Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/solaris/native/java/net/Inet4AddressImpl.c Wed Jul 05 16:48:21 2017 +0200 @@ -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; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/java/net/Inet6AddressImpl.c --- a/jdk/src/solaris/native/java/net/Inet6AddressImpl.c Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/solaris/native/java/net/Inet6AddressImpl.c Wed Jul 05 16:48:21 2017 +0200 @@ -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; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/java/net/NetworkInterface.c --- a/jdk/src/solaris/native/java/net/NetworkInterface.c Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/solaris/native/java/net/NetworkInterface.c Wed Jul 05 16:48:21 2017 +0200 @@ -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); diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/ch/EPoll.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/ch/EPoll.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include +#include + +#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); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/ch/EPollPort.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/ch/EPollPort.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include +#include + +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); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/ch/FileChannelImpl.c --- a/jdk/src/solaris/native/sun/nio/ch/FileChannelImpl.c Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/solaris/native/sun/nio/ch/FileChannelImpl.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 #include "sun_nio_ch_FileChannelImpl.h" #include "java_lang_Integer.h" -#include "java_lang_Long.h" #include "nio.h" #include "nio_util.h" #include @@ -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"); - } -} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/ch/FileDispatcher.c --- a/jdk/src/solaris/native/sun/nio/ch/FileDispatcher.c Wed Jul 05 16:47:52 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 -#include -#include -#include -#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); -} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/ch/FileDispatcherImpl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/ch/FileDispatcherImpl.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include +#include +#include +#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); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/ch/SocketDispatcher.c --- a/jdk/src/solaris/native/sun/nio/ch/SocketDispatcher.c Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/solaris/native/sun/nio/ch/SocketDispatcher.c Wed Jul 05 16:48:21 2017 +0200 @@ -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. */ diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/ch/SolarisEventPort.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/ch/SolarisEventPort.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include +#include +#include // 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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.c Wed Jul 05 16:48:21 2017 +0200 @@ -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); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/ch/UnixAsynchronousSocketChannelImpl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/ch/UnixAsynchronousSocketChannelImpl.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include + +#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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/fs/GnomeFileTypeDetector.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/fs/GnomeFileTypeDetector.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include +#include + +#ifdef __solaris__ +#include +#endif + +#ifdef __linux__ +#include +#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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include +#include +#include + +#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); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/fs/LinuxWatchService.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/fs/LinuxWatchService.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include +#include +#include +#include + +#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; + + +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/fs/SolarisNativeDispatcher.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/fs/SolarisNativeDispatcher.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include +#include + +#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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/fs/SolarisWatchService.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/fs/SolarisWatchService.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include +#include +#include // 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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/fs/UnixCopyFile.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/fs/UnixCopyFile.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include + +#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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __solaris__ +#include +#include +#include +#endif + +#ifdef __linux__ +#include +#include +#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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/fs/genSolarisConstants.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/fs/genSolarisConstants.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include +#include +#include +#include +#include + +/** + * 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 + emitX("ACE_ACCESS_ALLOWED_ACE_TYPE", 0x0000); + emitX("ACE_ACCESS_DENIED_ACE_TYPE", 0x0001); + emitX("ACE_SYSTEM_AUDIT_ACE_TYPE", 0x0002); + emitX("ACE_SYSTEM_ALARM_ACE_TYPE", 0x0003); + emitX("ACE_READ_DATA", 0x00000001); + emitX("ACE_LIST_DIRECTORY", 0x00000001); + emitX("ACE_WRITE_DATA", 0x00000002); + emitX("ACE_ADD_FILE", 0x00000002); + emitX("ACE_APPEND_DATA", 0x00000004); + emitX("ACE_ADD_SUBDIRECTORY", 0x00000004); + emitX("ACE_READ_NAMED_ATTRS", 0x00000008); + emitX("ACE_WRITE_NAMED_ATTRS", 0x00000010); + emitX("ACE_EXECUTE", 0x00000020); + emitX("ACE_DELETE_CHILD", 0x00000040); + emitX("ACE_READ_ATTRIBUTES", 0x00000080); + emitX("ACE_WRITE_ATTRIBUTES", 0x00000100); + emitX("ACE_DELETE", 0x00010000); + emitX("ACE_READ_ACL", 0x00020000); + emitX("ACE_WRITE_ACL", 0x00040000); + emitX("ACE_WRITE_OWNER", 0x00080000); + emitX("ACE_SYNCHRONIZE", 0x00100000); + emitX("ACE_FILE_INHERIT_ACE", 0x0001); + emitX("ACE_DIRECTORY_INHERIT_ACE", 0x0002); + emitX("ACE_NO_PROPAGATE_INHERIT_ACE", 0x0004); + emitX("ACE_INHERIT_ONLY_ACE", 0x0008); + emitX("ACE_SUCCESSFUL_ACCESS_ACE_FLAG", 0x0010); + emitX("ACE_FAILED_ACCESS_ACE_FLAG", 0x0020); + emitX("ACE_IDENTIFIER_GROUP", 0x0040); + emitX("ACE_OWNER", 0x1000); + emitX("ACE_GROUP", 0x2000); + emitX("ACE_EVERYONE", 0x4000); + + out("} "); + return 0; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/solaris/native/sun/nio/fs/genUnixConstants.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/native/sun/nio/fs/genUnixConstants.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include +#include +#include +#include + +/** + * 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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/ch/FileDispatcher.java --- a/jdk/src/windows/classes/sun/nio/ch/FileDispatcher.java Wed Jul 05 16:47:52 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; - -} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/ch/FileDispatcherImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; + +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/ch/Iocp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/ch/Iocp.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 keyToChannel = + new HashMap(); + 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 staleIoSet = new HashSet(); + + 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. + */ + PendingFuture 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 PendingFuture 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 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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/ch/PendingIoCache.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/ch/PendingIoCache.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 pendingIoMap = + new HashMap(); + + // 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") + PendingFuture remove(long overlapped) { + synchronized (this) { + PendingFuture 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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousChannelProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousChannelProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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)); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousFileChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 PendingFuture 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 implements Runnable, Iocp.ResultHandler { + private final long position; + private final FileLockImpl fli; + private final PendingFuture result; + + LockTask(long position, + FileLockImpl fli, + PendingFuture 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 Future lock(long position, + long size, + boolean shared, + A attachment, + CompletionHandler 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 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 result = + new PendingFuture(this, handler, attachment); + LockTask lockTask = new LockTask(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 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 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 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 Future read(ByteBuffer dst, + long position, + A attachment, + CompletionHandler 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 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 result = + CompletedFuture.withResult(this, 0, attachment); + Invoker.invoke(handler, result); + return result; + } + + // create Future and task that initiates read + PendingFuture result = + new PendingFuture(this, handler, attachment); + ReadTask readTask = new ReadTask(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 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 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 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 Future write(ByteBuffer src, + long position, + A attachment, + CompletionHandler handler) + { + if (!writing) + throw new NonWritableChannelException(); + if (position < 0) + throw new IllegalArgumentException("Negative position"); + + // check if channel is closed + if (!isOpen()) { + CompletedFuture 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 result = + CompletedFuture.withResult(this, 0, attachment); + Invoker.invoke(handler, result); + return result; + } + + // create Future and task to initiate write + PendingFuture result = + new PendingFuture(this, handler, attachment); + WriteTask writeTask = new WriteTask(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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 PendingFuture 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 implements Runnable, Iocp.ResultHandler { + private final WindowsAsynchronousSocketChannelImpl channel; + private final AccessControlContext acc; + private final PendingFuture result; + + AcceptTask(WindowsAsynchronousSocketChannelImpl channel, + AccessControlContext acc, + PendingFuture 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() { + 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 Future accept(A attachment, + final CompletionHandler handler) + { + if (!isOpen()) { + CompletedFuture 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 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 result = + new PendingFuture(this, handler, attachment); + AcceptTask task = new AcceptTask(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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 PendingFuture 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 implements Runnable, Iocp.ResultHandler { + private final InetSocketAddress remote; + private final PendingFuture result; + + ConnectTask(InetSocketAddress remote, PendingFuture 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 Future connect(SocketAddress remote, + A attachment, + CompletionHandler handler) + { + if (!isOpen()) { + CompletedFuture 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 result = CompletedFuture + .withFailure(this, bindException, attachment); + Invoker.invoke(handler, result); + return result; + } + + // setup task + PendingFuture result = + new PendingFuture(this, handler, attachment); + ConnectTask task = new ConnectTask(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 implements Runnable, Iocp.ResultHandler { + private final ByteBuffer[] bufs; + private final int numBufs; + private final boolean scatteringRead; + private final PendingFuture result; + + // set by run method + private ByteBuffer[] shadow; + + ReadTask(ByteBuffer[] bufs, + boolean scatteringRead, + PendingFuture 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= 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 Future readImpl(ByteBuffer[] bufs, + boolean scatteringRead, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) + { + // setup task + PendingFuture result = + new PendingFuture(this, handler, attachment); + final ReadTask readTask = new ReadTask(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 implements Runnable, Iocp.ResultHandler { + private final ByteBuffer[] bufs; + private final int numBufs; + private final boolean gatheringWrite; + private final PendingFuture result; + + // set by run method + private ByteBuffer[] shadow; + + WriteTask(ByteBuffer[] bufs, + boolean gatheringWrite, + PendingFuture 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= 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 Future writeImpl(ByteBuffer[] bufs, + boolean gatheringWrite, + long timeout, + TimeUnit unit, + A attachment, + CompletionHandler handler) + { + // setup task + PendingFuture result = + new PendingFuture(this, handler, attachment); + final WriteTask writeTask = new WriteTask(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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/DefaultFileSystemProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/DefaultFileSystemProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/DefaultFileTypeDetector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/DefaultFileTypeDetector.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/RegistryFileTypeDetector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/RegistryFileTypeDetector.java Wed Jul 05 16:48:21 2017 +0200 @@ -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\ + 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() { + @Override + public Void run() { + // nio.dll has dependency on net.dll + System.loadLibrary("net"); + System.loadLibrary("nio"); + return null; + }}); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 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(); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 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 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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,255 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, 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.BasicFileAttributes; +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 +{ + private final WindowsPath dir; + private final DirectoryStream.Filter filter; + + // handle to directory + private final long handle; + // first entry in the directory + private final String firstName; + + // buffer for WIN32_FIND_DATA structure that receives information about file + private final NativeBuffer findDataBuffer; + + private final Object closeLock = new Object(); + + // need closeLock to access these + private boolean isOpen = true; + private Iterator iterator; + + + WindowsDirectoryStream(WindowsPath dir, DirectoryStream.Filter 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(); + this.findDataBuffer = WindowsFileAttributes.getBufferForFindData(); + } 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; + } + findDataBuffer.release(); + try { + FindClose(handle); + } catch (WindowsException x) { + x.rethrowAsIOException(dir); + } + } + + @Override + public Iterator 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 { + 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, BasicFileAttributes attrs) { + if (s.equals(".") || s.equals("..")) + return null; + if (dir.needsSlashWhenResolving()) { + StringBuilder sb = new StringBuilder(dir.toString()); + sb.append('\\'); + sb.append(s); + s = sb.toString(); + } else { + s = dir + s; + } + Path entry = WindowsPath + .createFromNormalizedPath(dir.getFileSystem(), s, attrs); + 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, null); + first = null; + if (nextEntry != null) + return nextEntry; + } + + for (;;) { + String name = null; + WindowsFileAttributes attrs; + + // synchronize on closeLock to prevent close while reading + synchronized (closeLock) { + if (!isOpen) + throwAsConcurrentModificationException(new + IllegalStateException("Directory stream is closed")); + try { + name = FindNextFile(handle, findDataBuffer.address()); + if (name == null) { + // NO_MORE_FILES + return null; + } + } catch (WindowsException x) { + try { + x.rethrowAsIOException(dir); + } catch (IOException ioe) { + throwAsConcurrentModificationException(ioe); + } + } + + // grab the attributes from the WIN32_FIND_DATA structure + // (needs to be done while holding closeLock because close + // will release the buffer) + attrs = WindowsFileAttributes + .fromFindData(findDataBuffer.address()); + } + + // return entry if accepted by filter + Path entry = acceptEntry(name, attrs); + 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); + } + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsException.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); + } + +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributes.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,461 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, 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; + + /** + * typedef struct _WIN32_FIND_DATA { + * DWORD dwFileAttributes; + * FILETIME ftCreationTime; + * FILETIME ftLastAccessTime; + * FILETIME ftLastWriteTime; + * DWORD nFileSizeHigh; + * DWORD nFileSizeLow; + * DWORD dwReserved0; + * DWORD dwReserved1; + * TCHAR cFileName[MAX_PATH]; + * TCHAR cAlternateFileName[14]; + * } WIN32_FIND_DATA; + */ + private static final short SIZEOF_FIND_DATA = 592; + private static final short OFFSETOF_FIND_DATA_ATTRIBUTES = 0; + private static final short OFFSETOF_FIND_DATA_CREATETIME = 4; + private static final short OFFSETOF_FIND_DATA_LASTACCESSTIME = 12; + private static final short OFFSETOF_FIND_DATA_LASTWRITETIME = 20; + private static final short OFFSETOF_FIND_DATA_SIZEHIGH = 28; + private static final short OFFSETOF_FIND_DATA_SIZELOW = 32; + private static final short OFFSETOF_FIND_DATA_RESERVED0 = 36; + + // 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 + } + + + /** + * Allocates a native buffer for a WIN32_FIND_DATA structure + */ + static NativeBuffer getBufferForFindData() { + return NativeBuffers.getNativeBuffer(SIZEOF_FIND_DATA); + } + + /** + * Create a WindowsFileAttributes from a WIN32_FIND_DATA structure + */ + static WindowsFileAttributes fromFindData(long address) { + int fileAttrs = unsafe.getInt(address + OFFSETOF_FIND_DATA_ATTRIBUTES); + long creationTime = + toJavaTime(unsafe.getLong(address + OFFSETOF_FIND_DATA_CREATETIME)); + long lastAccessTime = + toJavaTime(unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTACCESSTIME)); + long lastWriteTime = + toJavaTime(unsafe.getLong(address + OFFSETOF_FIND_DATA_LASTWRITETIME)); + long size = ((long)(unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZEHIGH)) << 32) + + (unsafe.getInt(address + OFFSETOF_FIND_DATA_SIZELOW) & 0xFFFFFFFFL); + int reparseTag = ((fileAttrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0) ? + + unsafe.getInt(address + OFFSETOF_FIND_DATA_RESERVED0) : 0; + 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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsFileCopy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileCopy.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 getFileStoreAttributeView(Class 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 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 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 result = new HashMap(); + 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; + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsFileSystem.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystem.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,317 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, 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 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 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 result = new ArrayList(); + SecurityManager sm = System.getSecurityManager(); + for (int i = 0; i <= 25; i++) { // 0->A, 1->B, 2->C... + if ((drives & (1 << i)) != 0) { + 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 { + private final Iterator 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 getFileStores() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + try { + sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); + } catch (SecurityException se) { + return Collections.emptyList(); + } + } + return new Iterable() { + public Iterator iterator() { + return new FileStoreIterator(); + } + }; + } + + // supported views + private static final Set supportedFileAttributeViews = Collections + .unmodifiableSet(new HashSet(Arrays.asList("basic", "dos", "acl", "owner", "xattr"))); + + @Override + public Set supportedFileAttributeViews() { + return supportedFileAttributeViews; + } + + @Override + public Path getPath(String path) { + return WindowsPath.parse(this, 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 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 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 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(); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + @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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,1134 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, 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 or null + */ + static native String FindNextFile(long handle, long address) + 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() { + public Void run() { + // nio.dll has dependency on net.dll + System.loadLibrary("net"); + System.loadLibrary("nio"); + return null; + }}); + initIDs(); + } + +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsPath.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,1375 @@ +/* + * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, 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 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. + */ + private WindowsPath(WindowsFileSystem fs, + WindowsPathType type, + String root, + String path) + { + this.fs = fs; + this.type = type; + this.root = root; + this.path = path; + } + + /** + * Creates a Path 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 Path from a given path that is known to be normalized. + */ + static WindowsPath createFromNormalizedPath(WindowsFileSystem fs, + String path, + BasicFileAttributes attrs) + { + try { + WindowsPathParser.Result result = + WindowsPathParser.parseNormalizedPath(path); + if (attrs == null) { + return new WindowsPath(fs, + result.type(), + result.root(), + result.path()); + } else { + return new WindowsPathWithAttributes(fs, + result.type(), + result.root(), + result.path(), + attrs); + } + } catch (InvalidPathException x) { + throw new AssertionError(x.getMessage()); + } + } + + /** + * Creates a WindowsPath from a given path that is known to be normalized. + */ + static WindowsPath createFromNormalizedPath(WindowsFileSystem fs, + String path) + { + return createFromNormalizedPath(fs, path, null); + } + + /** + * Special implementation with attached/cached attributes (used to quicken + * file tree traveral) + */ + private static class WindowsPathWithAttributes + extends WindowsPath implements BasicFileAttributesHolder + { + final WeakReference ref; + + WindowsPathWithAttributes(WindowsFileSystem fs, + WindowsPathType type, + String root, + String path, + BasicFileAttributes attrs) + { + super(fs, type, root, path); + ref = new WeakReference(attrs); + } + + @Override + public BasicFileAttributes get() { + return ref.get(); + } + + @Override + public void invalidate() { + ref.clear(); + } + } + + // 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 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(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; + } + + boolean needsSlashWhenResolving() { + if (path.endsWith("\\")) + return false; + return path.length() > root.length(); + } + + @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 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 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//.. found so mark name and ".." to be + // ignored + ignore[prevName] = true; + ignore[i] = true; + remaining = remaining - 2; + prevName = -1; + } else { + // Cases: + // C:\\.. + // \\server\\share\\.. + // \.. + if (isAbsolute() || type == WindowsPathType.DIRECTORY_RELATIVE) { + boolean hasPrevious = false; + for (int j=0; j 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 list = new ArrayList(); + int start = root.length(); + int off = root.length(); + while (off < path.length()) { + if (path.charAt(off) != '\\') { + off++; + } else { + list.add(start); + start = ++off; + } + } + 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 iterator() { + return new Iterator() { + private int i = 0; + @Override + public boolean hasNext() { + return (i < getNameCount()); + } + @Override + public Path next() { + if (i < getNameCount()) { + Path result = getName(i); + i++; + return result; + } else { + throw new NoSuchElementException(); + } + } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + // -- file operations -- + + // package-private + 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 newDirectoryStream(DirectoryStream.Filter filter) + throws IOException + { + checkRead(); + if (filter == null) + throw new NullPointerException(); + return new WindowsDirectoryStream(this, filter); + } + + @Override + public void implCopyTo(Path obj, CopyOption... options) throws IOException { + WindowsPath target = (WindowsPath)obj; + WindowsFileCopy.copy(this, target, options); + } + + @Override + public void implMoveTo(Path obj, CopyOption... options) throws IOException { + WindowsPath target = (WindowsPath)obj; + WindowsFileCopy.move(this, target, options); + } + + private boolean followLinks(LinkOption... options) { + boolean followLinks = true; + for (LinkOption option: options) { + if (option == LinkOption.NOFOLLOW_LINKS) { + followLinks = false; + continue; + } + if (option == null) + throw new NullPointerException(); + throw new AssertionError("Should not get here"); + } + return followLinks; + } + + @Override + @SuppressWarnings("unchecked") + public V + getFileAttributeView(Class view, LinkOption... options) + { + if (view == null) + throw new NullPointerException(); + boolean followLinks = followLinks(options); + if (view == BasicFileAttributeView.class) + return (V) WindowsFileAttributeViews.createBasicView(this, followLinks); + if (view == DosFileAttributeView.class) + return (V) WindowsFileAttributeViews.createDosView(this, followLinks); + if (view == AclFileAttributeView.class) + return (V) new WindowsAclFileAttributeView(this, followLinks); + if (view == FileOwnerAttributeView.class) + return (V) new FileOwnerAttributeViewImpl( + new WindowsAclFileAttributeView(this, followLinks)); + if (view == UserDefinedFileAttributeView.class) + return (V) new WindowsUserDefinedFileAttributeView(this, followLinks); + return (V) null; + } + + @Override + public 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 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 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 options, + FileAttribute... attrs) + throws IOException + { + // need to copy options to add WRITE + Set opts = new HashSet(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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsPathParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsPathParser.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsPathType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsPathType.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsSecurity.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsSecurity.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); + } + } + }; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 acl) throws IOException { + boolean initialized = false; + + // SECURITY: need to copy list in case size changes during processing + acl = new ArrayList(acl); + + // list of SIDs + sidList = new ArrayList(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 flags = new HashSet(); + 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 perms = new HashSet(); + 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 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 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 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 acl = (List)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 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 result = new ArrayList(aceCount); + + // decode each of the ACEs to AclEntry objects + for (int i=0; i 2) && (path.charAt(2) == ':')) { + // "/c:/foo" --> "c:/foo" + path = path.substring(1); + } + } + return WindowsPath.parse(fs, path); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsUserDefinedFileAttributeView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsUserDefinedFileAttributeView.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 listUsingStreamEnumeration() throws IOException { + List list = new ArrayList(); + 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 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 list = new ArrayList(); + + 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 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 opts = new HashSet(); + 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 opts = new HashSet(); + 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 opts = new HashSet(); + 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsUserPrincipals.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsUserPrincipals.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java Wed Jul 05 16:48:21 2017 +0200 @@ -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> 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> 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> events() { + return events; + } + + void setEvents(Set> 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 int2key; + + // maps file key to WatchKey + private final Map 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(); + this.fk2key = new HashMap(); + 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> 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 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(); + } + } + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/native/sun/nio/ch/FileChannelImpl.c --- a/jdk/src/windows/native/sun/nio/ch/FileChannelImpl.c Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/src/windows/native/sun/nio/ch/FileChannelImpl.c Wed Jul 05 16:48:21 2017 +0200 @@ -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"); - } -} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/native/sun/nio/ch/FileDispatcher.c --- a/jdk/src/windows/native/sun/nio/ch/FileDispatcher.c Wed Jul 05 16:47:52 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 -#include "jni.h" -#include "jni_util.h" -#include "jvm.h" -#include "jlong.h" -#include "sun_nio_ch_FileDispatcher.h" -#include -#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 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 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); -} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/native/sun/nio/ch/FileDispatcherImpl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/native/sun/nio/ch/FileDispatcherImpl.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "sun_nio_ch_FileDispatcherImpl.h" +#include +#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 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 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); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/native/sun/nio/ch/Iocp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/native/sun/nio/ch/Iocp.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 + +#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)); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousFileChannelImpl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousFileChannelImpl.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 + +#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); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include + +#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"); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include +#include + +#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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/native/sun/nio/fs/RegistryFileTypeDetector.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/native/sun/nio/fs/RegistryFileTypeDetector.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 + +#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; +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c Wed Jul 05 16:48:21 2017 +0200 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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, jlong dataAddress) +{ + HANDLE h = (HANDLE)jlong_to_ptr(handle); + WIN32_FIND_DATAW* data = (WIN32_FIND_DATAW*)jlong_to_ptr(dataAddress); + + 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()); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousChannelGroup/AsExecutor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/AsExecutor.java Wed Jul 05 16:48:21 2017 +0200 @@ -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"); + } + +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousChannelGroup/Attack.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Attack.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousChannelGroup/BadProperties.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/BadProperties.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousChannelGroup/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 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) { + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/GroupOfOne.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + 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() { + 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() { + 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"); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousChannelGroup/Identity.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Identity.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 myGroup = + new ThreadLocal() { + @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() { + public void completed(final AsynchronousSocketChannel ch, Void att) { + listener.accept(null, this); + + final ByteBuffer buf = ByteBuffer.allocate(100); + ch.read(buf, null, new CompletionHandler() { + 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() { + 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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousChannelGroup/PrivilegedThreadFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/PrivilegedThreadFactory.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + @Override + public Thread run() { + Thread t = new Thread(r); + t.setDaemon(true); + return t; + } + }); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousChannelGroup/Restart.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Restart.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + 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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/Unbounded.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 queue = + new ArrayBlockingQueue(CONCURRENCY_COUNT); + + // create listener to accept connections + final AsynchronousServerSocketChannel listener = + AsynchronousServerSocketChannel.open() + .bind(new InetSocketAddress(0)); + listener.accept(null, new CompletionHandler() { + 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= 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() { + 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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousChannelGroup/run_any_task.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousChannelGroup/run_any_task.sh Wed Jul 05 16:48:21 2017 +0200 @@ -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 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousDatagramChannel/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + 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 exception = new AtomicReference(); + ch.receive(dst, 2, TimeUnit.SECONDS, null, new CompletionHandler() { + 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() { + 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() { + 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 exception = new AtomicReference(); + ch.read(dst, 2, TimeUnit.SECONDS, null, new CompletionHandler() { + 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() { + 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() { + 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() { + 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() { + 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 remote = ch + .receive(ByteBuffer.allocate(100), timeout, TimeUnit.SECONDS, null, + new CompletionHandler() { + 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 result = ch + .read(ByteBuffer.allocate(100), timeout, TimeUnit.SECONDS, null, + new CompletionHandler() { + 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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 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 () { + 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() { + 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 threads = new ArrayList(); + + 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 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 invoker = new AtomicReference(); + final CountDownLatch latch = new CountDownLatch(1); + + ch.write(genBuffer(), 0L, null, new CompletionHandler() { + 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 res = ch.write(genBuffer(), 0L, null, + new CompletionHandler() { + 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() { + 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() { + 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) { } + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/CustomThreadPool.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 invoker = new AtomicReference(); + ch.write(src, 0, invoker, + new CompletionHandler>() { + public void completed(Integer result, AtomicReference invoker) { + invoker.set(Thread.currentThread()); + } + public void failed(Throwable exc, AtomicReference invoker) { + } + public void cancelled(AtomicReference 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"); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousFileChannel/Lock.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 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 threads = new HashSet(); + + 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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 exception = new AtomicReference(); + + // start accepting + listener.accept(null, new CompletionHandler() { + 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) { + } + + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousServerSocketChannel/WithSecurityManager.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/WithSecurityManager.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousServerSocketChannel/java.policy.allow --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/java.policy.allow Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,3 @@ +grant { + permission java.net.SocketPermission "*:1024-", "accept,connect,resolve"; +}; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousServerSocketChannel/java.policy.deny --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/java.policy.deny Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,3 @@ +grant { + permission java.net.SocketPermission "*:1024-", "connect,resolve"; +}; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 connectException = + new AtomicReference(); + ch.connect(server.address(), null, new CompletionHandler() { + 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 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 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 writeException = + new AtomicReference(); + + // write bytes to fill socket buffer + ch.write(genBuffer(), ch, new CompletionHandler() { + 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 res = ch.read(buf, null, + new CompletionHandler() { + 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() { + 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() { + 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() { + 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() { + 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() { + 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 writeException = new AtomicReference(); + + final long timeout = 5; + final TimeUnit unit = TimeUnit.SECONDS; + + // write bytes to fill socket buffer + ch.write(genBuffer(), timeout, unit, ch, + new CompletionHandler() + { + 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 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 len) + throw new RuntimeException("Too many bytes read"); + if (n > 0) { + total += n; + for (int i=0; i 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 0); + + // close stream when done + out.close(); + + } catch (IOException x) { + x.printStackTrace(); + } + } + + int total() { return total; } + int hash() { return hash; } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java --- a/jdk/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/test/java/nio/channels/DatagramChannel/BasicMulticastTests.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java --- a/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java Wed Jul 05 16:48:21 2017 +0200 @@ -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> options = dc.options(); + Set> options = dc.supportedOptions(); List> expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF, SO_REUSEADDR, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF, IP_MULTICAST_TTL, IP_MULTICAST_LOOP); diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java --- a/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java Wed Jul 05 16:48:21 2017 +0200 @@ -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> options = ssc.options(); + Set> options = ssc.supportedOptions(); if (!options.contains(SO_REUSEADDR)) throw new RuntimeException("SO_REUSEADDR should be supported"); if (!options.contains(SO_RCVBUF)) diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java --- a/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java Wed Jul 05 16:48:21 2017 +0200 @@ -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> options = sc.options(); + Set> options = sc.supportedOptions(); List expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF, SO_KEEPALIVE, SO_REUSEADDR, SO_LINGER, TCP_NODELAY); for (SocketOption opt: expected) { diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/etc/NetworkChannelTests.java --- a/jdk/test/java/nio/channels/etc/NetworkChannelTests.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/test/java/nio/channels/etc/NetworkChannelTests.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/CheckProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/CheckProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 + "'"); + + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/META-INF/services/java.nio.channels.spi.AsynchronousChannelProvider --- /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 Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,1 @@ +Provider1 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider1.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/Provider2.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/custom_provider.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/channels/spi/AsynchronousChannelProvider/custom_provider.sh Wed Jul 05 16:48:21 2017 +0200 @@ -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 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/DirectoryStream/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/DirectoryStream/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 stream; + + // test that directory is empty + Files.withDirectory(dir, new FileAction() { + 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() { + 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 filter = new DirectoryStream.Filter() { + private PathMatcher matcher = + dir.getFileSystem().getPathMatcher("glob:f*"); + public boolean accept(Path file) { + return matcher.matches(file); + } + }; + Files.withDirectory(dir, filter, new FileAction() { + 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() { + private PathMatcher matcher = + dir.getFileSystem().getPathMatcher("glob:z*"); + public boolean accept(Path file) { + return matcher.matches(file); + } + }; + Files.withDirectory(dir, filter, new FileAction() { + 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() { + 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 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/DirectoryStream/DriveLetter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/DirectoryStream/DriveLetter.java Wed Jul 05 16:48:21 2017 +0200 @@ -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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 6808647 + * @summary Checks that a DirectoryStream's iterator returns the expected + * path when opening a directory by specifying only the drive letter. + * @library .. + */ + +import java.nio.file.*; +import java.io.File; +import java.io.IOException; + +public class DriveLetter { + + public static void main(String[] args) throws IOException { + String os = System.getProperty("os.name"); + if (!os.startsWith("Windows")) { + System.out.println("This is Windows specific test"); + return; + } + String here = System.getProperty("user.dir"); + if (here.length() < 2 || here.charAt(1) != ':') + throw new RuntimeException("Unable to determine drive letter"); + + // create temporary file in current directory + File tempFile = File.createTempFile("foo", "tmp", new File(here)); + try { + // we should expect C:foo.tmp to be returned by iterator + String drive = here.substring(0, 2); + Path expected = Paths.get(drive).resolve(tempFile.getName()); + + boolean found = false; + DirectoryStream stream = Paths.get(drive).newDirectoryStream(); + try { + for (Path file : stream) { + if (file.equals(expected)) { + found = true; + break; + } + } + } finally { + stream.close(); + } + if (!found) + throw new RuntimeException("Temporary file not found???"); + + } finally { + tempFile.delete(); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/DirectoryStream/Filters.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/DirectoryStream/Filters.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 newMinimumSizeFilter(final long min) { + return new DirectoryStream.Filter() { + 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 newGlobFilter(final String glob) { + return new DirectoryStream.Filter() { + 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 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> emptyList = Collections.emptyList(); + + // list containing two filters + List> filters = + new ArrayList>(); + filters.add(newMinimumSizeFilter(BIG_FILE_THRESHOLD)); + filters.add(newGlobFilter("*.html")); + + int accepted; + DirectoryStream 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/DirectoryStream/SecureDS.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/DirectoryStream/SecureDS.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 opts = Collections.emptySet(); + stream.newByteChannel(fileEntry, opts).close(); + if (supportsLinks) { + stream.newByteChannel(link1Entry, opts).close(); + try { + Set mixed = new HashSet(); + 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 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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/FileStore/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/FileStore/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/FileSystem/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/FileSystem/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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"); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Files/ContentType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Files/ContentType.java Wed Jul 05 16:48:21 2017 +0200 @@ -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("foo".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); + } + + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Files/CreateFileTree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Files/CreateFileTree.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 dirs = new ArrayList(); + + // create tree + Queue queue = new ArrayDeque(); + 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= 2; + + // create a few regular files in the file tree + int files = dirs.size() * 3; + for (int i=0; i() { + public void invoke(Path entry) { + } + }); + npeExpected(); + } catch (NullPointerException e) { + } + + try { + Files.withDirectory(Paths.get("."), (String)null, new FileAction() { + 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() { + 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(){}); + npeExpected(); + } catch (NullPointerException e) { + } + + try { + Files.walkFileTree(Paths.get("."), null, Integer.MAX_VALUE, + new SimpleFileVisitor(){}); + npeExpected(); + } catch (NullPointerException e) { + } + + try { + Files.walkFileTree(Paths.get("."), EnumSet.noneOf(FileVisitOption.class), + -1, new SimpleFileVisitor(){}); + throw new RuntimeException("IllegalArgumentExpected expected"); + } catch (IllegalArgumentException e) { + } + + try { + Set opts = new HashSet(1); + opts.add(null); + Files.walkFileTree(Paths.get("."), opts, Integer.MAX_VALUE, + new SimpleFileVisitor(){}); + npeExpected(); + } catch (NullPointerException e) { + } + + try { + Files.walkFileTree(Paths.get("."), EnumSet.noneOf(FileVisitOption.class), + Integer.MAX_VALUE, null); + npeExpected(); + } catch (NullPointerException e) { + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Files/PrintFileTree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Files/PrintFileTree.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 options = new HashSet(); + if (followLinks) + options.add(FileVisitOption.FOLLOW_LINKS); + + Files.walkFileTree(dir, options, Integer.MAX_VALUE, new FileVisitor() { + 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; + } + }); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Files/SimpleFileTypeDetector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Files/SimpleFileTypeDetector.java Wed Jul 05 16:48:21 2017 +0200 @@ -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; + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Files/SkipSiblings.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Files/SkipSiblings.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 skipped = new HashSet(); + + // 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() { + 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); + } + }); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Files/TerminateWalk.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Files/TerminateWalk.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + 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(); + } + }); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Files/content_type.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Files/content_type.sh Wed Jul 05 16:48:21 2017 +0200 @@ -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 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Files/walk_file_tree.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Files/walk_file_tree.sh Wed Jul 05 16:48:21 2017 +0200 @@ -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 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Path/CopyAndMove.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Path/CopyAndMove.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 attrs1, + Map 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 readUserDefinedFileAttributes(Path file) + throws IOException + { + UserDefinedFileAttributeView view = file + .getFileAttributeView(UserDefinedFileAttributeView.class); + Map result = new HashMap(); + 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 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 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 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); + } + } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Path/DeleteOnClose.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Path/DeleteOnClose.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 opts = new HashSet(); + 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Path/InterruptCopy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Path/InterruptCopy.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 result = pool.submit(new Callable() { + 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Path/Links.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Path/Links.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Path/Misc.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Path/Misc.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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)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"); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Path/PathOps.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Path/PathOps.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); + } + + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Path/SBC.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Path/SBC.java Wed Jul 05 16:48:21 2017 +0200 @@ -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)null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + + try { + Set opts = new HashSet(); + opts.add(READ); + opts.add(null); + file.newByteChannel(opts); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + + try { + EnumSet opts = EnumSet.of(READ); + file.newByteChannel(opts, (FileAttribute[])null); + throw new RuntimeException("NullPointerException expected"); + } catch (NullPointerException x) { } + + try { + EnumSet 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); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Path/TemporaryFiles.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Path/TemporaryFiles.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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(); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Path/UriImportExport.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Path/UriImportExport.java Wed Jul 05 16:48:21 2017 +0200 @@ -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"); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Path/delete_on_close.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Path/delete_on_close.sh Wed Jul 05 16:48:21 2017 +0200 @@ -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 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/Path/temporary_files.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/Path/temporary_files.sh Wed Jul 05 16:48:21 2017 +0200 @@ -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 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/PathMatcher/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/PathMatcher/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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"); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/TestUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/TestUtil.java Wed Jul 05 16:48:21 2017 +0200 @@ -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() { + @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; + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/WatchService/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/WatchService/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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> 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() { + @Override public String name() { return "custom"; } + @Override public Class 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/WatchService/FileTreeModifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/WatchService/FileTreeModifier.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/WatchService/SensitivityModifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/WatchService/SensitivityModifier.java Wed Jul 05 16:48:21 2017 +0200 @@ -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[]{ 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 event = key.pollEvents().iterator().next(); + if (event.kind() != ENTRY_MODIFY) + throw new RuntimeException("Unexpected event: " + event); + Path name = ((WatchEvent)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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/WatchService/WithSecurityManager.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/WatchService/WithSecurityManager.java Wed Jul 05 16:48:21 2017 +0200 @@ -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"); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/WatchService/denyAll.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/WatchService/denyAll.policy Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,3 @@ +// policy file that does not grant any permissions +grant { +}; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/WatchService/grantDirAndOneLevel.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/WatchService/grantDirAndOneLevel.policy Wed Jul 05 16:48:21 2017 +0200 @@ -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"; +}; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/WatchService/grantDirAndTree.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/WatchService/grantDirAndTree.policy Wed Jul 05 16:48:21 2017 +0200 @@ -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"; +}; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/WatchService/grantDirOnly.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/WatchService/grantDirOnly.policy Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,4 @@ +// policy file that grants read access to source directory +grant { + permission java.io.FilePermission "${test.src}", "read"; +}; diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/attribute/AclFileAttributeView/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/attribute/AclFileAttributeView/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 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 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> asAclAttribute(final List acl) { + return new FileAttribute>() { + public String name() { return "acl:acl"; } + public List value() { return acl; } + }; + } + + static void assertEquals(List actual, List 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 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 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/attribute/Attributes/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/attribute/Attributes/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 orig = attrs.permissions(); + Set newPerms = new HashSet(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 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 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 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/attribute/DosFileAttributeView/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/attribute/DosFileAttributeView/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/attribute/FileStoreAttributeView/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/attribute/FileStoreAttributeView/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 perms = PosixFilePermissions.fromString(mode); + + // change permissions and re-read them. + view.setPermissions(perms); + Set 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)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 requested, + Set 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 requested = PosixFilePermissions.fromString(mode); + FileAttribute> attr = + PosixFilePermissions.asFileAttribute(requested); + System.out.format("create file with mode: %s\n", mode); + + EnumSet 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 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 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 perms = new HashSet(); + 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); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 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); + } + } + } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/spi/SetDefaultProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/spi/SetDefaultProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/nio/file/spi/TestProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/nio/file/spi/TestProvider.java Wed Jul 05 16:48:21 2017 +0200 @@ -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 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 getRootDirectories() { + throw new RuntimeException("not implemented"); + } + + @Override + public Iterable getFileStores() { + throw new RuntimeException("not implemented"); + } + + @Override + public Set 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"); + } + } + +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/security/cert/CertificateFactory/BadX509CertData.java --- a/jdk/test/java/security/cert/CertificateFactory/BadX509CertData.java Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/test/java/security/cert/CertificateFactory/BadX509CertData.java Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2000 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 @@ -40,7 +40,7 @@ InputStream is = new ByteArrayInputStream(data.getBytes("ISO8859_1")); try { Certificate cert = factory.generateCertificate(is); - } catch (CertificateParsingException ce) { + } catch (CertificateException ce) { return; } throw new Exception("CertificateFactory.generateCertificate() did " diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/security/cert/CertificateFactory/openssl/OpenSSLCert.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/security/cert/CertificateFactory/openssl/OpenSSLCert.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 6535697 + * @summary keytool can be more flexible on format of PEM-encoded + * X.509 certificates + */ + +import java.io.*; +import java.util.Arrays; +import java.security.cert.CertificateFactory; + +public class OpenSSLCert { + static final String OUTFILE = "6535697.test"; + + public static void main(String[] args) throws Exception { + test("open"); + test("pem"); + test("open", "open"); + test("open", "pem"); + test("pem", "pem"); + test("pem", "open"); + test("open", "pem", "open"); + test("pem", "open", "pem"); + } + + static void test(String... files) throws Exception { + FileOutputStream fout = new FileOutputStream(OUTFILE); + for (String file: files) { + FileInputStream fin = new FileInputStream( + new File(System.getProperty("test.src", "."), file)); + byte[] buffer = new byte[4096]; + while (true) { + int len = fin.read(buffer); + if (len < 0) break; + fout.write(buffer, 0, len); + } + fin.close(); + } + fout.close(); + System.out.println("Testing " + Arrays.toString(files) + "..."); + if (CertificateFactory.getInstance("X509") + .generateCertificates(new FileInputStream(OUTFILE)) + .size() != files.length) { + throw new Exception("Not same number"); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/security/cert/CertificateFactory/openssl/open --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/security/cert/CertificateFactory/openssl/open Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,72 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1174535938 (0x4601ff02) + Signature Algorithm: dsaWithSHA1 + Issuer: C=EA, ST=Moon, L=Backside, O=A-B-C, OU=Office, CN=Me + Validity + Not Before: Mar 22 03:58:58 2007 GMT + Not After : Jun 20 03:58:58 2007 GMT + Subject: C=EA, ST=Moon, L=Backside, O=A-B-C, OU=Office, CN=Me + Subject Public Key Info: + Public Key Algorithm: dsaEncryption + DSA Public Key: + pub: + 00:c5:ce:e8:be:f0:de:27:9c:88:92:21:28:cf:a5: + 38:8d:c1:5f:e5:90:d2:0b:ea:d4:12:ca:86:b8:04: + 57:1d:41:74:3e:52:2d:87:b8:76:7b:d2:95:d7:67: + 30:76:35:47:fb:e9:86:bf:05:3f:9b:f2:6e:3a:96: + 9a:58:e1:05:44:78:02:31:ee:5f:67:6c:44:d2:95: + 8f:72:62:a4:3e:27:1c:f3:94:8a:1e:0b:98:4c:c0: + 9c:f4:3d:17:6d:36:e4:a0:12:04:01:e4:38:9e:bd: + 86:99:7b:84:43:9b:58:68:ef:ce:3d:85:e3:93:d1: + 1f:1a:18:a4:1e:59:ca:80:2e + P: + 00:fd:7f:53:81:1d:75:12:29:52:df:4a:9c:2e:ec: + e4:e7:f6:11:b7:52:3c:ef:44:00:c3:1e:3f:80:b6: + 51:26:69:45:5d:40:22:51:fb:59:3d:8d:58:fa:bf: + c5:f5:ba:30:f6:cb:9b:55:6c:d7:81:3b:80:1d:34: + 6f:f2:66:60:b7:6b:99:50:a5:a4:9f:9f:e8:04:7b: + 10:22:c2:4f:bb:a9:d7:fe:b7:c6:1b:f8:3b:57:e7: + c6:a8:a6:15:0f:04:fb:83:f6:d3:c5:1e:c3:02:35: + 54:13:5a:16:91:32:f6:75:f3:ae:2b:61:d7:2a:ef: + f2:22:03:19:9d:d1:48:01:c7 + Q: + 00:97:60:50:8f:15:23:0b:cc:b2:92:b9:82:a2:eb: + 84:0b:f0:58:1c:f5 + G: + 00:f7:e1:a0:85:d6:9b:3d:de:cb:bc:ab:5c:36:b8: + 57:b9:79:94:af:bb:fa:3a:ea:82:f9:57:4c:0b:3d: + 07:82:67:51:59:57:8e:ba:d4:59:4f:e6:71:07:10: + 81:80:b4:49:16:71:23:e8:4c:28:16:13:b7:cf:09: + 32:8c:c8:a6:e1:3c:16:7a:8b:54:7c:8d:28:e0:a3: + ae:1e:2b:b3:a6:75:91:6e:a3:7f:0b:fa:21:35:62: + f1:fb:62:7a:01:24:3b:cc:a4:f1:be:a8:51:90:89: + a8:83:df:e1:5a:e5:9f:06:92:8b:66:5e:80:7b:55: + 25:64:01:4c:3b:fe:cf:49:2a + X509v3 extensions: + X509v3 Subject Key Identifier: + ED:BF:8A:CA:57:05:ED:5C:9A:72:65:69:6C:C1:02:F8:30:02:A4:6B + Signature Algorithm: dsaWithSHA1 + 30:2d:02:15:00:85:38:a6:79:d4:70:c8:e1:d8:25:2f:87:f0: + 74:3d:26:59:4c:71:ef:02:14:15:32:10:1d:c0:d1:ce:18:f4: + 8b:ea:c0:8b:d7:da:ba:52:3a:0d:f7 +-----BEGIN CERTIFICATE----- +MIIDGDCCAtWgAwIBAgIERgH/AjALBgcqhkjOOAQDBQAwXTELMAkGA1UEBhMCRUEx +DTALBgNVBAgTBE1vb24xETAPBgNVBAcTCEJhY2tzaWRlMQ4wDAYDVQQKEwVBLUIt +QzEPMA0GA1UECxMGT2ZmaWNlMQswCQYDVQQDEwJNZTAeFw0wNzAzMjIwMzU4NTha +Fw0wNzA2MjAwMzU4NThaMF0xCzAJBgNVBAYTAkVBMQ0wCwYDVQQIEwRNb29uMREw +DwYDVQQHEwhCYWNrc2lkZTEOMAwGA1UEChMFQS1CLUMxDzANBgNVBAsTBk9mZmlj +ZTELMAkGA1UEAxMCTWUwggG4MIIBLAYHKoZIzjgEATCCAR8CgYEA/X9TgR11EilS +30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuA +HTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVU +E1oWkTL2dfOuK2HXKu/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QKB +gQD34aCF1ps93su8q1w2uFe5eZSvu/o66oL5V0wLPQeCZ1FZV4661FlP5nEHEIGA +tEkWcSPoTCgWE7fPCTKMyKbhPBZ6i1R8jSjgo64eK7OmdZFuo38L+iE1YvH7YnoB +JDvMpPG+qFGQiaiD3+Fa5Z8GkotmXoB7VSVkAUw7/s9JKgOBhQACgYEAxc7ovvDe +J5yIkiEoz6U4jcFf5ZDSC+rUEsqGuARXHUF0PlIth7h2e9KV12cwdjVH++mGvwU/ +m/JuOpaaWOEFRHgCMe5fZ2xE0pWPcmKkPicc85SKHguYTMCc9D0XbTbkoBIEAeQ4 +nr2GmXuEQ5tYaO/OPYXjk9EfGhikHlnKgC6jITAfMB0GA1UdDgQWBBTtv4rKVwXt +XJpyZWlswQL4MAKkazALBgcqhkjOOAQDBQADMAAwLQIVAIU4pnnUcMjh2CUvh/B0 +PSZZTHHvAhQVMhAdwNHOGPSL6sCL19q6UjoN9w== +-----END CERTIFICATE----- diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/security/cert/CertificateFactory/openssl/pem --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/security/cert/CertificateFactory/openssl/pem Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIIDGDCCAtWgAwIBAgIERgH/AjALBgcqhkjOOAQDBQAwXTELMAkGA1UEBhMCRUExDTALBgNVBAgT +BE1vb24xETAPBgNVBAcTCEJhY2tzaWRlMQ4wDAYDVQQKEwVBLUItQzEPMA0GA1UECxMGT2ZmaWNl +MQswCQYDVQQDEwJNZTAeFw0wNzAzMjIwMzU4NThaFw0wNzA2MjAwMzU4NThaMF0xCzAJBgNVBAYT +AkVBMQ0wCwYDVQQIEwRNb29uMREwDwYDVQQHEwhCYWNrc2lkZTEOMAwGA1UEChMFQS1CLUMxDzAN +BgNVBAsTBk9mZmljZTELMAkGA1UEAxMCTWUwggG4MIIBLAYHKoZIzjgEATCCAR8CgYEA/X9TgR11 +EilS30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZg +t2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/y +IgMZndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QKBgQD34aCF1ps93su8q1w2uFe5eZSvu/o6 +6oL5V0wLPQeCZ1FZV4661FlP5nEHEIGAtEkWcSPoTCgWE7fPCTKMyKbhPBZ6i1R8jSjgo64eK7Om +dZFuo38L+iE1YvH7YnoBJDvMpPG+qFGQiaiD3+Fa5Z8GkotmXoB7VSVkAUw7/s9JKgOBhQACgYEA +xc7ovvDeJ5yIkiEoz6U4jcFf5ZDSC+rUEsqGuARXHUF0PlIth7h2e9KV12cwdjVH++mGvwU/m/Ju +OpaaWOEFRHgCMe5fZ2xE0pWPcmKkPicc85SKHguYTMCc9D0XbTbkoBIEAeQ4nr2GmXuEQ5tYaO/O +PYXjk9EfGhikHlnKgC6jITAfMB0GA1UdDgQWBBTtv4rKVwXtXJpyZWlswQL4MAKkazALBgcqhkjO +OAQDBQADMAAwLQIVAIU4pnnUcMjh2CUvh/B0PSZZTHHvAhQVMhAdwNHOGPSL6sCL19q6UjoN9w== +-----END CERTIFICATE----- diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/util/regex/BMPTestCases.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/regex/BMPTestCases.txt Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,951 @@ +// +// Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute 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. +// +// +// This file contains test cases with BMP characters for regular expressions. +// A test case consists of three lines: +// The first line is a pattern used in the test +// The second line is the input to search for the pattern in +// The third line is a concatentation of the match, the number of groups, +// and the contents of the first four subexpressions. +// Empty lines and lines beginning with comment slashes are ignored. + +// Test unsetting of backed off groups +^(\u3042)?\u3042 +\u3042 +true \u3042 1 + +^(\u3042\u3042(\u3043\u3043)?)+$ +\u3042\u3042\u3043\u3043\u3042\u3042 +true \u3042\u3042\u3043\u3043\u3042\u3042 2 \u3042\u3042 \u3043\u3043 + +((\u3042|\u3043)?\u3043)+ +\u3043 +true \u3043 2 \u3043 + +(\u3042\u3042\u3042)?\u3042\u3042\u3042 +\u3042\u3042\u3042 +true \u3042\u3042\u3042 1 + +^(\u3042(\u3043)?)+$ +\u3042\u3043\u3042 +true \u3042\u3043\u3042 2 \u3042 \u3043 + +^(\u3042(\u3043(\u3044)?)?)?\u3042\u3043\u3044 +\u3042\u3043\u3044 +true \u3042\u3043\u3044 3 + +^(\u3042(\u3043(\u3044))).* +\u3042\u3043\u3044 +true \u3042\u3043\u3044 3 \u3042\u3043\u3044 \u3043\u3044 \u3044 + +// use of x modifier +\u3042\u3043\u3044(?x)\u3043la\u3049 +\u3042\u3043\u3044\u3043la\u3049 +true \u3042\u3043\u3044\u3043la\u3049 0 + +\u3042\u3043\u3044(?x) bla\u3049 +\u3042\u3043\u3044bla\u3049 +true \u3042\u3043\u3044bla\u3049 0 + +\u3042\u3043\u3044(?x) bla\u3049 ble\u3044\u3049 +\u3042\u3043\u3044bla\u3049ble\u3044\u3049 +true \u3042\u3043\u3044bla\u3049ble\u3044\u3049 0 + +\u3042\u3043\u3044(?x) bla\u3049 # ignore comment +\u3042\u3043\u3044bla\u3049 +true \u3042\u3043\u3044bla\u3049 0 + +// Simple alternation +\u3042|\u3043 +\u3042 +true \u3042 0 + +\u3042|\u3043 +\u305B +false 0 + +\u3042|\u3043 +\u3043 +true \u3043 0 + +\u3042|\u3043|\u3044\u3045 +\u3044\u3045 +true \u3044\u3045 0 + +\u3042|\u3042\u3045 +\u3042\u3045 +true \u3042 0 + +\u305B(\u3042|\u3042\u3044)\u3043 +\u305B\u3042\u3044\u3043 +true \u305B\u3042\u3044\u3043 1 \u3042\u3044 + +// Simple char class +[\u3042\u3043\u3044]+ +\u3042\u3043\u3042\u3043\u3042\u3043 +true \u3042\u3043\u3042\u3043\u3042\u3043 0 + +[\u3042\u3043\u3044]+ +\u3045\u3046\u3047\u3048 +false 0 + +[\u3042\u3043\u3044]+[\u3045\u3046\u3047]+[\u3048\u3049\u304A]+ +\u305B\u305B\u305B\u3042\u3042\u3045\u3045\u3048\u3048\u305B\u305B\u305B +true \u3042\u3042\u3045\u3045\u3048\u3048 0 + +// Range char class +[\u3042-\u3048]+ +\u305B\u305B\u305B\u3048\u3048\u3048 +true \u3048\u3048\u3048 0 + +[\u3042-\u3048]+ +mmm +false 0 + +[\u3042-]+ +\u305B\u3042-9\u305B +true \u3042- 0 + +[\u3042-\\u4444]+ +\u305B\u3042-9\u305B +true \u305B\u3042 0 + +// Negated char class +[^\u3042\u3043\u3044]+ +\u3042\u3043\u3042\u3043\u3042\u3043 +false 0 + +[^\u3042\u3043\u3044]+ +\u3042\u3042\u3042\u3043\u3043\u3043\u3044\u3044\u3044\u3045\u3046\u3047\u3048 +true \u3045\u3046\u3047\u3048 0 + +// Making sure a ^ not in first position matches literal ^ +[\u3042\u3043\u3044^\u3043] +\u3043 +true \u3043 0 + +[\u3042\u3043\u3044^\u3043] +^ +true ^ 0 + +// Class union and intersection +[\u3042\u3043\u3044[\u3045\u3046\u3047]] +\u3043 +true \u3043 0 + +[\u3042\u3043\u3044[\u3045\u3046\u3047]] +\u3046 +true \u3046 0 + +[\u3042-\u3045[0-9][\u304e-\u3051]] +\u3042 +true \u3042 0 + +[\u3042-\u3045[0-9][\u304e-\u3051]] +\u3050 +true \u3050 0 + +[\u3042-\u3045[0-9][\u304e-\u3051]] +4 +true 4 0 + +[\u3042-\u3045[0-9][\u304e-\u3051]] +\u3046 +false 0 + +[\u3042-\u3045[0-9][\u304e-\u3051]] +\u3056 +false 0 + +[[\u3042-\u3045][0-9][\u304e-\u3051]] +\u3043 +true \u3043 0 + +[[\u3042-\u3045][0-9][\u304e-\u3051]] +\u305B +false 0 + +[\u3042-\u3044[\u3045-\u3047[\u3048-\u304A]]] +\u3042 +true \u3042 0 + +[\u3042-\u3044[\u3045-\u3047[\u3048-\u304A]]] +\u3046 +true \u3046 0 + +[\u3042-\u3044[\u3045-\u3047[\u3048-\u304A]]] +\u3049 +true \u3049 0 + +[\u3042-\u3044[\u3045-\u3047[\u3048-\u304A]]] +m +false 0 + +[\u3042-\u3044[\u3045-\u3047[\u3048-\u304A]]m] +m +true m 0 + +[\u3042\u3043\u3044[\u3045\u3046\u3047]\u3048\u3049\u304A] +\u3042 +true \u3042 0 + +[\u3042\u3043\u3044[\u3045\u3046\u3047]\u3048\u3049\u304A] +\u3045 +true \u3045 0 + +[\u3042\u3043\u3044[\u3045\u3046\u3047]\u3048\u3049\u304A] +\u3049 +true \u3049 0 + +[\u3042\u3043\u3044[\u3045\u3046\u3047]\u3048\u3049\u304A] +w +false 0 + +[\u3042-\u3044&&[\u3045-\u3047]] +\u3042 +false 0 + +[\u3042-\u3044&&[\u3045-\u3047]] +\u3046 +false 0 + +[\u3042-\u3044&&[\u3045-\u3047]] +\u305B +false 0 + +[[\u3042-\u3044]&&[\u3045-\u3047]] +\u3042 +false 0 + +[[\u3042-\u3044]&&[\u3045-\u3047]] +\u3046 +false 0 + +[[\u3042-\u3044]&&[\u3045-\u3047]] +\u305B +false 0 + +[\u3042-\u3044&&\u3045-\u3047] +\u3042 +false 0 + +[\u3042-\u304e&&\u304e-\u305B] +\u304e +true \u304e 0 + +[\u3042-\u304e&&\u304e-\u305B&&\u3042-\u3044] +\u304e +false 0 + +[\u3042-\u304e&&\u304e-\u305B&&\u3042-\u305B] +\u304e +true \u304e 0 + +[[\u3042-\u304e]&&[\u304e-\u305B]] +\u3042 +false 0 + +[[\u3042-\u304e]&&[\u304e-\u305B]] +\u304e +true \u304e 0 + +[[\u3042-\u304e]&&[\u304e-\u305B]] +\u305B +false 0 + +[[\u3042-\u304e]&&[^\u3042-\u3044]] +\u3042 +false 0 + +[[\u3042-\u304e]&&[^\u3042-\u3044]] +\u3045 +true \u3045 0 + +[\u3042-\u304e&&[^\u3042-\u3044]] +\u3042 +false 0 + +[\u3042-\u304e&&[^\u3042-\u3044]] +\u3045 +true \u3045 0 + +[\u3042-\u3044\u3045-\u3047&&[\u3045-\u3047]] +\u3042 +false 0 + +[\u3042-\u3044\u3045-\u3047&&[\u3045-\u3047]] +\u3046 +true \u3046 0 + +[[\u3042-\u3044]&&\u3045-\u3047\u3042-\u3044] +\u3042 +true \u3042 0 + +[[\u3042-\u3044]&&[\u3045-\u3047][\u3042-\u3044]] +\u3042 +true \u3042 0 + +[[\u3042-\u3044][\u3045-\u3047]&&\u3042\u3043\u3044] +\u3042 +true \u3042 0 + +[[\u3042-\u3044][\u3045-\u3047]&&\u3042\u3043\u3044[\u3045\u3046\u3047]] +\u3046 +true \u3046 0 + +[[\u3042-\u3044]&&[\u3043-\u3045]&&[\u3044-\u3046]] +\u3042 +false 0 + +[[\u3042-\u3044]&&[\u3043-\u3045]&&[\u3044-\u3046]] +\u3044 +true \u3044 0 + +[[\u3042-\u3044]&&[\u3043-\u3045][\u3044-\u3046]&&[\u3056-\u305B]] +\u3044 +false 0 + +[\u3042\u3043\u3044[^\u3043\u3044\u3045]] +\u3042 +true \u3042 0 + +[\u3042\u3043\u3044[^\u3043\u3044\u3045]] +\u3045 +false 0 + +[\u3042-\u3044&&\u3042-\u3045&&\u3042-\u3046\u3048\u3049\u304A] +\u3043 +true \u3043 0 + +[\u3042-\u3044&&\u3042-\u3045&&\u3042-\u3046\u3048\u3049\u304A] +\u3048 +false 0 + +[[\u3042[\u3043]]&&[\u3043[\u3042]]] +\u3042 +true \u3042 0 + +[[\u3042]&&[\u3043][\u3044][\u3042]&&[^\u3045]] +\u3042 +true \u3042 0 + +[[\u3042]&&[b][c][\u3042]&&[^d]] +\u3042 +true \u3042 0 + +[[\u3042]&&[\u3043][\u3044][\u3042]&&[^\u3045]] +\u3045 +false 0 + +[[[\u3042-\u3045]&&[\u3044-\u3047]]] +\u3042 +false 0 + +[[[\u3042-\u3045]&&[\u3044-\u3047]]] +\u3044 +true \u3044 0 + +[[[\u3042-\u3045]&&[\u3044-\u3047]]&&[\u3044]] +\u3044 +true \u3044 0 + +[[[\u3042-\u3045]&&[\u3044-\u3047]]&&[\u3044]&&\u3044] +\u3044 +true \u3044 0 + +[[[\u3042-\u3045]&&[\u3044-\u3047]]&&[\u3044]&&\u3044&&\u3044] +\u3044 +true \u3044 0 + +[[[\u3042-\u3045]&&[\u3044-\u3047]]&&[\u3044]&&\u3044&&[\u3044\u3045\u3046]] +\u3044 +true \u3044 0 + +[\u305B[\u3042\u3043\u3044&&\u3043\u3044\u3045]] +\u3044 +true \u3044 0 + +[\u305B[\u3042\u3043\u3044&&\u3043\u3044\u3045]&&[\u3056-\u305B]] +\u305B +true \u305B 0 + +[\u3059[\u3042\u3043\u3044&&\u3043\u3044\u3045[\u305B]]&&[\u3056-\u305B]] +\u305B +false 0 + +[\u3059[[w\u305B]\u3042\u3043\u3044&&\u3043\u3044\u3045[\u305B]]&&[\u3056-\u305B]] +\u305B +true \u305B 0 + +[[\u3042\u3043\u3044]&&[\u3045\u3046\u3047]\u3042\u3043\u3044] +\u3042 +true \u3042 0 + +[[\u3042\u3043\u3044]&&[\u3045\u3046\u3047]\u3059\u305A\u305B[\u3042\u3043\u3044]] +\u3042 +true \u3042 0 + +\pL +\u3042 +true \u3042 0 + +\pL +7 +false 0 + +\p{L} +\u3042 +true \u3042 0 + +\p{IsL} +\u3042 +true \u3042 0 + +\p{InHiragana} +\u3042 +true \u3042 0 + +\p{InHiragana} +\u0370 +false 0 + +\pL\u3043\u3044 +\u3042\u3043\u3044 +true \u3042\u3043\u3044 0 + +\u3042[r\p{InGreek}]\u3044 +\u3042\u0370\u3044 +true \u3042\u0370\u3044 0 + +\u3042\p{InGreek} +\u3042\u0370 +true \u3042\u0370 0 + +\u3042\P{InGreek} +\u3042\u0370 +false 0 + +\u3042\P{InGreek} +\u3042\u3043 +true \u3042\u3043 0 + +\u3042{^InGreek} +- +error + +\u3042\p{^InGreek} +- +error + +\u3042\P{^InGreek} +- +error + +\u3042\p{InGreek} +\u3042\u0370 +true \u3042\u0370 0 + +\u3042[\p{InGreek}]\u3044 +\u3042\u0370\u3044 +true \u3042\u0370\u3044 0 + +\u3042[\P{InGreek}]\u3044 +\u3042\u0370\u3044 +false 0 + +\u3042[\P{InGreek}]\u3044 +\u3042\u3043\u3044 +true \u3042\u3043\u3044 0 + +\u3042[{^InGreek}]\u3044 +\u3042n\u3044 +true \u3042n\u3044 0 + +\u3042[{^InGreek}]\u3044 +\u3042\u305B\u3044 +false 0 + +\u3042[\p{^InGreek}]\u3044 +- +error + +\u3042[\P{^InGreek}]\u3044 +- +error + +\u3042[\p{InGreek}] +\u3042\u0370 +true \u3042\u0370 0 + +\u3042[r\p{InGreek}]\u3044 +\u3042r\u3044 +true \u3042r\u3044 0 + +\u3042[\p{InGreek}r]\u3044 +\u3042r\u3044 +true \u3042r\u3044 0 + +\u3042[r\p{InGreek}]\u3044 +\u3042r\u3044 +true \u3042r\u3044 0 + +\u3042[^\p{InGreek}]\u3044 +\u3042\u0370\u3044 +false 0 + +\u3042[^\P{InGreek}]\u3044 +\u3042\u0370\u3044 +true \u3042\u0370\u3044 0 + +\u3042[\p{InGreek}&&[^\u0370]]\u3044 +\u3042\u0370\u3044 +false 0 + +// Test the dot metacharacter +\u3042.\u3044.+ +\u3042#\u3044%& +true \u3042#\u3044%& 0 + +\u3042\u3043. +\u3042\u3043\n +false 0 + +(?s)\u3042\u3043. +\u3042\u3043\n +true \u3042\u3043\n 0 + +\u3042[\p{L}&&[\P{InGreek}]]\u3044 +\u3042\u6000\u3044 +true \u3042\u6000\u3044 0 + +\u3042[\p{L}&&[\P{InGreek}]]\u3044 +\u3042r\u3044 +true \u3042r\u3044 0 + +\u3042[\p{L}&&[\P{InGreek}]]\u3044 +\u3042\u0370\u3044 +false 0 + +\u3042\p{InGreek}\u3044 +\u3042\u0370\u3044 +true \u3042\u0370\u3044 0 + +\u3042\p{Sc} +\u3042$ +true \u3042$ 0 + +\W\w\W +rrrr#\u3048\u3048\u3048 +false 0 + +\u3042\u3043\u3044[\s\u3045\u3046\u3047]* +\u3042\u3043\u3044 \u3045\u3046\u3047 +true \u3042\u3043\u3044 \u3045\u3046\u3047 0 + +\u3042\u3043\u3044[\s\u305A-\u305B]* +\u3042\u3043\u3044 \u305A \u305B +true \u3042\u3043\u3044 \u305A \u305B 0 + +\u3042\u3043\u3044[\u3042-\u3045\s\u304e-\u3051]* +\u3042\u3043\u3044\u3042\u3042 \u304e\u304f \u3051 +true \u3042\u3043\u3044\u3042\u3042 \u304e\u304f \u3051 0 + +// Test the whitespace escape sequence +\u3042\u3043\s\u3044 +\u3042\u3043 \u3044 +true \u3042\u3043 \u3044 0 + +\s\s\s +\u3043l\u3042\u3049 \u3046rr +false 0 + +\S\S\s +\u3043l\u3042\u3049 \u3046rr +true \u3042\u3049 0 + +// Test the digit escape sequence +\u3042\u3043\d\u3044 +\u3042\u30439\u3044 +true \u3042\u30439\u3044 0 + +\d\d\d +\u3043l\u3042\u304945 +false 0 + +// Test the caret metacharacter +^\u3042\u3043\u3044 +\u3042\u3043\u3044\u3045\u3046\u3047 +true \u3042\u3043\u3044 0 + +^\u3042\u3043\u3044 +\u3043\u3044\u3045\u3042\u3043\u3044 +false 0 + +// Greedy ? metacharacter +\u3042?\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3043 0 + +\u3042?\u3043 +\u3043 +true \u3043 0 + +\u3042?\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.?\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3043 0 + +// Reluctant ? metacharacter +\u3042??\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3043 0 + +\u3042??\u3043 +\u3043 +true \u3043 0 + +\u3042??\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.??\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3043 0 + +// Possessive ? metacharacter +\u3042?+\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3043 0 + +\u3042?+\u3043 +\u3043 +true \u3043 0 + +\u3042?+\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.?+\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3043 0 + +// Greedy + metacharacter +\u3042+\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +\u3042+\u3043 +\u3043 +false 0 + +\u3042+\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.+\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +// Reluctant + metacharacter +\u3042+?\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +\u3042+?\u3043 +\u3043 +false 0 + +\u3042+?\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.+?\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +// Possessive + metacharacter +\u3042++\u3043 +\u3042\u3042\u3042\u3042\u3043 +true \u3042\u3042\u3042\u3042\u3043 0 + +\u3042++\u3043 +\u3043 +false 0 + +\u3042++\u3043 +\u3042\u3042\u3042\u3044\u3044\u3044 +false 0 + +.++\u3043 +\u3042\u3042\u3042\u3042\u3043 +false 0 + +// Greedy Repetition +\u3042{2,3} +\u3042 +false 0 + +\u3042{2,3} +\u3042\u3042 +true \u3042\u3042 0 + +\u3042{2,3} +\u3042\u3042\u3042 +true \u3042\u3042\u3042 0 + +\u3042{2,3} +\u3042\u3042\u3042\u3042 +true \u3042\u3042\u3042 0 + +\u3042{3,} +\u305B\u305B\u305B\u3042\u3042\u3042\u3042\u305B\u305B\u305B +true \u3042\u3042\u3042\u3042 0 + +\u3042{3,} +\u305B\u305B\u305B\u3042\u3042\u305B\u305B\u305B +false 0 + +// Reluctant Repetition +\u3042{2,3}? +\u3042 +false 0 + +\u3042{2,3}? +\u3042\u3042 +true \u3042\u3042 0 + +\u3042{2,3}? +\u3042\u3042\u3042 +true \u3042\u3042 0 + +\u3042{2,3}? +\u3042\u3042\u3042\u3042 +true \u3042\u3042 0 + +// Zero width Positive lookahead +\u3042\u3043\u3044(?=\u3045) +\u305B\u305B\u305B\u3042\u3043\u3044\u3045 +true \u3042\u3043\u3044 0 + +\u3042\u3043\u3044(?=\u3045) +\u305B\u305B\u305B\u3042\u3043\u3044\u3046\u3045 +false 0 + +// Zero width Negative lookahead +\u3042\u3043\u3044(?!\u3045) +\u305B\u305B\u3042\u3043\u3044\u3045 +false 0 + +\u3042\u3043\u3044(?!\u3045) +\u305B\u305B\u3042\u3043\u3044\u3046\u3045 +true \u3042\u3043\u3044 0 + +// Zero width Positive lookbehind +\u3042(?<=\u3042) +###\u3042\u3043\u3044 +true \u3042 0 + +\u3042(?<=\u3042) +###\u3043\u3044### +false 0 + +// Zero width Negative lookbehind +(?3 +// So that the BM optimization is part of test +\Q***\E\u3042\u3043\u3044 +***\u3042\u3043\u3044 +true ***\u3042\u3043\u3044 0 + +\u3043l\Q***\E\u3042\u3043\u3044 +\u3043l***\u3042\u3043\u3044 +true \u3043l***\u3042\u3043\u3044 0 + +\Q***\u3042\u3043\u3044 +***\u3042\u3043\u3044 +true ***\u3042\u3043\u3044 0 + +\u3043l\u3042\u3049\Q***\E\u3042\u3043\u3044 +\u3043l\u3042\u3049***\u3042\u3043\u3044 +true \u3043l\u3042\u3049***\u3042\u3043\u3044 0 + +\Q***\u3042\u3043\u3044 +***\u3042\u3043\u3044 +true ***\u3042\u3043\u3044 0 + +\Q*\u3042\u3043 +*\u3042\u3043 +true *\u3042\u3043 0 + +\u3043l\u3042\u3049\Q***\u3042\u3043\u3044 +\u3043l\u3042\u3049***\u3042\u3043\u3044 +true \u3043l\u3042\u3049***\u3042\u3043\u3044 0 + +\u3043l\u3042\Q***\u3042\u3043\u3044 +\u3043l\u3042***\u3042\u3043\u3044 +true \u3043l\u3042***\u3042\u3043\u3044 0 + +[\043]+ +\u3043l\u3042\u3049\u3043l\u3042\u3049#\u3043le\u3044\u3049 +true # 0 + +[\042-\044]+ +\u3043l\u3042\u3049\u3043l\u3042\u3049#\u3043le\u3044\u3049 +true # 0 + +[\u1234-\u1236] +\u3043l\u3042\u3049\u3043l\u3042\u3049\u1235\u3043le\u3044\u3049 +true \u1235 0 + +[^\043]* +\u3043l\u3042\u3049\u3043l\u3042\u3049#\u3043le\u3044\u3049 +true \u3043l\u3042\u3049\u3043l\u3042\u3049 0 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/util/regex/RegExTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/regex/RegExTest.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,3511 @@ +/* + * Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 tests RegExp framework + * @author Mike McCloskey + * @bug 4481568 4482696 4495089 4504687 4527731 4599621 4631553 4619345 + * 4630911 4672616 4711773 4727935 4750573 4792284 4803197 4757029 4808962 + * 4872664 4803179 4892980 4900747 4945394 4938995 4979006 4994840 4997476 + * 5013885 5003322 4988891 5098443 5110268 6173522 4829857 5027748 6376940 + * 6358731 6178785 6284152 6231989 6497148 6486934 6233084 6504326 6635133 + * 6350801 6676425 + */ + +import java.util.regex.*; +import java.util.Random; +import java.io.*; +import java.util.*; +import java.nio.CharBuffer; + +/** + * This is a test class created to check the operation of + * the Pattern and Matcher classes. + */ +public class RegExTest { + + private static Random generator = new Random(); + private static boolean failure = false; + private static int failCount = 0; + + /** + * Main to interpret arguments and run several tests. + * + */ + public static void main(String[] args) throws Exception { + // Most of the tests are in a file + processFile("TestCases.txt"); + //processFile("PerlCases.txt"); + processFile("BMPTestCases.txt"); + processFile("SupplementaryTestCases.txt"); + + // These test many randomly generated char patterns + bm(); + slice(); + + // These are hard to put into the file + escapes(); + blankInput(); + + // Substitition tests on randomly generated sequences + globalSubstitute(); + stringbufferSubstitute(); + substitutionBasher(); + + // Canonical Equivalence + ceTest(); + + // Anchors + anchorTest(); + + // boolean match calls + matchesTest(); + lookingAtTest(); + + // Pattern API + patternMatchesTest(); + + // Misc + lookbehindTest(); + nullArgumentTest(); + backRefTest(); + groupCaptureTest(); + caretTest(); + charClassTest(); + emptyPatternTest(); + findIntTest(); + group0Test(); + longPatternTest(); + octalTest(); + ampersandTest(); + negationTest(); + splitTest(); + appendTest(); + caseFoldingTest(); + commentsTest(); + unixLinesTest(); + replaceFirstTest(); + gTest(); + zTest(); + serializeTest(); + reluctantRepetitionTest(); + multilineDollarTest(); + dollarAtEndTest(); + caretBetweenTerminatorsTest(); + // This RFE rejected in Tiger numOccurrencesTest(); + javaCharClassTest(); + nonCaptureRepetitionTest(); + notCapturedGroupCurlyMatchTest(); + escapedSegmentTest(); + literalPatternTest(); + literalReplacementTest(); + regionTest(); + toStringTest(); + negatedCharClassTest(); + findFromTest(); + boundsTest(); + unicodeWordBoundsTest(); + caretAtEndTest(); + wordSearchTest(); + hitEndTest(); + toMatchResultTest(); + surrogatesInClassTest(); + namedGroupCaptureTest(); + + if (failure) + throw new RuntimeException("Failure in the RE handling."); + else + System.err.println("OKAY: All tests passed."); + } + + // Utility functions + + private static String getRandomAlphaString(int length) { + StringBuffer buf = new StringBuffer(length); + for (int i=0; i 0) + failure = true; + failCount = 0; + } + + /** + * Converts ASCII alphabet characters [A-Za-z] in the given 's' to + * supplementary characters. This method does NOT fully take care + * of the regex syntax. + */ + private static String toSupplementaries(String s) { + int length = s.length(); + StringBuffer sb = new StringBuffer(length * 2); + + for (int i = 0; i < length; ) { + char c = s.charAt(i++); + if (c == '\\') { + sb.append(c); + if (i < length) { + c = s.charAt(i++); + sb.append(c); + if (c == 'u') { + // assume no syntax error + sb.append(s.charAt(i++)); + sb.append(s.charAt(i++)); + sb.append(s.charAt(i++)); + sb.append(s.charAt(i++)); + } + } + } else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { + sb.append('\ud800').append((char)('\udc00'+c)); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + // Regular expression tests + + // This is for bug 6178785 + // Test if an expected NPE gets thrown when passing in a null argument + private static boolean check(Runnable test) { + try { + test.run(); + failCount++; + return false; + } catch (NullPointerException npe) { + return true; + } + } + + private static void nullArgumentTest() { + check(new Runnable() { public void run() { Pattern.compile(null); }}); + check(new Runnable() { public void run() { Pattern.matches(null, null); }}); + check(new Runnable() { public void run() { Pattern.matches("xyz", null);}}); + check(new Runnable() { public void run() { Pattern.quote(null);}}); + check(new Runnable() { public void run() { Pattern.compile("xyz").split(null);}}); + check(new Runnable() { public void run() { Pattern.compile("xyz").matcher(null);}}); + + final Matcher m = Pattern.compile("xyz").matcher("xyz"); + m.matches(); + check(new Runnable() { public void run() { m.appendTail(null);}}); + check(new Runnable() { public void run() { m.replaceAll(null);}}); + check(new Runnable() { public void run() { m.replaceFirst(null);}}); + check(new Runnable() { public void run() { m.appendReplacement(null, null);}}); + check(new Runnable() { public void run() { m.reset(null);}}); + check(new Runnable() { public void run() { Matcher.quoteReplacement(null);}}); + //check(new Runnable() { public void run() { m.usePattern(null);}}); + + report("Null Argument"); + } + + // This is for bug6635133 + // Test if surrogate pair in Unicode escapes can be handled correctly. + private static void surrogatesInClassTest() throws Exception { + Pattern pattern = Pattern.compile("[\\ud834\\udd21-\\ud834\\udd24]"); + Matcher matcher = pattern.matcher("\ud834\udd22"); + if (!matcher.find()) + failCount++; + } + + // This is for bug 4988891 + // Test toMatchResult to see that it is a copy of the Matcher + // that is not affected by subsequent operations on the original + private static void toMatchResultTest() throws Exception { + Pattern pattern = Pattern.compile("squid"); + Matcher matcher = pattern.matcher( + "agiantsquidofdestinyasmallsquidoffate"); + matcher.find(); + int matcherStart1 = matcher.start(); + MatchResult mr = matcher.toMatchResult(); + if (mr == matcher) + failCount++; + int resultStart1 = mr.start(); + if (matcherStart1 != resultStart1) + failCount++; + matcher.find(); + int matcherStart2 = matcher.start(); + int resultStart2 = mr.start(); + if (matcherStart2 == resultStart2) + failCount++; + if (resultStart1 != resultStart2) + failCount++; + MatchResult mr2 = matcher.toMatchResult(); + if (mr == mr2) + failCount++; + if (mr2.start() != matcherStart2) + failCount++; + report("toMatchResult is a copy"); + } + + // This is for bug 5013885 + // Must test a slice to see if it reports hitEnd correctly + private static void hitEndTest() throws Exception { + // Basic test of Slice node + Pattern p = Pattern.compile("^squidattack"); + Matcher m = p.matcher("squack"); + m.find(); + if (m.hitEnd()) + failCount++; + m.reset("squid"); + m.find(); + if (!m.hitEnd()) + failCount++; + + // Test Slice, SliceA and SliceU nodes + for (int i=0; i<3; i++) { + int flags = 0; + if (i==1) flags = Pattern.CASE_INSENSITIVE; + if (i==2) flags = Pattern.UNICODE_CASE; + p = Pattern.compile("^abc", flags); + m = p.matcher("ad"); + m.find(); + if (m.hitEnd()) + failCount++; + m.reset("ab"); + m.find(); + if (!m.hitEnd()) + failCount++; + } + + // Test Boyer-Moore node + p = Pattern.compile("catattack"); + m = p.matcher("attack"); + m.find(); + if (!m.hitEnd()) + failCount++; + + p = Pattern.compile("catattack"); + m = p.matcher("attackattackattackcatatta"); + m.find(); + if (!m.hitEnd()) + failCount++; + + report("hitEnd from a Slice"); + } + + // This is for bug 4997476 + // It is weird code submitted by customer demonstrating a regression + private static void wordSearchTest() throws Exception { + String testString = new String("word1 word2 word3"); + Pattern p = Pattern.compile("\\b"); + Matcher m = p.matcher(testString); + int position = 0; + int start = 0; + while (m.find(position)) { + start = m.start(); + if (start == testString.length()) + break; + if (m.find(start+1)) { + position = m.start(); + } else { + position = testString.length(); + } + if (testString.substring(start, position).equals(" ")) + continue; + if (!testString.substring(start, position-1).startsWith("word")) + failCount++; + } + report("Customer word search"); + } + + // This is for bug 4994840 + private static void caretAtEndTest() throws Exception { + // Problem only occurs with multiline patterns + // containing a beginning-of-line caret "^" followed + // by an expression that also matches the empty string. + Pattern pattern = Pattern.compile("^x?", Pattern.MULTILINE); + Matcher matcher = pattern.matcher("\r"); + matcher.find(); + matcher.find(); + report("Caret at end"); + } + + // This test is for 4979006 + // Check to see if word boundary construct properly handles unicode + // non spacing marks + private static void unicodeWordBoundsTest() throws Exception { + String spaces = " "; + String wordChar = "a"; + String nsm = "\u030a"; + + assert (Character.getType('\u030a') == Character.NON_SPACING_MARK); + + Pattern pattern = Pattern.compile("\\b"); + Matcher matcher = pattern.matcher(""); + // S=other B=word character N=non spacing mark .=word boundary + // SS.BB.SS + String input = spaces + wordChar + wordChar + spaces; + twoFindIndexes(input, matcher, 2, 4); + // SS.BBN.SS + input = spaces + wordChar +wordChar + nsm + spaces; + twoFindIndexes(input, matcher, 2, 5); + // SS.BN.SS + input = spaces + wordChar + nsm + spaces; + twoFindIndexes(input, matcher, 2, 4); + // SS.BNN.SS + input = spaces + wordChar + nsm + nsm + spaces; + twoFindIndexes(input, matcher, 2, 5); + // SSN.BB.SS + input = spaces + nsm + wordChar + wordChar + spaces; + twoFindIndexes(input, matcher, 3, 5); + // SS.BNB.SS + input = spaces + wordChar + nsm + wordChar + spaces; + twoFindIndexes(input, matcher, 2, 5); + // SSNNSS + input = spaces + nsm + nsm + spaces; + matcher.reset(input); + if (matcher.find()) + failCount++; + // SSN.BBN.SS + input = spaces + nsm + wordChar + wordChar + nsm + spaces; + twoFindIndexes(input, matcher, 3, 6); + + report("Unicode word boundary"); + } + + private static void twoFindIndexes(String input, Matcher matcher, int a, + int b) throws Exception + { + matcher.reset(input); + matcher.find(); + if (matcher.start() != a) + failCount++; + matcher.find(); + if (matcher.start() != b) + failCount++; + } + + // This test is for 6284152 + static void check(String regex, String input, String[] expected) { + List result = new ArrayList(); + Pattern p = Pattern.compile(regex); + Matcher m = p.matcher(input); + while (m.find()) { + result.add(m.group()); + } + if (!Arrays.asList(expected).equals(result)) + failCount++; + } + + private static void lookbehindTest() throws Exception { + //Positive + check("(?<=%.{0,5})foo\\d", + "%foo1\n%bar foo2\n%bar foo3\n%blahblah foo4\nfoo5", + new String[]{"foo1", "foo2", "foo3"}); + + //boundary at end of the lookbehind sub-regex should work consistently + //with the boundary just after the lookbehind sub-regex + check("(?<=.*\\b)foo", "abcd foo", new String[]{"foo"}); + check("(?<=.*)\\bfoo", "abcd foo", new String[]{"foo"}); + check("(?]"); + Matcher matcher = pattern.matcher("\u203A"); + if (!matcher.matches()) + failCount++; + pattern = Pattern.compile("[^fr]"); + matcher = pattern.matcher("a"); + if (!matcher.find()) + failCount++; + matcher.reset("\u203A"); + if (!matcher.find()) + failCount++; + String s = "for"; + String result[] = s.split("[^fr]"); + if (!result[0].equals("f")) + failCount++; + if (!result[1].equals("r")) + failCount++; + s = "f\u203Ar"; + result = s.split("[^fr]"); + if (!result[0].equals("f")) + failCount++; + if (!result[1].equals("r")) + failCount++; + + // Test adding to bits, subtracting a node, then adding to bits again + pattern = Pattern.compile("[^f\u203Ar]"); + matcher = pattern.matcher("a"); + if (!matcher.find()) + failCount++; + matcher.reset("f"); + if (matcher.find()) + failCount++; + matcher.reset("\u203A"); + if (matcher.find()) + failCount++; + matcher.reset("r"); + if (matcher.find()) + failCount++; + matcher.reset("\u203B"); + if (!matcher.find()) + failCount++; + + // Test subtracting a node, adding to bits, subtracting again + pattern = Pattern.compile("[^\u203Ar\u203B]"); + matcher = pattern.matcher("a"); + if (!matcher.find()) + failCount++; + matcher.reset("\u203A"); + if (matcher.find()) + failCount++; + matcher.reset("r"); + if (matcher.find()) + failCount++; + matcher.reset("\u203B"); + if (matcher.find()) + failCount++; + matcher.reset("\u203C"); + if (!matcher.find()) + failCount++; + + report("Negated Character Class"); + } + + // This test is for 4628291 + private static void toStringTest() throws Exception { + Pattern pattern = Pattern.compile("b+"); + if (pattern.toString() != "b+") + failCount++; + Matcher matcher = pattern.matcher("aaabbbccc"); + String matcherString = matcher.toString(); // unspecified + matcher.find(); + matcherString = matcher.toString(); // unspecified + matcher.region(0,3); + matcherString = matcher.toString(); // unspecified + matcher.reset(); + matcherString = matcher.toString(); // unspecified + report("toString"); + } + + // This test is for 4808962 + private static void literalPatternTest() throws Exception { + int flags = Pattern.LITERAL; + + Pattern pattern = Pattern.compile("abc\\t$^", flags); + check(pattern, "abc\\t$^", true); + + pattern = Pattern.compile(Pattern.quote("abc\\t$^")); + check(pattern, "abc\\t$^", true); + + pattern = Pattern.compile("\\Qa^$bcabc\\E", flags); + check(pattern, "\\Qa^$bcabc\\E", true); + check(pattern, "a^$bcabc", false); + + pattern = Pattern.compile("\\\\Q\\\\E"); + check(pattern, "\\Q\\E", true); + + pattern = Pattern.compile("\\Qabc\\Eefg\\\\Q\\\\Ehij"); + check(pattern, "abcefg\\Q\\Ehij", true); + + pattern = Pattern.compile("\\\\\\Q\\\\E"); + check(pattern, "\\\\\\\\", true); + + pattern = Pattern.compile(Pattern.quote("\\Qa^$bcabc\\E")); + check(pattern, "\\Qa^$bcabc\\E", true); + check(pattern, "a^$bcabc", false); + + pattern = Pattern.compile(Pattern.quote("\\Qabc\\Edef")); + check(pattern, "\\Qabc\\Edef", true); + check(pattern, "abcdef", false); + + pattern = Pattern.compile(Pattern.quote("abc\\Edef")); + check(pattern, "abc\\Edef", true); + check(pattern, "abcdef", false); + + pattern = Pattern.compile(Pattern.quote("\\E")); + check(pattern, "\\E", true); + + pattern = Pattern.compile("((((abc.+?:)", flags); + check(pattern, "((((abc.+?:)", true); + + flags |= Pattern.MULTILINE; + + pattern = Pattern.compile("^cat$", flags); + check(pattern, "abc^cat$def", true); + check(pattern, "cat", false); + + flags |= Pattern.CASE_INSENSITIVE; + + pattern = Pattern.compile("abcdef", flags); + check(pattern, "ABCDEF", true); + check(pattern, "AbCdEf", true); + + flags |= Pattern.DOTALL; + + pattern = Pattern.compile("a...b", flags); + check(pattern, "A...b", true); + check(pattern, "Axxxb", false); + + flags |= Pattern.CANON_EQ; + + Pattern p = Pattern.compile("testa\u030a", flags); + check(pattern, "testa\u030a", false); + check(pattern, "test\u00e5", false); + + // Supplementary character test + flags = Pattern.LITERAL; + + pattern = Pattern.compile(toSupplementaries("abc\\t$^"), flags); + check(pattern, toSupplementaries("abc\\t$^"), true); + + pattern = Pattern.compile(Pattern.quote(toSupplementaries("abc\\t$^"))); + check(pattern, toSupplementaries("abc\\t$^"), true); + + pattern = Pattern.compile(toSupplementaries("\\Qa^$bcabc\\E"), flags); + check(pattern, toSupplementaries("\\Qa^$bcabc\\E"), true); + check(pattern, toSupplementaries("a^$bcabc"), false); + + pattern = Pattern.compile(Pattern.quote(toSupplementaries("\\Qa^$bcabc\\E"))); + check(pattern, toSupplementaries("\\Qa^$bcabc\\E"), true); + check(pattern, toSupplementaries("a^$bcabc"), false); + + pattern = Pattern.compile(Pattern.quote(toSupplementaries("\\Qabc\\Edef"))); + check(pattern, toSupplementaries("\\Qabc\\Edef"), true); + check(pattern, toSupplementaries("abcdef"), false); + + pattern = Pattern.compile(Pattern.quote(toSupplementaries("abc\\Edef"))); + check(pattern, toSupplementaries("abc\\Edef"), true); + check(pattern, toSupplementaries("abcdef"), false); + + pattern = Pattern.compile(toSupplementaries("((((abc.+?:)"), flags); + check(pattern, toSupplementaries("((((abc.+?:)"), true); + + flags |= Pattern.MULTILINE; + + pattern = Pattern.compile(toSupplementaries("^cat$"), flags); + check(pattern, toSupplementaries("abc^cat$def"), true); + check(pattern, toSupplementaries("cat"), false); + + flags |= Pattern.DOTALL; + + // note: this is case-sensitive. + pattern = Pattern.compile(toSupplementaries("a...b"), flags); + check(pattern, toSupplementaries("a...b"), true); + check(pattern, toSupplementaries("axxxb"), false); + + flags |= Pattern.CANON_EQ; + + String t = toSupplementaries("test"); + p = Pattern.compile(t + "a\u030a", flags); + check(pattern, t + "a\u030a", false); + check(pattern, t + "\u00e5", false); + + report("Literal pattern"); + } + + // This test is for 4803179 + // This test is also for 4808962, replacement parts + private static void literalReplacementTest() throws Exception { + int flags = Pattern.LITERAL; + + Pattern pattern = Pattern.compile("abc", flags); + Matcher matcher = pattern.matcher("zzzabczzz"); + String replaceTest = "$0"; + String result = matcher.replaceAll(replaceTest); + if (!result.equals("zzzabczzz")) + failCount++; + + matcher.reset(); + String literalReplacement = matcher.quoteReplacement(replaceTest); + result = matcher.replaceAll(literalReplacement); + if (!result.equals("zzz$0zzz")) + failCount++; + + matcher.reset(); + replaceTest = "\\t$\\$"; + literalReplacement = matcher.quoteReplacement(replaceTest); + result = matcher.replaceAll(literalReplacement); + if (!result.equals("zzz\\t$\\$zzz")) + failCount++; + + // Supplementary character test + pattern = Pattern.compile(toSupplementaries("abc"), flags); + matcher = pattern.matcher(toSupplementaries("zzzabczzz")); + replaceTest = "$0"; + result = matcher.replaceAll(replaceTest); + if (!result.equals(toSupplementaries("zzzabczzz"))) + failCount++; + + matcher.reset(); + literalReplacement = matcher.quoteReplacement(replaceTest); + result = matcher.replaceAll(literalReplacement); + if (!result.equals(toSupplementaries("zzz$0zzz"))) + failCount++; + + matcher.reset(); + replaceTest = "\\t$\\$"; + literalReplacement = matcher.quoteReplacement(replaceTest); + result = matcher.replaceAll(literalReplacement); + if (!result.equals(toSupplementaries("zzz\\t$\\$zzz"))) + failCount++; + + report("Literal replacement"); + } + + // This test is for 4757029 + private static void regionTest() throws Exception { + Pattern pattern = Pattern.compile("abc"); + Matcher matcher = pattern.matcher("abcdefabc"); + + matcher.region(0,9); + if (!matcher.find()) + failCount++; + if (!matcher.find()) + failCount++; + matcher.region(0,3); + if (!matcher.find()) + failCount++; + matcher.region(3,6); + if (matcher.find()) + failCount++; + matcher.region(0,2); + if (matcher.find()) + failCount++; + + expectRegionFail(matcher, 1, -1); + expectRegionFail(matcher, -1, -1); + expectRegionFail(matcher, -1, 1); + expectRegionFail(matcher, 5, 3); + expectRegionFail(matcher, 5, 12); + expectRegionFail(matcher, 12, 12); + + pattern = Pattern.compile("^abc$"); + matcher = pattern.matcher("zzzabczzz"); + matcher.region(0,9); + if (matcher.find()) + failCount++; + matcher.region(3,6); + if (!matcher.find()) + failCount++; + matcher.region(3,6); + matcher.useAnchoringBounds(false); + if (matcher.find()) + failCount++; + + // Supplementary character test + pattern = Pattern.compile(toSupplementaries("abc")); + matcher = pattern.matcher(toSupplementaries("abcdefabc")); + matcher.region(0,9*2); + if (!matcher.find()) + failCount++; + if (!matcher.find()) + failCount++; + matcher.region(0,3*2); + if (!matcher.find()) + failCount++; + matcher.region(1,3*2); + if (matcher.find()) + failCount++; + matcher.region(3*2,6*2); + if (matcher.find()) + failCount++; + matcher.region(0,2*2); + if (matcher.find()) + failCount++; + matcher.region(0,2*2+1); + if (matcher.find()) + failCount++; + + expectRegionFail(matcher, 1*2, -1); + expectRegionFail(matcher, -1, -1); + expectRegionFail(matcher, -1, 1*2); + expectRegionFail(matcher, 5*2, 3*2); + expectRegionFail(matcher, 5*2, 12*2); + expectRegionFail(matcher, 12*2, 12*2); + + pattern = Pattern.compile(toSupplementaries("^abc$")); + matcher = pattern.matcher(toSupplementaries("zzzabczzz")); + matcher.region(0,9*2); + if (matcher.find()) + failCount++; + matcher.region(3*2,6*2); + if (!matcher.find()) + failCount++; + matcher.region(3*2+1,6*2); + if (matcher.find()) + failCount++; + matcher.region(3*2,6*2-1); + if (matcher.find()) + failCount++; + matcher.region(3*2,6*2); + matcher.useAnchoringBounds(false); + if (matcher.find()) + failCount++; + report("Regions"); + } + + private static void expectRegionFail(Matcher matcher, int index1, + int index2) + { + try { + matcher.region(index1, index2); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Correct result + } catch (IllegalStateException ise) { + // Correct result + } + } + + // This test is for 4803197 + private static void escapedSegmentTest() throws Exception { + + Pattern pattern = Pattern.compile("\\Qdir1\\dir2\\E"); + check(pattern, "dir1\\dir2", true); + + pattern = Pattern.compile("\\Qdir1\\dir2\\\\E"); + check(pattern, "dir1\\dir2\\", true); + + pattern = Pattern.compile("(\\Qdir1\\dir2\\\\E)"); + check(pattern, "dir1\\dir2\\", true); + + // Supplementary character test + pattern = Pattern.compile(toSupplementaries("\\Qdir1\\dir2\\E")); + check(pattern, toSupplementaries("dir1\\dir2"), true); + + pattern = Pattern.compile(toSupplementaries("\\Qdir1\\dir2")+"\\\\E"); + check(pattern, toSupplementaries("dir1\\dir2\\"), true); + + pattern = Pattern.compile(toSupplementaries("(\\Qdir1\\dir2")+"\\\\E)"); + check(pattern, toSupplementaries("dir1\\dir2\\"), true); + + report("Escaped segment"); + } + + // This test is for 4792284 + private static void nonCaptureRepetitionTest() throws Exception { + String input = "abcdefgh;"; + + String[] patterns = new String[] { + "(?:\\w{4})+;", + "(?:\\w{8})*;", + "(?:\\w{2}){2,4};", + "(?:\\w{4}){2,};", // only matches the + ".*?(?:\\w{5})+;", // specified minimum + ".*?(?:\\w{9})*;", // number of reps - OK + "(?:\\w{4})+?;", // lazy repetition - OK + "(?:\\w{4})++;", // possessive repetition - OK + "(?:\\w{2,}?)+;", // non-deterministic - OK + "(\\w{4})+;", // capturing group - OK + }; + + for (int i = 0; i < patterns.length; i++) { + // Check find() + check(patterns[i], 0, input, input, true); + // Check matches() + Pattern p = Pattern.compile(patterns[i]); + Matcher m = p.matcher(input); + + if (m.matches()) { + if (!m.group(0).equals(input)) + failCount++; + } else { + failCount++; + } + } + + report("Non capturing repetition"); + } + + // This test is for 6358731 + private static void notCapturedGroupCurlyMatchTest() throws Exception { + Pattern pattern = Pattern.compile("(abc)+|(abcd)+"); + Matcher matcher = pattern.matcher("abcd"); + if (!matcher.matches() || + matcher.group(1) != null || + !matcher.group(2).equals("abcd")) { + failCount++; + } + report("Not captured GroupCurly"); + } + + // This test is for 4706545 + private static void javaCharClassTest() throws Exception { + for (int i=0; i<1000; i++) { + char c = (char)generator.nextInt(); + check("{javaLowerCase}", c, Character.isLowerCase(c)); + check("{javaUpperCase}", c, Character.isUpperCase(c)); + check("{javaUpperCase}+", c, Character.isUpperCase(c)); + check("{javaTitleCase}", c, Character.isTitleCase(c)); + check("{javaDigit}", c, Character.isDigit(c)); + check("{javaDefined}", c, Character.isDefined(c)); + check("{javaLetter}", c, Character.isLetter(c)); + check("{javaLetterOrDigit}", c, Character.isLetterOrDigit(c)); + check("{javaJavaIdentifierStart}", c, + Character.isJavaIdentifierStart(c)); + check("{javaJavaIdentifierPart}", c, + Character.isJavaIdentifierPart(c)); + check("{javaUnicodeIdentifierStart}", c, + Character.isUnicodeIdentifierStart(c)); + check("{javaUnicodeIdentifierPart}", c, + Character.isUnicodeIdentifierPart(c)); + check("{javaIdentifierIgnorable}", c, + Character.isIdentifierIgnorable(c)); + check("{javaSpaceChar}", c, Character.isSpaceChar(c)); + check("{javaWhitespace}", c, Character.isWhitespace(c)); + check("{javaISOControl}", c, Character.isISOControl(c)); + check("{javaMirrored}", c, Character.isMirrored(c)); + + } + + // Supplementary character test + for (int i=0; i<1000; i++) { + int c = generator.nextInt(Character.MAX_CODE_POINT + - Character.MIN_SUPPLEMENTARY_CODE_POINT) + + Character.MIN_SUPPLEMENTARY_CODE_POINT; + check("{javaLowerCase}", c, Character.isLowerCase(c)); + check("{javaUpperCase}", c, Character.isUpperCase(c)); + check("{javaUpperCase}+", c, Character.isUpperCase(c)); + check("{javaTitleCase}", c, Character.isTitleCase(c)); + check("{javaDigit}", c, Character.isDigit(c)); + check("{javaDefined}", c, Character.isDefined(c)); + check("{javaLetter}", c, Character.isLetter(c)); + check("{javaLetterOrDigit}", c, Character.isLetterOrDigit(c)); + check("{javaJavaIdentifierStart}", c, + Character.isJavaIdentifierStart(c)); + check("{javaJavaIdentifierPart}", c, + Character.isJavaIdentifierPart(c)); + check("{javaUnicodeIdentifierStart}", c, + Character.isUnicodeIdentifierStart(c)); + check("{javaUnicodeIdentifierPart}", c, + Character.isUnicodeIdentifierPart(c)); + check("{javaIdentifierIgnorable}", c, + Character.isIdentifierIgnorable(c)); + check("{javaSpaceChar}", c, Character.isSpaceChar(c)); + check("{javaWhitespace}", c, Character.isWhitespace(c)); + check("{javaISOControl}", c, Character.isISOControl(c)); + check("{javaMirrored}", c, Character.isMirrored(c)); + } + + report("Java character classes"); + } + + // This test is for 4523620 + /* + private static void numOccurrencesTest() throws Exception { + Pattern pattern = Pattern.compile("aaa"); + + if (pattern.numOccurrences("aaaaaa", false) != 2) + failCount++; + if (pattern.numOccurrences("aaaaaa", true) != 4) + failCount++; + + pattern = Pattern.compile("^"); + if (pattern.numOccurrences("aaaaaa", false) != 1) + failCount++; + if (pattern.numOccurrences("aaaaaa", true) != 1) + failCount++; + + report("Number of Occurrences"); + } + */ + + // This test is for 4776374 + private static void caretBetweenTerminatorsTest() throws Exception { + int flags1 = Pattern.DOTALL; + int flags2 = Pattern.DOTALL | Pattern.UNIX_LINES; + int flags3 = Pattern.DOTALL | Pattern.UNIX_LINES | Pattern.MULTILINE; + int flags4 = Pattern.DOTALL | Pattern.MULTILINE; + + check("^....", flags1, "test\ntest", "test", true); + check(".....^", flags1, "test\ntest", "test", false); + check(".....^", flags1, "test\n", "test", false); + check("....^", flags1, "test\r\n", "test", false); + + check("^....", flags2, "test\ntest", "test", true); + check("....^", flags2, "test\ntest", "test", false); + check(".....^", flags2, "test\n", "test", false); + check("....^", flags2, "test\r\n", "test", false); + + check("^....", flags3, "test\ntest", "test", true); + check(".....^", flags3, "test\ntest", "test\n", true); + check(".....^", flags3, "test\u0085test", "test\u0085", false); + check(".....^", flags3, "test\n", "test", false); + check(".....^", flags3, "test\r\n", "test", false); + check("......^", flags3, "test\r\ntest", "test\r\n", true); + + check("^....", flags4, "test\ntest", "test", true); + check(".....^", flags3, "test\ntest", "test\n", true); + check(".....^", flags4, "test\u0085test", "test\u0085", true); + check(".....^", flags4, "test\n", "test\n", false); + check(".....^", flags4, "test\r\n", "test\r", false); + + // Supplementary character test + String t = toSupplementaries("test"); + check("^....", flags1, t+"\n"+t, t, true); + check(".....^", flags1, t+"\n"+t, t, false); + check(".....^", flags1, t+"\n", t, false); + check("....^", flags1, t+"\r\n", t, false); + + check("^....", flags2, t+"\n"+t, t, true); + check("....^", flags2, t+"\n"+t, t, false); + check(".....^", flags2, t+"\n", t, false); + check("....^", flags2, t+"\r\n", t, false); + + check("^....", flags3, t+"\n"+t, t, true); + check(".....^", flags3, t+"\n"+t, t+"\n", true); + check(".....^", flags3, t+"\u0085"+t, t+"\u0085", false); + check(".....^", flags3, t+"\n", t, false); + check(".....^", flags3, t+"\r\n", t, false); + check("......^", flags3, t+"\r\n"+t, t+"\r\n", true); + + check("^....", flags4, t+"\n"+t, t, true); + check(".....^", flags3, t+"\n"+t, t+"\n", true); + check(".....^", flags4, t+"\u0085"+t, t+"\u0085", true); + check(".....^", flags4, t+"\n", t+"\n", false); + check(".....^", flags4, t+"\r\n", t+"\r", false); + + report("Caret between terminators"); + } + + // This test is for 4727935 + private static void dollarAtEndTest() throws Exception { + int flags1 = Pattern.DOTALL; + int flags2 = Pattern.DOTALL | Pattern.UNIX_LINES; + int flags3 = Pattern.DOTALL | Pattern.MULTILINE; + + check("....$", flags1, "test\n", "test", true); + check("....$", flags1, "test\r\n", "test", true); + check(".....$", flags1, "test\n", "test\n", true); + check(".....$", flags1, "test\u0085", "test\u0085", true); + check("....$", flags1, "test\u0085", "test", true); + + check("....$", flags2, "test\n", "test", true); + check(".....$", flags2, "test\n", "test\n", true); + check(".....$", flags2, "test\u0085", "test\u0085", true); + check("....$", flags2, "test\u0085", "est\u0085", true); + + check("....$.blah", flags3, "test\nblah", "test\nblah", true); + check(".....$.blah", flags3, "test\n\nblah", "test\n\nblah", true); + check("....$blah", flags3, "test\nblah", "!!!!", false); + check(".....$blah", flags3, "test\nblah", "!!!!", false); + + // Supplementary character test + String t = toSupplementaries("test"); + String b = toSupplementaries("blah"); + check("....$", flags1, t+"\n", t, true); + check("....$", flags1, t+"\r\n", t, true); + check(".....$", flags1, t+"\n", t+"\n", true); + check(".....$", flags1, t+"\u0085", t+"\u0085", true); + check("....$", flags1, t+"\u0085", t, true); + + check("....$", flags2, t+"\n", t, true); + check(".....$", flags2, t+"\n", t+"\n", true); + check(".....$", flags2, t+"\u0085", t+"\u0085", true); + check("....$", flags2, t+"\u0085", toSupplementaries("est\u0085"), true); + + check("....$."+b, flags3, t+"\n"+b, t+"\n"+b, true); + check(".....$."+b, flags3, t+"\n\n"+b, t+"\n\n"+b, true); + check("....$"+b, flags3, t+"\n"+b, "!!!!", false); + check(".....$"+b, flags3, t+"\n"+b, "!!!!", false); + + report("Dollar at End"); + } + + // This test is for 4711773 + private static void multilineDollarTest() throws Exception { + Pattern findCR = Pattern.compile("$", Pattern.MULTILINE); + Matcher matcher = findCR.matcher("first bit\nsecond bit"); + matcher.find(); + if (matcher.start(0) != 9) + failCount++; + matcher.find(); + if (matcher.start(0) != 20) + failCount++; + + // Supplementary character test + matcher = findCR.matcher(toSupplementaries("first bit\n second bit")); // double BMP chars + matcher.find(); + if (matcher.start(0) != 9*2) + failCount++; + matcher.find(); + if (matcher.start(0) != 20*2) + failCount++; + + report("Multiline Dollar"); + } + + private static void reluctantRepetitionTest() throws Exception { + Pattern p = Pattern.compile("1(\\s\\S+?){1,3}?[\\s,]2"); + check(p, "1 word word word 2", true); + check(p, "1 wor wo w 2", true); + check(p, "1 word word 2", true); + check(p, "1 word 2", true); + check(p, "1 wo w w 2", true); + check(p, "1 wo w 2", true); + check(p, "1 wor w 2", true); + + p = Pattern.compile("([a-z])+?c"); + Matcher m = p.matcher("ababcdefdec"); + check(m, "ababc"); + + // Supplementary character test + p = Pattern.compile(toSupplementaries("([a-z])+?c")); + m = p.matcher(toSupplementaries("ababcdefdec")); + check(m, toSupplementaries("ababc")); + + report("Reluctant Repetition"); + } + + private static void serializeTest() throws Exception { + String patternStr = "(b)"; + String matchStr = "b"; + Pattern pattern = Pattern.compile(patternStr); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(pattern); + oos.close(); + ObjectInputStream ois = new ObjectInputStream( + new ByteArrayInputStream(baos.toByteArray())); + Pattern serializedPattern = (Pattern)ois.readObject(); + ois.close(); + Matcher matcher = serializedPattern.matcher(matchStr); + if (!matcher.matches()) + failCount++; + if (matcher.groupCount() != 1) + failCount++; + + report("Serialization"); + } + + private static void gTest() { + Pattern pattern = Pattern.compile("\\G\\w"); + Matcher matcher = pattern.matcher("abc#x#x"); + matcher.find(); + matcher.find(); + matcher.find(); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("\\GA*"); + matcher = pattern.matcher("1A2AA3"); + matcher.find(); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("\\GA*"); + matcher = pattern.matcher("1A2AA3"); + if (!matcher.find(1)) + failCount++; + matcher.find(); + if (matcher.find()) + failCount++; + + report("\\G"); + } + + private static void zTest() { + Pattern pattern = Pattern.compile("foo\\Z"); + // Positives + check(pattern, "foo\u0085", true); + check(pattern, "foo\u2028", true); + check(pattern, "foo\u2029", true); + check(pattern, "foo\n", true); + check(pattern, "foo\r", true); + check(pattern, "foo\r\n", true); + // Negatives + check(pattern, "fooo", false); + check(pattern, "foo\n\r", false); + + pattern = Pattern.compile("foo\\Z", Pattern.UNIX_LINES); + // Positives + check(pattern, "foo", true); + check(pattern, "foo\n", true); + // Negatives + check(pattern, "foo\r", false); + check(pattern, "foo\u0085", false); + check(pattern, "foo\u2028", false); + check(pattern, "foo\u2029", false); + + report("\\Z"); + } + + private static void replaceFirstTest() { + Pattern pattern = Pattern.compile("(ab)(c*)"); + Matcher matcher = pattern.matcher("abccczzzabcczzzabccc"); + if (!matcher.replaceFirst("test").equals("testzzzabcczzzabccc")) + failCount++; + + matcher.reset("zzzabccczzzabcczzzabccczzz"); + if (!matcher.replaceFirst("test").equals("zzztestzzzabcczzzabccczzz")) + failCount++; + + matcher.reset("zzzabccczzzabcczzzabccczzz"); + String result = matcher.replaceFirst("$1"); + if (!result.equals("zzzabzzzabcczzzabccczzz")) + failCount++; + + matcher.reset("zzzabccczzzabcczzzabccczzz"); + result = matcher.replaceFirst("$2"); + if (!result.equals("zzzccczzzabcczzzabccczzz")) + failCount++; + + pattern = Pattern.compile("a*"); + matcher = pattern.matcher("aaaaaaaaaa"); + if (!matcher.replaceFirst("test").equals("test")) + failCount++; + + pattern = Pattern.compile("a+"); + matcher = pattern.matcher("zzzaaaaaaaaaa"); + if (!matcher.replaceFirst("test").equals("zzztest")) + failCount++; + + // Supplementary character test + pattern = Pattern.compile(toSupplementaries("(ab)(c*)")); + matcher = pattern.matcher(toSupplementaries("abccczzzabcczzzabccc")); + if (!matcher.replaceFirst(toSupplementaries("test")) + .equals(toSupplementaries("testzzzabcczzzabccc"))) + failCount++; + + matcher.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); + if (!matcher.replaceFirst(toSupplementaries("test")). + equals(toSupplementaries("zzztestzzzabcczzzabccczzz"))) + failCount++; + + matcher.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); + result = matcher.replaceFirst("$1"); + if (!result.equals(toSupplementaries("zzzabzzzabcczzzabccczzz"))) + failCount++; + + matcher.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); + result = matcher.replaceFirst("$2"); + if (!result.equals(toSupplementaries("zzzccczzzabcczzzabccczzz"))) + failCount++; + + pattern = Pattern.compile(toSupplementaries("a*")); + matcher = pattern.matcher(toSupplementaries("aaaaaaaaaa")); + if (!matcher.replaceFirst(toSupplementaries("test")).equals(toSupplementaries("test"))) + failCount++; + + pattern = Pattern.compile(toSupplementaries("a+")); + matcher = pattern.matcher(toSupplementaries("zzzaaaaaaaaaa")); + if (!matcher.replaceFirst(toSupplementaries("test")).equals(toSupplementaries("zzztest"))) + failCount++; + + report("Replace First"); + } + + private static void unixLinesTest() { + Pattern pattern = Pattern.compile(".*"); + Matcher matcher = pattern.matcher("aa\u2028blah"); + matcher.find(); + if (!matcher.group(0).equals("aa")) + failCount++; + + pattern = Pattern.compile(".*", Pattern.UNIX_LINES); + matcher = pattern.matcher("aa\u2028blah"); + matcher.find(); + if (!matcher.group(0).equals("aa\u2028blah")) + failCount++; + + pattern = Pattern.compile("[az]$", + Pattern.MULTILINE | Pattern.UNIX_LINES); + matcher = pattern.matcher("aa\u2028zz"); + check(matcher, "a\u2028", false); + + // Supplementary character test + pattern = Pattern.compile(".*"); + matcher = pattern.matcher(toSupplementaries("aa\u2028blah")); + matcher.find(); + if (!matcher.group(0).equals(toSupplementaries("aa"))) + failCount++; + + pattern = Pattern.compile(".*", Pattern.UNIX_LINES); + matcher = pattern.matcher(toSupplementaries("aa\u2028blah")); + matcher.find(); + if (!matcher.group(0).equals(toSupplementaries("aa\u2028blah"))) + failCount++; + + pattern = Pattern.compile(toSupplementaries("[az]$"), + Pattern.MULTILINE | Pattern.UNIX_LINES); + matcher = pattern.matcher(toSupplementaries("aa\u2028zz")); + check(matcher, toSupplementaries("a\u2028"), false); + + report("Unix Lines"); + } + + private static void commentsTest() { + int flags = Pattern.COMMENTS; + + Pattern pattern = Pattern.compile("aa \\# aa", flags); + Matcher matcher = pattern.matcher("aa#aa"); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa # blah", flags); + matcher = pattern.matcher("aa"); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa blah", flags); + matcher = pattern.matcher("aablah"); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa # blah blech ", flags); + matcher = pattern.matcher("aa"); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa # blah\n ", flags); + matcher = pattern.matcher("aa"); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa # blah\nbc # blech", flags); + matcher = pattern.matcher("aabc"); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa # blah\nbc# blech", flags); + matcher = pattern.matcher("aabc"); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa # blah\nbc\\# blech", flags); + matcher = pattern.matcher("aabc#blech"); + if (!matcher.matches()) + failCount++; + + // Supplementary character test + pattern = Pattern.compile(toSupplementaries("aa \\# aa"), flags); + matcher = pattern.matcher(toSupplementaries("aa#aa")); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile(toSupplementaries("aa # blah"), flags); + matcher = pattern.matcher(toSupplementaries("aa")); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile(toSupplementaries("aa blah"), flags); + matcher = pattern.matcher(toSupplementaries("aablah")); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile(toSupplementaries("aa # blah blech "), flags); + matcher = pattern.matcher(toSupplementaries("aa")); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile(toSupplementaries("aa # blah\n "), flags); + matcher = pattern.matcher(toSupplementaries("aa")); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile(toSupplementaries("aa # blah\nbc # blech"), flags); + matcher = pattern.matcher(toSupplementaries("aabc")); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile(toSupplementaries("aa # blah\nbc# blech"), flags); + matcher = pattern.matcher(toSupplementaries("aabc")); + if (!matcher.matches()) + failCount++; + + pattern = Pattern.compile(toSupplementaries("aa # blah\nbc\\# blech"), flags); + matcher = pattern.matcher(toSupplementaries("aabc#blech")); + if (!matcher.matches()) + failCount++; + + report("Comments"); + } + + private static void caseFoldingTest() { // bug 4504687 + int flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE; + Pattern pattern = Pattern.compile("aa", flags); + Matcher matcher = pattern.matcher("ab"); + if (matcher.matches()) + failCount++; + + pattern = Pattern.compile("aA", flags); + matcher = pattern.matcher("ab"); + if (matcher.matches()) + failCount++; + + pattern = Pattern.compile("aa", flags); + matcher = pattern.matcher("aB"); + if (matcher.matches()) + failCount++; + matcher = pattern.matcher("Ab"); + if (matcher.matches()) + failCount++; + + // ASCII "a" + // Latin-1 Supplement "a" + grave + // Cyrillic "a" + String[] patterns = new String[] { + //single + "a", "\u00e0", "\u0430", + //slice + "ab", "\u00e0\u00e1", "\u0430\u0431", + //class single + "[a]", "[\u00e0]", "[\u0430]", + //class range + "[a-b]", "[\u00e0-\u00e5]", "[\u0430-\u0431]", + //back reference + "(a)\\1", "(\u00e0)\\1", "(\u0430)\\1" + }; + + String[] texts = new String[] { + "A", "\u00c0", "\u0410", + "AB", "\u00c0\u00c1", "\u0410\u0411", + "A", "\u00c0", "\u0410", + "B", "\u00c2", "\u0411", + "aA", "\u00e0\u00c0", "\u0430\u0410" + }; + + boolean[] expected = new boolean[] { + true, false, false, + true, false, false, + true, false, false, + true, false, false, + true, false, false + }; + + flags = Pattern.CASE_INSENSITIVE; + for (int i = 0; i < patterns.length; i++) { + pattern = Pattern.compile(patterns[i], flags); + matcher = pattern.matcher(texts[i]); + if (matcher.matches() != expected[i]) { + System.out.println("<1> Failed at " + i); + failCount++; + } + } + + flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE; + for (int i = 0; i < patterns.length; i++) { + pattern = Pattern.compile(patterns[i], flags); + matcher = pattern.matcher(texts[i]); + if (!matcher.matches()) { + System.out.println("<2> Failed at " + i); + failCount++; + } + } + // flag unicode_case alone should do nothing + flags = Pattern.UNICODE_CASE; + for (int i = 0; i < patterns.length; i++) { + pattern = Pattern.compile(patterns[i], flags); + matcher = pattern.matcher(texts[i]); + if (matcher.matches()) { + System.out.println("<3> Failed at " + i); + failCount++; + } + } + + // Special cases: i, I, u+0131 and u+0130 + flags = Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE; + pattern = Pattern.compile("[h-j]+", flags); + if (!pattern.matcher("\u0131\u0130").matches()) + failCount++; + report("Case Folding"); + } + + private static void appendTest() { + Pattern pattern = Pattern.compile("(ab)(cd)"); + Matcher matcher = pattern.matcher("abcd"); + String result = matcher.replaceAll("$2$1"); + if (!result.equals("cdab")) + failCount++; + + String s1 = "Swap all: first = 123, second = 456"; + String s2 = "Swap one: first = 123, second = 456"; + String r = "$3$2$1"; + pattern = Pattern.compile("([a-z]+)( *= *)([0-9]+)"); + matcher = pattern.matcher(s1); + + result = matcher.replaceAll(r); + if (!result.equals("Swap all: 123 = first, 456 = second")) + failCount++; + + matcher = pattern.matcher(s2); + + if (matcher.find()) { + StringBuffer sb = new StringBuffer(); + matcher.appendReplacement(sb, r); + matcher.appendTail(sb); + result = sb.toString(); + if (!result.equals("Swap one: 123 = first, second = 456")) + failCount++; + } + + // Supplementary character test + pattern = Pattern.compile(toSupplementaries("(ab)(cd)")); + matcher = pattern.matcher(toSupplementaries("abcd")); + result = matcher.replaceAll("$2$1"); + if (!result.equals(toSupplementaries("cdab"))) + failCount++; + + s1 = toSupplementaries("Swap all: first = 123, second = 456"); + s2 = toSupplementaries("Swap one: first = 123, second = 456"); + r = toSupplementaries("$3$2$1"); + pattern = Pattern.compile(toSupplementaries("([a-z]+)( *= *)([0-9]+)")); + matcher = pattern.matcher(s1); + + result = matcher.replaceAll(r); + if (!result.equals(toSupplementaries("Swap all: 123 = first, 456 = second"))) + failCount++; + + matcher = pattern.matcher(s2); + + if (matcher.find()) { + StringBuffer sb = new StringBuffer(); + matcher.appendReplacement(sb, r); + matcher.appendTail(sb); + result = sb.toString(); + if (!result.equals(toSupplementaries("Swap one: 123 = first, second = 456"))) + failCount++; + } + report("Append"); + } + + private static void splitTest() { + Pattern pattern = Pattern.compile(":"); + String[] result = pattern.split("foo:and:boo", 2); + if (!result[0].equals("foo")) + failCount++; + if (!result[1].equals("and:boo")) + failCount++; + // Supplementary character test + Pattern patternX = Pattern.compile(toSupplementaries("X")); + result = patternX.split(toSupplementaries("fooXandXboo"), 2); + if (!result[0].equals(toSupplementaries("foo"))) + failCount++; + if (!result[1].equals(toSupplementaries("andXboo"))) + failCount++; + + CharBuffer cb = CharBuffer.allocate(100); + cb.put("foo:and:boo"); + cb.flip(); + result = pattern.split(cb); + if (!result[0].equals("foo")) + failCount++; + if (!result[1].equals("and")) + failCount++; + if (!result[2].equals("boo")) + failCount++; + + // Supplementary character test + CharBuffer cbs = CharBuffer.allocate(100); + cbs.put(toSupplementaries("fooXandXboo")); + cbs.flip(); + result = patternX.split(cbs); + if (!result[0].equals(toSupplementaries("foo"))) + failCount++; + if (!result[1].equals(toSupplementaries("and"))) + failCount++; + if (!result[2].equals(toSupplementaries("boo"))) + failCount++; + + String source = "0123456789"; + for (int limit=-2; limit<3; limit++) { + for (int x=0; x<10; x++) { + result = source.split(Integer.toString(x), limit); + int expectedLength = limit < 1 ? 2 : limit; + + if ((limit == 0) && (x == 9)) { + // expected dropping of "" + if (result.length != 1) + failCount++; + if (!result[0].equals("012345678")) { + failCount++; + } + } else { + if (result.length != expectedLength) { + failCount++; + } + if (!result[0].equals(source.substring(0,x))) { + if (limit != 1) { + failCount++; + } else { + if (!result[0].equals(source.substring(0,10))) { + failCount++; + } + } + } + if (expectedLength > 1) { // Check segment 2 + if (!result[1].equals(source.substring(x+1,10))) + failCount++; + } + } + } + } + // Check the case for no match found + for (int limit=-2; limit<3; limit++) { + result = source.split("e", limit); + if (result.length != 1) + failCount++; + if (!result[0].equals(source)) + failCount++; + } + // Check the case for limit == 0, source = ""; + source = ""; + result = source.split("e", 0); + if (result.length != 1) + failCount++; + if (!result[0].equals(source)) + failCount++; + + report("Split"); + } + + private static void negationTest() { + Pattern pattern = Pattern.compile("[\\[@^]+"); + Matcher matcher = pattern.matcher("@@@@[[[[^^^^"); + if (!matcher.find()) + failCount++; + if (!matcher.group(0).equals("@@@@[[[[^^^^")) + failCount++; + pattern = Pattern.compile("[@\\[^]+"); + matcher = pattern.matcher("@@@@[[[[^^^^"); + if (!matcher.find()) + failCount++; + if (!matcher.group(0).equals("@@@@[[[[^^^^")) + failCount++; + pattern = Pattern.compile("[@\\[^@]+"); + matcher = pattern.matcher("@@@@[[[[^^^^"); + if (!matcher.find()) + failCount++; + if (!matcher.group(0).equals("@@@@[[[[^^^^")) + failCount++; + + pattern = Pattern.compile("\\)"); + matcher = pattern.matcher("xxx)xxx"); + if (!matcher.find()) + failCount++; + + report("Negation"); + } + + private static void ampersandTest() { + Pattern pattern = Pattern.compile("[&@]+"); + check(pattern, "@@@@&&&&", true); + + pattern = Pattern.compile("[@&]+"); + check(pattern, "@@@@&&&&", true); + + pattern = Pattern.compile("[@\\&]+"); + check(pattern, "@@@@&&&&", true); + + report("Ampersand"); + } + + private static void octalTest() throws Exception { + Pattern pattern = Pattern.compile("\\u0007"); + Matcher matcher = pattern.matcher("\u0007"); + if (!matcher.matches()) + failCount++; + pattern = Pattern.compile("\\07"); + matcher = pattern.matcher("\u0007"); + if (!matcher.matches()) + failCount++; + pattern = Pattern.compile("\\007"); + matcher = pattern.matcher("\u0007"); + if (!matcher.matches()) + failCount++; + pattern = Pattern.compile("\\0007"); + matcher = pattern.matcher("\u0007"); + if (!matcher.matches()) + failCount++; + pattern = Pattern.compile("\\040"); + matcher = pattern.matcher("\u0020"); + if (!matcher.matches()) + failCount++; + pattern = Pattern.compile("\\0403"); + matcher = pattern.matcher("\u00203"); + if (!matcher.matches()) + failCount++; + pattern = Pattern.compile("\\0103"); + matcher = pattern.matcher("\u0043"); + if (!matcher.matches()) + failCount++; + + report("Octal"); + } + + private static void longPatternTest() throws Exception { + try { + Pattern pattern = Pattern.compile( + "a 32-character-long pattern xxxx"); + pattern = Pattern.compile("a 33-character-long pattern xxxxx"); + pattern = Pattern.compile("a thirty four character long regex"); + StringBuffer patternToBe = new StringBuffer(101); + for (int i=0; i<100; i++) + patternToBe.append((char)(97 + i%26)); + pattern = Pattern.compile(patternToBe.toString()); + } catch (PatternSyntaxException e) { + failCount++; + } + + // Supplementary character test + try { + Pattern pattern = Pattern.compile( + toSupplementaries("a 32-character-long pattern xxxx")); + pattern = Pattern.compile(toSupplementaries("a 33-character-long pattern xxxxx")); + pattern = Pattern.compile(toSupplementaries("a thirty four character long regex")); + StringBuffer patternToBe = new StringBuffer(101*2); + for (int i=0; i<100; i++) + patternToBe.append(Character.toChars(Character.MIN_SUPPLEMENTARY_CODE_POINT + + 97 + i%26)); + pattern = Pattern.compile(patternToBe.toString()); + } catch (PatternSyntaxException e) { + failCount++; + } + report("LongPattern"); + } + + private static void group0Test() throws Exception { + Pattern pattern = Pattern.compile("(tes)ting"); + Matcher matcher = pattern.matcher("testing"); + check(matcher, "testing"); + + matcher.reset("testing"); + if (matcher.lookingAt()) { + if (!matcher.group(0).equals("testing")) + failCount++; + } else { + failCount++; + } + + matcher.reset("testing"); + if (matcher.matches()) { + if (!matcher.group(0).equals("testing")) + failCount++; + } else { + failCount++; + } + + pattern = Pattern.compile("(tes)ting"); + matcher = pattern.matcher("testing"); + if (matcher.lookingAt()) { + if (!matcher.group(0).equals("testing")) + failCount++; + } else { + failCount++; + } + + pattern = Pattern.compile("^(tes)ting"); + matcher = pattern.matcher("testing"); + if (matcher.matches()) { + if (!matcher.group(0).equals("testing")) + failCount++; + } else { + failCount++; + } + + // Supplementary character test + pattern = Pattern.compile(toSupplementaries("(tes)ting")); + matcher = pattern.matcher(toSupplementaries("testing")); + check(matcher, toSupplementaries("testing")); + + matcher.reset(toSupplementaries("testing")); + if (matcher.lookingAt()) { + if (!matcher.group(0).equals(toSupplementaries("testing"))) + failCount++; + } else { + failCount++; + } + + matcher.reset(toSupplementaries("testing")); + if (matcher.matches()) { + if (!matcher.group(0).equals(toSupplementaries("testing"))) + failCount++; + } else { + failCount++; + } + + pattern = Pattern.compile(toSupplementaries("(tes)ting")); + matcher = pattern.matcher(toSupplementaries("testing")); + if (matcher.lookingAt()) { + if (!matcher.group(0).equals(toSupplementaries("testing"))) + failCount++; + } else { + failCount++; + } + + pattern = Pattern.compile(toSupplementaries("^(tes)ting")); + matcher = pattern.matcher(toSupplementaries("testing")); + if (matcher.matches()) { + if (!matcher.group(0).equals(toSupplementaries("testing"))) + failCount++; + } else { + failCount++; + } + + report("Group0"); + } + + private static void findIntTest() throws Exception { + Pattern p = Pattern.compile("blah"); + Matcher m = p.matcher("zzzzblahzzzzzblah"); + boolean result = m.find(2); + if (!result) + failCount++; + + p = Pattern.compile("$"); + m = p.matcher("1234567890"); + result = m.find(10); + if (!result) + failCount++; + try { + result = m.find(11); + failCount++; + } catch (IndexOutOfBoundsException e) { + // correct result + } + + // Supplementary character test + p = Pattern.compile(toSupplementaries("blah")); + m = p.matcher(toSupplementaries("zzzzblahzzzzzblah")); + result = m.find(2); + if (!result) + failCount++; + + report("FindInt"); + } + + private static void emptyPatternTest() throws Exception { + Pattern p = Pattern.compile(""); + Matcher m = p.matcher("foo"); + + // Should find empty pattern at beginning of input + boolean result = m.find(); + if (result != true) + failCount++; + if (m.start() != 0) + failCount++; + + // Should not match entire input if input is not empty + m.reset(); + result = m.matches(); + if (result == true) + failCount++; + + try { + m.start(0); + failCount++; + } catch (IllegalStateException e) { + // Correct result + } + + // Should match entire input if input is empty + m.reset(""); + result = m.matches(); + if (result != true) + failCount++; + + result = Pattern.matches("", ""); + if (result != true) + failCount++; + + result = Pattern.matches("", "foo"); + if (result == true) + failCount++; + report("EmptyPattern"); + } + + private static void charClassTest() throws Exception { + Pattern pattern = Pattern.compile("blah[ab]]blech"); + check(pattern, "blahb]blech", true); + + pattern = Pattern.compile("[abc[def]]"); + check(pattern, "b", true); + + // Supplementary character tests + pattern = Pattern.compile(toSupplementaries("blah[ab]]blech")); + check(pattern, toSupplementaries("blahb]blech"), true); + + pattern = Pattern.compile(toSupplementaries("[abc[def]]")); + check(pattern, toSupplementaries("b"), true); + + try { + // u00ff when UNICODE_CASE + pattern = Pattern.compile("[ab\u00ffcd]", + Pattern.CASE_INSENSITIVE| + Pattern.UNICODE_CASE); + check(pattern, "ab\u00ffcd", true); + check(pattern, "Ab\u0178Cd", true); + + // u00b5 when UNICODE_CASE + pattern = Pattern.compile("[ab\u00b5cd]", + Pattern.CASE_INSENSITIVE| + Pattern.UNICODE_CASE); + check(pattern, "ab\u00b5cd", true); + check(pattern, "Ab\u039cCd", true); + } catch (Exception e) { failCount++; } + + /* Special cases + (1)LatinSmallLetterLongS u+017f + (2)LatinSmallLetterDotlessI u+0131 + (3)LatineCapitalLetterIWithDotAbove u+0130 + (4)KelvinSign u+212a + (5)AngstromSign u+212b + */ + int flags = Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE; + pattern = Pattern.compile("[sik\u00c5]+", flags); + if (!pattern.matcher("\u017f\u0130\u0131\u212a\u212b").matches()) + failCount++; + + report("CharClass"); + } + + private static void caretTest() throws Exception { + Pattern pattern = Pattern.compile("\\w*"); + Matcher matcher = pattern.matcher("a#bc#def##g"); + check(matcher, "a"); + check(matcher, ""); + check(matcher, "bc"); + check(matcher, ""); + check(matcher, "def"); + check(matcher, ""); + check(matcher, ""); + check(matcher, "g"); + check(matcher, ""); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("^\\w*"); + matcher = pattern.matcher("a#bc#def##g"); + check(matcher, "a"); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("\\w"); + matcher = pattern.matcher("abc##x"); + check(matcher, "a"); + check(matcher, "b"); + check(matcher, "c"); + check(matcher, "x"); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("^\\w"); + matcher = pattern.matcher("abc##x"); + check(matcher, "a"); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("\\A\\p{Alpha}{3}"); + matcher = pattern.matcher("abcdef-ghi\njklmno"); + check(matcher, "abc"); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("^\\p{Alpha}{3}", Pattern.MULTILINE); + matcher = pattern.matcher("abcdef-ghi\njklmno"); + check(matcher, "abc"); + check(matcher, "jkl"); + if (matcher.find()) + failCount++; + + pattern = Pattern.compile("^", Pattern.MULTILINE); + matcher = pattern.matcher("this is some text"); + String result = matcher.replaceAll("X"); + if (!result.equals("Xthis is some text")) + failCount++; + + pattern = Pattern.compile("^"); + matcher = pattern.matcher("this is some text"); + result = matcher.replaceAll("X"); + if (!result.equals("Xthis is some text")) + failCount++; + + pattern = Pattern.compile("^", Pattern.MULTILINE | Pattern.UNIX_LINES); + matcher = pattern.matcher("this is some text\n"); + result = matcher.replaceAll("X"); + if (!result.equals("Xthis is some text\n")) + failCount++; + + report("Caret"); + } + + private static void groupCaptureTest() throws Exception { + // Independent group + Pattern pattern = Pattern.compile("x+(?>y+)z+"); + Matcher matcher = pattern.matcher("xxxyyyzzz"); + matcher.find(); + try { + String blah = matcher.group(1); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Good result + } + // Pure group + pattern = Pattern.compile("x+(?:y+)z+"); + matcher = pattern.matcher("xxxyyyzzz"); + matcher.find(); + try { + String blah = matcher.group(1); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Good result + } + + // Supplementary character tests + // Independent group + pattern = Pattern.compile(toSupplementaries("x+(?>y+)z+")); + matcher = pattern.matcher(toSupplementaries("xxxyyyzzz")); + matcher.find(); + try { + String blah = matcher.group(1); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Good result + } + // Pure group + pattern = Pattern.compile(toSupplementaries("x+(?:y+)z+")); + matcher = pattern.matcher(toSupplementaries("xxxyyyzzz")); + matcher.find(); + try { + String blah = matcher.group(1); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Good result + } + + report("GroupCapture"); + } + + private static void backRefTest() throws Exception { + Pattern pattern = Pattern.compile("(a*)bc\\1"); + check(pattern, "zzzaabcazzz", true); + + pattern = Pattern.compile("(a*)bc\\1"); + check(pattern, "zzzaabcaazzz", true); + + pattern = Pattern.compile("(abc)(def)\\1"); + check(pattern, "abcdefabc", true); + + pattern = Pattern.compile("(abc)(def)\\3"); + check(pattern, "abcdefabc", false); + + try { + for (int i = 1; i < 10; i++) { + // Make sure backref 1-9 are always accepted + pattern = Pattern.compile("abcdef\\" + i); + // and fail to match if the target group does not exit + check(pattern, "abcdef", false); + } + } catch(PatternSyntaxException e) { + failCount++; + } + + pattern = Pattern.compile("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)\\11"); + check(pattern, "abcdefghija", false); + check(pattern, "abcdefghija1", true); + + pattern = Pattern.compile("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11"); + check(pattern, "abcdefghijkk", true); + + pattern = Pattern.compile("(a)bcdefghij\\11"); + check(pattern, "abcdefghija1", true); + + // Supplementary character tests + pattern = Pattern.compile(toSupplementaries("(a*)bc\\1")); + check(pattern, toSupplementaries("zzzaabcazzz"), true); + + pattern = Pattern.compile(toSupplementaries("(a*)bc\\1")); + check(pattern, toSupplementaries("zzzaabcaazzz"), true); + + pattern = Pattern.compile(toSupplementaries("(abc)(def)\\1")); + check(pattern, toSupplementaries("abcdefabc"), true); + + pattern = Pattern.compile(toSupplementaries("(abc)(def)\\3")); + check(pattern, toSupplementaries("abcdefabc"), false); + + pattern = Pattern.compile(toSupplementaries("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)\\11")); + check(pattern, toSupplementaries("abcdefghija"), false); + check(pattern, toSupplementaries("abcdefghija1"), true); + + pattern = Pattern.compile(toSupplementaries("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11")); + check(pattern, toSupplementaries("abcdefghijkk"), true); + + report("BackRef"); + } + + /** + * Unicode Technical Report #18, section 2.6 End of Line + * There is no empty line to be matched in the sequence \u000D\u000A + * but there is an empty line in the sequence \u000A\u000D. + */ + private static void anchorTest() throws Exception { + Pattern p = Pattern.compile("^.*$", Pattern.MULTILINE); + Matcher m = p.matcher("blah1\r\nblah2"); + m.find(); + m.find(); + if (!m.group().equals("blah2")) + failCount++; + + m.reset("blah1\n\rblah2"); + m.find(); + m.find(); + m.find(); + if (!m.group().equals("blah2")) + failCount++; + + // Test behavior of $ with \r\n at end of input + p = Pattern.compile(".+$"); + m = p.matcher("blah1\r\n"); + if (!m.find()) + failCount++; + if (!m.group().equals("blah1")) + failCount++; + if (m.find()) + failCount++; + + // Test behavior of $ with \r\n at end of input in multiline + p = Pattern.compile(".+$", Pattern.MULTILINE); + m = p.matcher("blah1\r\n"); + if (!m.find()) + failCount++; + if (m.find()) + failCount++; + + // Test for $ recognition of \u0085 for bug 4527731 + p = Pattern.compile(".+$", Pattern.MULTILINE); + m = p.matcher("blah1\u0085"); + if (!m.find()) + failCount++; + + // Supplementary character test + p = Pattern.compile("^.*$", Pattern.MULTILINE); + m = p.matcher(toSupplementaries("blah1\r\nblah2")); + m.find(); + m.find(); + if (!m.group().equals(toSupplementaries("blah2"))) + failCount++; + + m.reset(toSupplementaries("blah1\n\rblah2")); + m.find(); + m.find(); + m.find(); + if (!m.group().equals(toSupplementaries("blah2"))) + failCount++; + + // Test behavior of $ with \r\n at end of input + p = Pattern.compile(".+$"); + m = p.matcher(toSupplementaries("blah1\r\n")); + if (!m.find()) + failCount++; + if (!m.group().equals(toSupplementaries("blah1"))) + failCount++; + if (m.find()) + failCount++; + + // Test behavior of $ with \r\n at end of input in multiline + p = Pattern.compile(".+$", Pattern.MULTILINE); + m = p.matcher(toSupplementaries("blah1\r\n")); + if (!m.find()) + failCount++; + if (m.find()) + failCount++; + + // Test for $ recognition of \u0085 for bug 4527731 + p = Pattern.compile(".+$", Pattern.MULTILINE); + m = p.matcher(toSupplementaries("blah1\u0085")); + if (!m.find()) + failCount++; + + report("Anchors"); + } + + /** + * A basic sanity test of Matcher.lookingAt(). + */ + private static void lookingAtTest() throws Exception { + Pattern p = Pattern.compile("(ab)(c*)"); + Matcher m = p.matcher("abccczzzabcczzzabccc"); + + if (!m.lookingAt()) + failCount++; + + if (!m.group().equals(m.group(0))) + failCount++; + + m = p.matcher("zzzabccczzzabcczzzabccczzz"); + if (m.lookingAt()) + failCount++; + + // Supplementary character test + p = Pattern.compile(toSupplementaries("(ab)(c*)")); + m = p.matcher(toSupplementaries("abccczzzabcczzzabccc")); + + if (!m.lookingAt()) + failCount++; + + if (!m.group().equals(m.group(0))) + failCount++; + + m = p.matcher(toSupplementaries("zzzabccczzzabcczzzabccczzz")); + if (m.lookingAt()) + failCount++; + + report("Looking At"); + } + + /** + * A basic sanity test of Matcher.matches(). + */ + private static void matchesTest() throws Exception { + // matches() + Pattern p = Pattern.compile("ulb(c*)"); + Matcher m = p.matcher("ulbcccccc"); + if (!m.matches()) + failCount++; + + // find() but not matches() + m.reset("zzzulbcccccc"); + if (m.matches()) + failCount++; + + // lookingAt() but not matches() + m.reset("ulbccccccdef"); + if (m.matches()) + failCount++; + + // matches() + p = Pattern.compile("a|ad"); + m = p.matcher("ad"); + if (!m.matches()) + failCount++; + + // Supplementary character test + // matches() + p = Pattern.compile(toSupplementaries("ulb(c*)")); + m = p.matcher(toSupplementaries("ulbcccccc")); + if (!m.matches()) + failCount++; + + // find() but not matches() + m.reset(toSupplementaries("zzzulbcccccc")); + if (m.matches()) + failCount++; + + // lookingAt() but not matches() + m.reset(toSupplementaries("ulbccccccdef")); + if (m.matches()) + failCount++; + + // matches() + p = Pattern.compile(toSupplementaries("a|ad")); + m = p.matcher(toSupplementaries("ad")); + if (!m.matches()) + failCount++; + + report("Matches"); + } + + /** + * A basic sanity test of Pattern.matches(). + */ + private static void patternMatchesTest() throws Exception { + // matches() + if (!Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("ulbcccccc"))) + failCount++; + + // find() but not matches() + if (Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("zzzulbcccccc"))) + failCount++; + + // lookingAt() but not matches() + if (Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("ulbccccccdef"))) + failCount++; + + // Supplementary character test + // matches() + if (!Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("ulbcccccc"))) + failCount++; + + // find() but not matches() + if (Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("zzzulbcccccc"))) + failCount++; + + // lookingAt() but not matches() + if (Pattern.matches(toSupplementaries("ulb(c*)"), + toSupplementaries("ulbccccccdef"))) + failCount++; + + report("Pattern Matches"); + } + + /** + * Canonical equivalence testing. Tests the ability of the engine + * to match sequences that are not explicitly specified in the + * pattern when they are considered equivalent by the Unicode Standard. + */ + private static void ceTest() throws Exception { + // Decomposed char outside char classes + Pattern p = Pattern.compile("testa\u030a", Pattern.CANON_EQ); + Matcher m = p.matcher("test\u00e5"); + if (!m.matches()) + failCount++; + + m.reset("testa\u030a"); + if (!m.matches()) + failCount++; + + // Composed char outside char classes + p = Pattern.compile("test\u00e5", Pattern.CANON_EQ); + m = p.matcher("test\u00e5"); + if (!m.matches()) + failCount++; + + m.reset("testa\u030a"); + if (!m.find()) + failCount++; + + // Decomposed char inside a char class + p = Pattern.compile("test[abca\u030a]", Pattern.CANON_EQ); + m = p.matcher("test\u00e5"); + if (!m.find()) + failCount++; + + m.reset("testa\u030a"); + if (!m.find()) + failCount++; + + // Composed char inside a char class + p = Pattern.compile("test[abc\u00e5def\u00e0]", Pattern.CANON_EQ); + m = p.matcher("test\u00e5"); + if (!m.find()) + failCount++; + + m.reset("testa\u0300"); + if (!m.find()) + failCount++; + + m.reset("testa\u030a"); + if (!m.find()) + failCount++; + + // Marks that cannot legally change order and be equivalent + p = Pattern.compile("testa\u0308\u0300", Pattern.CANON_EQ); + check(p, "testa\u0308\u0300", true); + check(p, "testa\u0300\u0308", false); + + // Marks that can legally change order and be equivalent + p = Pattern.compile("testa\u0308\u0323", Pattern.CANON_EQ); + check(p, "testa\u0308\u0323", true); + check(p, "testa\u0323\u0308", true); + + // Test all equivalences of the sequence a\u0308\u0323\u0300 + p = Pattern.compile("testa\u0308\u0323\u0300", Pattern.CANON_EQ); + check(p, "testa\u0308\u0323\u0300", true); + check(p, "testa\u0323\u0308\u0300", true); + check(p, "testa\u0308\u0300\u0323", true); + check(p, "test\u00e4\u0323\u0300", true); + check(p, "test\u00e4\u0300\u0323", true); + + /* + * The following canonical equivalence tests don't work. Bug id: 4916384. + * + // Decomposed hangul (jamos) + p = Pattern.compile("\u1100\u1161", Pattern.CANON_EQ); + m = p.matcher("\u1100\u1161"); + if (!m.matches()) + failCount++; + + m.reset("\uac00"); + if (!m.matches()) + failCount++; + + // Composed hangul + p = Pattern.compile("\uac00", Pattern.CANON_EQ); + m = p.matcher("\u1100\u1161"); + if (!m.matches()) + failCount++; + + m.reset("\uac00"); + if (!m.matches()) + failCount++; + + // Decomposed supplementary outside char classes + p = Pattern.compile("test\ud834\uddbc\ud834\udd6f", Pattern.CANON_EQ); + m = p.matcher("test\ud834\uddc0"); + if (!m.matches()) + failCount++; + + m.reset("test\ud834\uddbc\ud834\udd6f"); + if (!m.matches()) + failCount++; + + // Composed supplementary outside char classes + p = Pattern.compile("test\ud834\uddc0", Pattern.CANON_EQ); + m.reset("test\ud834\uddbc\ud834\udd6f"); + if (!m.matches()) + failCount++; + + m = p.matcher("test\ud834\uddc0"); + if (!m.matches()) + failCount++; + + */ + + report("Canonical Equivalence"); + } + + /** + * A basic sanity test of Matcher.replaceAll(). + */ + private static void globalSubstitute() throws Exception { + // Global substitution with a literal + Pattern p = Pattern.compile("(ab)(c*)"); + Matcher m = p.matcher("abccczzzabcczzzabccc"); + if (!m.replaceAll("test").equals("testzzztestzzztest")) + failCount++; + + m.reset("zzzabccczzzabcczzzabccczzz"); + if (!m.replaceAll("test").equals("zzztestzzztestzzztestzzz")) + failCount++; + + // Global substitution with groups + m.reset("zzzabccczzzabcczzzabccczzz"); + String result = m.replaceAll("$1"); + if (!result.equals("zzzabzzzabzzzabzzz")) + failCount++; + + // Supplementary character test + // Global substitution with a literal + p = Pattern.compile(toSupplementaries("(ab)(c*)")); + m = p.matcher(toSupplementaries("abccczzzabcczzzabccc")); + if (!m.replaceAll(toSupplementaries("test")). + equals(toSupplementaries("testzzztestzzztest"))) + failCount++; + + m.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); + if (!m.replaceAll(toSupplementaries("test")). + equals(toSupplementaries("zzztestzzztestzzztestzzz"))) + failCount++; + + // Global substitution with groups + m.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz")); + result = m.replaceAll("$1"); + if (!result.equals(toSupplementaries("zzzabzzzabzzzabzzz"))) + failCount++; + + report("Global Substitution"); + } + + /** + * Tests the usage of Matcher.appendReplacement() with literal + * and group substitutions. + */ + private static void stringbufferSubstitute() throws Exception { + // SB substitution with literal + String blah = "zzzblahzzz"; + Pattern p = Pattern.compile("blah"); + Matcher m = p.matcher(blah); + StringBuffer result = new StringBuffer(); + try { + m.appendReplacement(result, "blech"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "blech"); + if (!result.toString().equals("zzzblech")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzblechzzz")) + failCount++; + + // SB substitution with groups + blah = "zzzabcdzzz"; + p = Pattern.compile("(ab)(cd)*"); + m = p.matcher(blah); + result = new StringBuffer(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals("zzzab")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabzzz")) + failCount++; + + // SB substitution with 3 groups + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuffer(); + try { + m.appendReplacement(result, "$1w$2w$3"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1w$2w$3"); + if (!result.toString().equals("zzzabwcdwef")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabwcdwefzzz")) + failCount++; + + // SB substitution with groups and three matches + // skipping middle match + blah = "zzzabcdzzzabcddzzzabcdzzz"; + p = Pattern.compile("(ab)(cd*)"); + m = p.matcher(blah); + result = new StringBuffer(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals("zzzab")) + failCount++; + + m.find(); + m.find(); + m.appendReplacement(result, "$2"); + if (!result.toString().equals("zzzabzzzabcddzzzcd")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabzzzabcddzzzcdzzz")) + failCount++; + + // Check to make sure escaped $ is ignored + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + m.appendReplacement(result, "$1w\\$2w$3"); + if (!result.toString().equals("zzzabw$2wef")) + failCount++; + + m.appendTail(result); + if (!result.toString().equals("zzzabw$2wefzzz")) + failCount++; + + // Check to make sure a reference to nonexistent group causes error + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + try { + m.appendReplacement(result, "$1w$5w$3"); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Correct result + } + + // Check double digit group references + blah = "zzz123456789101112zzz"; + p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + m.appendReplacement(result, "$1w$11w$3"); + if (!result.toString().equals("zzz1w11w3")) + failCount++; + + // Check to make sure it backs off $15 to $1 if only three groups + blah = "zzzabcdcdefzzz"; + p = Pattern.compile("(ab)(cd)*(ef)"); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + m.appendReplacement(result, "$1w$15w$3"); + if (!result.toString().equals("zzzabwab5wef")) + failCount++; + + + // Supplementary character test + // SB substitution with literal + blah = toSupplementaries("zzzblahzzz"); + p = Pattern.compile(toSupplementaries("blah")); + m = p.matcher(blah); + result = new StringBuffer(); + try { + m.appendReplacement(result, toSupplementaries("blech")); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, toSupplementaries("blech")); + if (!result.toString().equals(toSupplementaries("zzzblech"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzblechzzz"))) + failCount++; + + // SB substitution with groups + blah = toSupplementaries("zzzabcdzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*")); + m = p.matcher(blah); + result = new StringBuffer(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals(toSupplementaries("zzzab"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabzzz"))) + failCount++; + + // SB substitution with 3 groups + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuffer(); + try { + m.appendReplacement(result, toSupplementaries("$1w$2w$3")); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, toSupplementaries("$1w$2w$3")); + if (!result.toString().equals(toSupplementaries("zzzabwcdwef"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabwcdwefzzz"))) + failCount++; + + // SB substitution with groups and three matches + // skipping middle match + blah = toSupplementaries("zzzabcdzzzabcddzzzabcdzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd*)")); + m = p.matcher(blah); + result = new StringBuffer(); + try { + m.appendReplacement(result, "$1"); + failCount++; + } catch (IllegalStateException e) { + } + m.find(); + m.appendReplacement(result, "$1"); + if (!result.toString().equals(toSupplementaries("zzzab"))) + failCount++; + + m.find(); + m.find(); + m.appendReplacement(result, "$2"); + if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcd"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcdzzz"))) + failCount++; + + // Check to make sure escaped $ is ignored + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + m.appendReplacement(result, toSupplementaries("$1w\\$2w$3")); + if (!result.toString().equals(toSupplementaries("zzzabw$2wef"))) + failCount++; + + m.appendTail(result); + if (!result.toString().equals(toSupplementaries("zzzabw$2wefzzz"))) + failCount++; + + // Check to make sure a reference to nonexistent group causes error + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + try { + m.appendReplacement(result, toSupplementaries("$1w$5w$3")); + failCount++; + } catch (IndexOutOfBoundsException ioobe) { + // Correct result + } + + // Check double digit group references + blah = toSupplementaries("zzz123456789101112zzz"); + p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)"); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + m.appendReplacement(result, toSupplementaries("$1w$11w$3")); + if (!result.toString().equals(toSupplementaries("zzz1w11w3"))) + failCount++; + + // Check to make sure it backs off $15 to $1 if only three groups + blah = toSupplementaries("zzzabcdcdefzzz"); + p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)")); + m = p.matcher(blah); + result = new StringBuffer(); + m.find(); + m.appendReplacement(result, toSupplementaries("$1w$15w$3")); + if (!result.toString().equals(toSupplementaries("zzzabwab5wef"))) + failCount++; + + // Check nothing has been appended into the output buffer if + // the replacement string triggers IllegalArgumentException. + p = Pattern.compile("(abc)"); + m = p.matcher("abcd"); + result = new StringBuffer(); + m.find(); + try { + m.appendReplacement(result, ("xyz$g")); + failCount++; + } catch (IllegalArgumentException iae) { + if (result.length() != 0) + failCount++; + } + + report("SB Substitution"); + } + + /* + * 5 groups of characters are created to make a substitution string. + * A base string will be created including random lead chars, the + * substitution string, and random trailing chars. + * A pattern containing the 5 groups is searched for and replaced with: + * random group + random string + random group. + * The results are checked for correctness. + */ + private static void substitutionBasher() { + for (int runs = 0; runs<1000; runs++) { + // Create a base string to work in + int leadingChars = generator.nextInt(10); + StringBuffer baseBuffer = new StringBuffer(100); + String leadingString = getRandomAlphaString(leadingChars); + baseBuffer.append(leadingString); + + // Create 5 groups of random number of random chars + // Create the string to substitute + // Create the pattern string to search for + StringBuffer bufferToSub = new StringBuffer(25); + StringBuffer bufferToPat = new StringBuffer(50); + String[] groups = new String[5]; + for(int i=0; i<5; i++) { + int aGroupSize = generator.nextInt(5)+1; + groups[i] = getRandomAlphaString(aGroupSize); + bufferToSub.append(groups[i]); + bufferToPat.append('('); + bufferToPat.append(groups[i]); + bufferToPat.append(')'); + } + String stringToSub = bufferToSub.toString(); + String pattern = bufferToPat.toString(); + + // Place sub string into working string at random index + baseBuffer.append(stringToSub); + + // Append random chars to end + int trailingChars = generator.nextInt(10); + String trailingString = getRandomAlphaString(trailingChars); + baseBuffer.append(trailingString); + String baseString = baseBuffer.toString(); + + // Create test pattern and matcher + Pattern p = Pattern.compile(pattern); + Matcher m = p.matcher(baseString); + + // Reject candidate if pattern happens to start early + m.find(); + if (m.start() < leadingChars) + continue; + + // Reject candidate if more than one match + if (m.find()) + continue; + + // Construct a replacement string with : + // random group + random string + random group + StringBuffer bufferToRep = new StringBuffer(); + int groupIndex1 = generator.nextInt(5); + bufferToRep.append("$" + (groupIndex1 + 1)); + String randomMidString = getRandomAlphaString(5); + bufferToRep.append(randomMidString); + int groupIndex2 = generator.nextInt(5); + bufferToRep.append("$" + (groupIndex2 + 1)); + String replacement = bufferToRep.toString(); + + // Do the replacement + String result = m.replaceAll(replacement); + + // Construct expected result + StringBuffer bufferToRes = new StringBuffer(); + bufferToRes.append(leadingString); + bufferToRes.append(groups[groupIndex1]); + bufferToRes.append(randomMidString); + bufferToRes.append(groups[groupIndex2]); + bufferToRes.append(trailingString); + String expectedResult = bufferToRes.toString(); + + // Check results + if (!result.equals(expectedResult)) + failCount++; + } + + report("Substitution Basher"); + } + + /** + * Checks the handling of some escape sequences that the Pattern + * class should process instead of the java compiler. These are + * not in the file because the escapes should be be processed + * by the Pattern class when the regex is compiled. + */ + private static void escapes() throws Exception { + Pattern p = Pattern.compile("\\043"); + Matcher m = p.matcher("#"); + if (!m.find()) + failCount++; + + p = Pattern.compile("\\x23"); + m = p.matcher("#"); + if (!m.find()) + failCount++; + + p = Pattern.compile("\\u0023"); + m = p.matcher("#"); + if (!m.find()) + failCount++; + + report("Escape sequences"); + } + + /** + * Checks the handling of blank input situations. These + * tests are incompatible with my test file format. + */ + private static void blankInput() throws Exception { + Pattern p = Pattern.compile("abc", Pattern.CASE_INSENSITIVE); + Matcher m = p.matcher(""); + if (m.find()) + failCount++; + + p = Pattern.compile("a*", Pattern.CASE_INSENSITIVE); + m = p.matcher(""); + if (!m.find()) + failCount++; + + p = Pattern.compile("abc"); + m = p.matcher(""); + if (m.find()) + failCount++; + + p = Pattern.compile("a*"); + m = p.matcher(""); + if (!m.find()) + failCount++; + + report("Blank input"); + } + + /** + * Tests the Boyer-Moore pattern matching of a character sequence + * on randomly generated patterns. + */ + private static void bm() throws Exception { + doBnM('a'); + report("Boyer Moore (ASCII)"); + + doBnM(Character.MIN_SUPPLEMENTARY_CODE_POINT - 10); + report("Boyer Moore (Supplementary)"); + } + + private static void doBnM(int baseCharacter) throws Exception { + int achar=0; + + for (int i=0; i<100; i++) { + // Create a short pattern to search for + int patternLength = generator.nextInt(7) + 4; + StringBuffer patternBuffer = new StringBuffer(patternLength); + for (int x=0; xy+)z+"), + "xxxyyyzzz", + "gname", + "yyy"); + + //backref + Pattern pattern = Pattern.compile("(a*)bc\\1"); + check(pattern, "zzzaabcazzz", true); // found "abca" + + check(Pattern.compile("(?a*)bc\\k"), + "zzzaabcaazzz", true); + + check(Pattern.compile("(?abc)(def)\\k"), + "abcdefabc", true); + + check(Pattern.compile("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(?k)\\k"), + "abcdefghijkk", true); + + // Supplementary character tests + check(Pattern.compile("(?" + toSupplementaries("a*)bc") + "\\k"), + toSupplementaries("zzzaabcazzz"), true); + + check(Pattern.compile("(?" + toSupplementaries("a*)bc") + "\\k"), + toSupplementaries("zzzaabcaazzz"), true); + + check(Pattern.compile("(?" + toSupplementaries("abc)(def)") + "\\k"), + toSupplementaries("abcdefabc"), true); + + check(Pattern.compile(toSupplementaries("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)") + + "(?" + + toSupplementaries("k)") + "\\k"), + toSupplementaries("abcdefghijkk"), true); + + check(Pattern.compile("x+(?y+)z+\\k"), + "xxxyyyzzzyyy", + "gname", + "yyy"); + + //replaceFirst/All + checkReplaceFirst("(?ab)(c*)", + "abccczzzabcczzzabccc", + "$", + "abzzzabcczzzabccc"); + + checkReplaceAll("(?ab)(c*)", + "abccczzzabcczzzabccc", + "$", + "abzzzabzzzab"); + + + checkReplaceFirst("(?ab)(c*)", + "zzzabccczzzabcczzzabccczzz", + "$", + "zzzabzzzabcczzzabccczzz"); + + checkReplaceAll("(?ab)(c*)", + "zzzabccczzzabcczzzabccczzz", + "$", + "zzzabzzzabzzzabzzz"); + + checkReplaceFirst("(?ab)(?c*)", + "zzzabccczzzabcczzzabccczzz", + "$", + "zzzccczzzabcczzzabccczzz"); + + checkReplaceAll("(?ab)(?c*)", + "zzzabccczzzabcczzzabccczzz", + "$", + "zzzccczzzcczzzccczzz"); + + //toSupplementaries("(ab)(c*)")); + checkReplaceFirst("(?" + toSupplementaries("ab") + + ")(?" + toSupplementaries("c") + "*)", + toSupplementaries("abccczzzabcczzzabccc"), + "$", + toSupplementaries("abzzzabcczzzabccc")); + + + checkReplaceAll("(?" + toSupplementaries("ab") + + ")(?" + toSupplementaries("c") + "*)", + toSupplementaries("abccczzzabcczzzabccc"), + "$", + toSupplementaries("abzzzabzzzab")); + + checkReplaceFirst("(?" + toSupplementaries("ab") + + ")(?" + toSupplementaries("c") + "*)", + toSupplementaries("abccczzzabcczzzabccc"), + "$", + toSupplementaries("ccczzzabcczzzabccc")); + + + checkReplaceAll("(?" + toSupplementaries("ab") + + ")(?" + toSupplementaries("c") + "*)", + toSupplementaries("abccczzzabcczzzabccc"), + "$", + toSupplementaries("ccczzzcczzzccc")); + + checkReplaceFirst("(?Dog)AndCat", + "zzzDogAndCatzzzDogAndCatzzz", + "$", + "zzzDogzzzDogAndCatzzz"); + + + checkReplaceAll("(?Dog)AndCat", + "zzzDogAndCatzzzDogAndCatzzz", + "$", + "zzzDogzzzDogzzz"); + + // backref in Matcher & String + if (!"abcdefghij".replaceFirst("cd(?ef)gh", "$").equals("abefij") || + !"abbbcbdbefgh".replaceAll("(?[a-e])b", "$").equals("abcdefgh")) + failCount++; + + // negative + checkExpectedFail("(?abc)(def)"); + checkExpectedFail("(?abc)(def)"); + checkExpectedFail("(?abc)(def)\\k"); + checkExpectedFail("(?abc)(?def)\\k"); + checkExpectedFail(Pattern.compile("(?abc)(def)").matcher("abcdef"), + "gnameX"); + checkExpectedFail(Pattern.compile("(?abc)(def)").matcher("abcdef"), + null); + report("NamedGroupCapture"); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/util/regex/SupplementaryTestCases.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/regex/SupplementaryTestCases.txt Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,1434 @@ +// +// Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute 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. +// +// -------------------------------------------------------- +// This file contains test cases with supplementary characters for regular expressions. +// A test case consists of three lines: +// The first line is a pattern used in the test +// The second line is the input to search for the pattern in +// The third line is a concatentation of the match, the number of groups, +// and the contents of the first four subexpressions. +// Empty lines and lines beginning with comment slashes are ignored. + +// Test unsetting of backed off groups +^(\ud800\udc61)?\ud800\udc61 +\ud800\udc61 +true \ud800\udc61 1 + +^(\ud800\udc61\ud800)?\ud800\udc61\ud800 +\ud800\udc61\ud800 +true \ud800\udc61\ud800 1 + +^(\ud800\udc61\ud800\udc61(\ud800\udc62\ud800\udc62)?)+$ +\ud800\udc61\ud800\udc61\ud800\udc62\ud800\udc62\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61\ud800\udc62\ud800\udc62\ud800\udc61\ud800\udc61 2 \ud800\udc61\ud800\udc61 \ud800\udc62\ud800\udc62 + +^(\ud800\udc61\ud800\udc61\ud800(\ud800\udc62\ud800\udc62\ud800)?)+$ +\ud800\udc61\ud800\udc61\ud800\ud800\udc62\ud800\udc62\ud800\ud800\udc61\ud800\udc61\ud800 +true \ud800\udc61\ud800\udc61\ud800\ud800\udc62\ud800\udc62\ud800\ud800\udc61\ud800\udc61\ud800 2 \ud800\udc61\ud800\udc61\ud800 \ud800\udc62\ud800\udc62\ud800 + +((\ud800\udc61|\ud800\udc62)?\ud800\udc62)+ +\ud800\udc62 +true \ud800\udc62 2 \ud800\udc62 + +((\ud800|\ud800\udc62)?\ud800\udc62)+ +\ud800\udc62 +true \ud800\udc62 2 \ud800\udc62 + +(\ud800\udc61\ud800\udc61\ud800\udc61)?\ud800\udc61\ud800\udc61\ud800\udc61 +\ud800\udc61\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61\ud800\udc61 1 + +(\ud800\udc61\ud800\udc61\ud800\ud800\udc61)?\ud800\udc61\ud800\udc61\ud800\ud800\udc61 +\ud800\udc61\ud800\udc61\ud800\ud800\udc61 +true \ud800\udc61\ud800\udc61\ud800\ud800\udc61 1 + +^(\ud800\udc61\ud800(\ud800\udc62\ud800)?)+$ +\ud800\udc61\ud800\ud800\udc62\ud800\ud800\udc61\ud800 +true \ud800\udc61\ud800\ud800\udc62\ud800\ud800\udc61\ud800 2 \ud800\udc61\ud800 \ud800\udc62\ud800 + +^(\ud800\udc61(\ud800\udc62)?)+$ +\ud800\udc61\ud800\udc62\ud800\udc61 +true \ud800\udc61\ud800\udc62\ud800\udc61 2 \ud800\udc61 \ud800\udc62 + +^(\ud800\udc61\ud800(\ud800\udc62\ud800)?)+$ +\ud800\udc61\ud800\ud800\udc62\ud800\ud800\udc61\ud800 +true \ud800\udc61\ud800\ud800\udc62\ud800\ud800\udc61\ud800 2 \ud800\udc61\ud800 \ud800\udc62\ud800 + +^(\ud800\udc61(\ud800\udc62(\ud800\udc63)?)?)?\ud800\udc61\ud800\udc62\ud800\udc63 +\ud800\udc61\ud800\udc62\ud800\udc63 +true \ud800\udc61\ud800\udc62\ud800\udc63 3 + +^(\ud800\udc61\ud800(\ud800\udc62(\ud800\udc63)?)?)?\ud800\udc61\ud800\ud800\udc62\ud800\udc63 +\ud800\udc61\ud800\ud800\udc62\ud800\udc63 +true \ud800\udc61\ud800\ud800\udc62\ud800\udc63 3 + +^(\ud800\udc61(\ud800\udc02(\ud800\udc63))).* +\ud800\udc61\ud800\udc02\ud800\udc63 +true \ud800\udc61\ud800\udc02\ud800\udc63 3 \ud800\udc61\ud800\udc02\ud800\udc63 \ud800\udc02\ud800\udc63 \ud800\udc63 + +^(\ud800\udc61(\ud800(\ud800\udc63))).* +\ud800\udc61\ud800\ud800\udc63 +true \ud800\udc61\ud800\ud800\udc63 3 \ud800\udc61\ud800\ud800\udc63 \ud800\ud800\udc63 \ud800\udc63 + +// Patterns including no surrogates +(.)([^a])xyz +\ud801\ud800\udc00xyz +true \ud801\ud800\udc00xyz 2 \ud801 \ud800\udc00 + +[^a-z].. +\ud801\ud800\udc00xyz +true \ud801\ud800\udc00x 0 + +.$ +\ud801\ud800\udc00 +true \ud800\udc00 0 + +.$ +\ud801\udc01\ud800\udc00 +true \ud800\udc00 0 + +.$ +\ud801\udc01\ud800\udc00\udcff +true \udcff 0 + +[^x-\uffff][^y-\uffff] +\ud800\udc00pqr +true \ud800\udc00p 0 + +[^x-\uffff]+ +\ud800\udc00pqrx +true \ud800\udc00pqr 0 + +/// The following test cases fail due to use of Start rather than +/// StartS. Disabled for now. +///[a-\uffff] +///\ud800\udc00x +///true x 0 +/// +///[a-\uffff] +///\ud800\udc00 +///false 0 + +// use of x modifier +\ud800\udc61bc(?x)bl\ud800\udc61h +\ud800\udc61bcbl\ud800\udc61h +true \ud800\udc61bcbl\ud800\udc61h 0 + +\ud800\udc61bc(?x) bl\ud800\udc61h +\ud800\udc61bcbl\ud800\udc61h +true \ud800\udc61bcbl\ud800\udc61h 0 + +\ud800\udc61bc(?x) bl\ud800\udc61h blech +\ud800\udc61bcbl\ud800\udc61hblech +true \ud800\udc61bcbl\ud800\udc61hblech 0 + +\ud800\udc61bc(?x) bl\ud800\udc61h # ignore comment +\ud800\udc61bcbl\ud800\udc61h +true \ud800\udc61bcbl\ud800\udc61h 0 + +// Simple alternation +\ud800\udc61|\ud800\udc62 +\ud800\udc61 +true \ud800\udc61 0 + +\ud800\udc61|\ud800\udc62|\ud800 +\ud800\udc61 +true \ud800\udc61 0 + +\ud800\udc61|\ud800 +\ud800\udc62 +false 0 + +\ud800\udc62|\ud800 +\ud800 +true \ud800 0 + +\ud800\udc61|\ud802\udc02 +z +false 0 + +\ud800\udc61|\ud802\udc02 +\ud802\udc02 +true \ud802\udc02 0 + +\ud800\udc61|\ud802\udc02|\ud803\udc03\ud804\udc04 +\ud803\udc03\ud804\udc04 +true \ud803\udc03\ud804\udc04 0 + +\ud800\udc61|\ud800\udc61d +\ud800\udc61d +true \ud800\udc61 0 + +z(\ud800\udc61|\ud800\udc61c)\ud802\udc02 +z\ud800\udc61c\ud802\udc02 +true z\ud800\udc61c\ud802\udc02 1 \ud800\udc61c + +z(\ud800\udc61|\ud800\udc61c|\udc61c)\ud802\udc02 +z\udc61c\ud802\udc02 +true z\udc61c\ud802\udc02 1 \udc61c + +// Simple codepoint class +[\ud800\udc61\ud802\udc02c]+ +\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02 +true \ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02 0 + +[\ud800\udc61\ud802\udc02c]+ +\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02 +true \ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02 0 + +[\ud800\udc61\ud802\udc02c\ud800]+ +\ud800\udc61\ud802\udc02\ud800\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02 +true \ud800\udc61\ud802\udc02\ud800\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02 0 + +[\ud800\udc61bc]+ +d\ud800\udc62fg +false 0 + +[\ud800\udc61bc]+[\ud804\udc04ef]+[\ud807\udc07hi]+ +zzz\ud800\udc61\ud800\udc61\ud804\udc04\ud804\udc04\ud807\udc07\ud807\udc07zzz +true \ud800\udc61\ud800\udc61\ud804\udc04\ud804\udc04\ud807\udc07\ud807\udc07 0 + +// Range codepoint class +[\ud801\udc01-\ud807\udc07]+ +\ud8ff\udcff\ud8ff\udcff\ud8ff\udcff\ud807\udc07\ud807\udc07\ud807\udc07 +true \ud807\udc07\ud807\udc07\ud807\udc07 0 + +[\ud801\udc01-\ud807\udc07]+ +mmm +false 0 + +[\ud800\udc61-]+ +z\ud800\udc61-9z +true \ud800\udc61- 0 + +// Negated char class +[^\ud800\udc61\ud802\udc02c]+ +\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02\ud800\udc61\ud802\udc02 +false 0 + +[^\ud800\udc61\ud802\udc02\ud803\udc03]+ +\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02\ud802\udc02\ud802\udc02\ud803\udc03\ud803\udc03\ud803\udc03\ud804\udc04efg +true \ud804\udc04efg 0 + +[^\ud800\udc61\ud802\udc02\ud803\udc03\ud800]+ +\ud800\udc61\ud800\udc61\ud800\udc61\ud802\udc02\ud802\udc02\ud802\udc02\ud803\udc03\ud803\udc03\ud803\udc03\ud804\udc04efg +true \ud804\udc04efg 0 + +// Making sure a ^ not in first position matches literal ^ +[\ud801\udc01\ud802\udc02\ud803\udc03^\ud802\udc02] +\ud802\udc02 +true \ud802\udc02 0 + +[\ud801\udc01\ud802\udc02\ud803\udc03^\ud802\udc02] +^ +true ^ 0 + +// Class union and intersection +[\ud801\udc01\ud802\udc02\ud803\udc03[\ud804\udc04\ud805\udc05\ud806\udc06]] +\ud802\udc02 +true \ud802\udc02 0 + +[\ud800\udc61\ud802\udc02\ud803\udc03[\ud804\udc04\ud805\udc05\ud806\udc06]] +\ud805\udc05 +true \ud805\udc05 0 + +[\ud801\udc01-\ud804\udc04[0-9][\ud80b\udc0b-\ud80d\udc0d]] +\ud801\udc01 +true \ud801\udc01 0 + +[\ud801\udc01-\ud804\udc04[0-9][\ud80b\udc0b-\ud80d\udc0d]] +\ud80c\udc0c +true \ud80c\udc0c 0 + +[\ud801\udc01-\ud804\udc04[0-9][\ud80b\udc0b-\ud80d\udc0d]] +4 +true 4 0 + +[\ud801\udc01-\ud804\udc04[0-9][\ud80b\udc0b-\ud80d\udc0d]] +\ud805\udc05 +false 0 + +[\ud801\udc01-\ud804\udc04[0-9][\ud80b\udc0b-\ud80d\udc0d]] +\ud816\udc16 +false 0 + +[[\ud801\udc01-\ud804\udc04][0-9][\ud80b\udc0b-\ud80d\udc0d]] +\ud802\udc02 +true \ud802\udc02 0 + +[[\ud801\udc01-\ud804\udc04][0-9][\ud80b\udc0b-\ud80d\udc0d]] +\ud81a\udc1a +false 0 + +[\ud801\udc01-\ud803\udc03[\ud804\udc04-\ud806\udc06[\ud807\udc07-\ud809\udc09]]] +\ud801\udc01 +true \ud801\udc01 0 + +[\ud801\udc01-\ud803\udc03[\ud804\udc04-\ud806\udc06[\ud807\udc07-\ud809\udc09]]] +\ud805\udc05 +true \ud805\udc05 0 + +[\ud801\udc01-\ud803\udc03[\ud804\udc04-\ud806\udc06[\ud807\udc07-\ud809\udc09]]] +\ud808\udc08 +true \ud808\udc08 0 + +[\ud801\udc01-\ud803\udc03[\ud804\udc04-\ud806\udc06[\ud807\udc07-\ud809\udc09]]] +\ud80d\udc0d +false 0 + +[\ud801\udc01-\ud803\udc03[\ud804\udc04-\ud806\udc06[\ud807\udc07-\ud809\udc09]]\ud80d\udc0d] +\ud80d\udc0d +true \ud80d\udc0d 0 + +[\ud801\udc01\ud802\udc02\ud803\udc03[\ud804\udc04\ud805\udc05\ud806\udc06]\ud807\udc07\ud808\udc08\ud809\udc09] +\ud801\udc01 +true \ud801\udc01 0 + +[\ud800\udc61\ud802\udc02\ud803\udc03[\ud804\udc04\ud805\udc05\ud806\udc06]\ud807\udc07\ud808\udc08\ud809\udc09] +\ud804\udc04 +true \ud804\udc04 0 + +[\ud800\udc61\ud802\udc02\ud803\udc03[\ud804\udc04\ud805\udc05\ud806\udc06]\ud807\udc07\ud808\udc08\ud809\udc09] +\ud808\udc08 +true \ud808\udc08 0 + +[\ud800\udc61\ud802\udc02\ud803\udc03[\ud804\udc04\ud805\udc05\ud806\udc06]\ud807\udc07\ud808\udc08\ud809\udc09] +\ud816\udc16 +false 0 + +[\ud801\udc01-\ud803\udc03&&[\ud804\udc04-\ud806\udc06]] +\ud801\udc01 +false 0 + +[\ud801\udc01-\ud803\udc03&&[\ud804\udc04-\ud806\udc06]] +\ud805\udc05 +false 0 + +[\ud801\udc01-\ud803\udc03&&[\ud804\udc04-\ud806\udc06]] +\ud81a\udc1a +false 0 + +[[\ud801\udc01-\ud803\udc03]&&[\ud804\udc04-\ud806\udc06]] +\ud801\udc01 +false 0 + +[[\ud801\udc01-\ud803\udc03]&&[\ud804\udc04-\ud806\udc06]] +\ud805\udc05 +false 0 + +[[\ud801\udc01-\ud803\udc03]&&[\ud804\udc04-\ud806\udc06]] +\ud81a\udc1a +false 0 + +[\ud801\udc01-\ud803\udc03&&\ud804\udc04-\ud806\udc06] +\ud801\udc01 +false 0 + +[\ud801\udc01-\ud80d\udc0d&&\ud80d\udc0d-\ud81a\udc1a] +\ud80d\udc0d +true \ud80d\udc0d 0 + +[\ud801\udc01-\ud80d\udc0d&&\ud80d\udc0d-\ud81a\udc1a&&\ud801\udc01-\ud803\udc03] +\ud80d\udc0d +false 0 + +[\ud801\udc01-\ud80d\udc0d&&\ud80d\udc0d-\ud81a\udc1a&&\ud801\udc01-\ud81a\udc1a] +\ud80d\udc0d +true \ud80d\udc0d 0 + +[[\ud801\udc01-\ud80d\udc0d]&&[\ud80d\udc0d-\ud81a\udc1a]] +\ud801\udc01 +false 0 + +[[\ud801\udc01-\ud80d\udc0d]&&[\ud80d\udc0d-\ud81a\udc1a]] +\ud80d\udc0d +true \ud80d\udc0d 0 + +[[\ud801\udc01-\ud80d\udc0d]&&[\ud80d\udc0d-\ud81a\udc1a]] +\ud81a\udc1a +false 0 + +[[\ud801\udc01-\ud80d\udc0d]&&[^\ud801\udc01-\ud803\udc03]] +\ud801\udc01 +false 0 + +[[\ud801\udc01-\ud80d\udc0d]&&[^\ud801\udc01-\ud803\udc03]] +\ud804\udc04 +true \ud804\udc04 0 + +[\ud801\udc01-\ud80d\udc0d&&[^\ud801\udc01-\ud803\udc03]] +\ud801\udc01 +false 0 + +[\ud801\udc01-\ud80d\udc0d&&[^\ud801\udc01-\ud803\udc03]] +\ud804\udc04 +true \ud804\udc04 0 + +[\ud801\udc01-\ud803\udc03\ud804\udc04-\ud806\udc06&&[\ud804\udc04-\ud806\udc06]] +\ud801\udc01 +false 0 + +[\ud801\udc01-\ud803\udc03\ud804\udc04-\ud806\udc06&&[\ud804\udc04-\ud806\udc06]] +\ud805\udc05 +true \ud805\udc05 0 + +[[\ud801\udc01-\ud803\udc03]&&\ud804\udc04-\ud806\udc06\ud801\udc01-\ud803\udc03] +\ud801\udc01 +true \ud801\udc01 0 + +[[\ud801\udc01-\ud803\udc03]&&[\ud804\udc04-\ud806\udc06][\ud801\udc01-\ud803\udc03]] +\ud801\udc01 +true \ud801\udc01 0 + +[[\ud801\udc01-\ud803\udc03][\ud804\udc04-\ud806\udc06]&&\ud801\udc01\ud802\udc02\ud803\udc03] +\ud801\udc01 +true \ud801\udc01 0 + +[[\ud801\udc01-\ud803\udc03][\ud804\udc04-\ud806\udc06]&&\ud801\udc01\ud802\udc02\ud803\udc03[\ud804\udc04\ud805\udc05\ud806\udc06]] +\ud805\udc05 +true \ud805\udc05 0 + +[[\ud801\udc01-\ud803\udc03]&&[\ud802\udc02-\ud804\udc04]&&[\ud803\udc03-\ud805\udc05]] +\ud801\udc01 +false 0 + +[[\ud801\udc01-\ud803\udc03]&&[\ud802\udc02-\ud804\udc04]&&[\ud803\udc03-\ud805\udc05]] +\ud803\udc03 +true \ud803\udc03 0 + +[[\ud801\udc01-\ud803\udc03]&&[\ud802\udc02-\ud804\udc04][\ud803\udc03-\ud805\udc05]&&[\ud815\udc15-\ud81a\udc1a]] +\ud803\udc03 +false 0 + +[\ud801\udc01\ud802\udc02\ud803\udc03[^\ud802\udc02\ud803\udc03\ud804\udc04]] +\ud801\udc01 +true \ud801\udc01 0 + +[\ud800\udc61\ud802\udc02\ud803\udc03[^\ud802\udc02\ud803\udc03\ud804\udc04]] +\ud804\udc04 +false 0 + +[\ud801\udc01-\ud803\udc03&&\ud801\udc01-\ud804\udc04&&\ud801\udc01-\ud805\udc05\ud807\udc07\ud808\udc08\ud809\udc09] +\ud802\udc02 +true \ud802\udc02 0 + +[\ud801\udc01-\ud803\udc03&&\ud801\udc01-\ud804\udc04&&\ud801\udc01-\ud805\udc05\ud807\udc07\ud808\udc08\ud809\udc09] +\ud807\udc07 +false 0 + +[[\ud801\udc01[\ud802\udc02]]&&[\ud802\udc02[\ud801\udc01]]] +\ud801\udc01 +true \ud801\udc01 0 + +// Unicode isn't supported in clazz() +[[\ud800\udc61]&&[b][c][\ud800\udc61]&&[^d]] +\ud800\udc61 +true \ud800\udc61 0 + +[[\ud800\udc61]&&[\ud802\udc02][\ud800][\ud800\udc61]&&[^\ud804\udc04]] +\ud800\udc61 +true \ud800\udc61 0 + +[[\ud800\udc61]&&[b][\ud800][\ud800\udc61]&&[^\ud804\udc04]] +\ud804\udc04 +false 0 + +[[\ud800\udc61]&&[b][c][\ud800\udc61]&&[^d]] +d +false 0 + +[[[\ud800\udc01-\ud800\udc04]&&[\ud800\udc03-\ud800\udc06]]] +\ud800\udc01 +false 0 + +[[[\ud800\udc01-\ud800\udc04]&&[\ud800\udc03-\ud800\udc06]]] +\ud800\udc03 +true \ud800\udc03 0 + +[[[\ud800\udc01-\ud800\udc04]&&[\ud800\udc03-\ud800\udc06]]&&[\ud800\udc03]] +\ud800\udc03 +true \ud800\udc03 0 + +[[[\ud800\udc01-\ud800\udc04]&&[\ud800\udc03-\ud800\udc06]]&&[\ud800\udc03]&&\ud800\udc03] +\ud800\udc03 +true \ud800\udc03 0 + +[[[\ud800\udc01-\ud800\udc04]&&[\ud800\udc03-\ud800\udc06]]&&[\ud800\udc03]&&\ud800\udc03&&\ud800\udc03] +\ud800\udc03 +true \ud800\udc03 0 + +[[[\ud800\udc01-\ud800\udc04]&&[\ud800\udc03-\ud800\udc06]]&&[\ud800\udc03]&&\ud800\udc03&&[\ud800\udc03\ud800\udc04\ud800\udc05]] +\ud800\udc03 +true \ud800\udc03 0 + +[z[\ud800\udc61b\ud800\udc03&&b\ud800\udc03\ud800\udc04]] +\ud800\udc03 +true \ud800\udc03 0 + +[z[\ud800\udc61b\ud800\udc03&&b\ud800\udc03\ud800\udc04]&&[u-z]] +z +true z 0 + +[x[\ud800\udc61b\ud800\udc03&&b\ud800\udc03\ud800\udc04[z]]&&[u-z]] +z +false 0 + +[x[[wz]\ud800\udc61b\ud800\udc03&&b\ud800\udc03\ud800\udc04[z]]&&[u-z]] +z +true z 0 + +[[\ud800\udc61b\ud800\udc03]&&[\ud800\udc04\ud800\udc05f]\ud800\udc61b\ud800\udc03] +\ud800\udc61 +true \ud800\udc61 0 + +[[\ud800\udc61b\ud800\udc03]&&[\ud800\udc04\ud800\udc05f]xyz[\ud800\udc61b\ud800\udc03]] +\ud800\udc61 +true \ud800\udc61 0 + +\pL +\ud800\udc00 +true \ud800\udc00 0 + +\p{IsASCII} +\ud800\udc00 +false 0 + +\pLbc +\ud800\udc00bc +true \ud800\udc00bc 0 + +\ud800\udc61[r\p{InGreek}]c +\ud800\udc61\u0370c +true \ud800\udc61\u0370c 0 + +\ud800\udc61\p{InGreek} +\ud800\udc61\u0370 +true \ud800\udc61\u0370 0 + +\ud800\udc61\P{InGreek} +\ud800\udc61\u0370 +false 0 + +\ud800\udc61\P{InGreek} +\ud800\udc61b +true \ud800\udc61b 0 + +\ud800\udc61{^InGreek} +- +error + +\ud800\udc61\p{^InGreek} +- +error + +\ud800\udc61\P{^InGreek} +- +error + +\ud800\udc61\p{InGreek} +\ud800\udc61\u0370 +true \ud800\udc61\u0370 0 + +\ud800\udc61[\p{InGreek}]c +\ud800\udc61\u0370c +true \ud800\udc61\u0370c 0 + +\ud800\udc61[\P{InGreek}]c +\ud800\udc61\u0370c +false 0 + +\ud800\udc61[\P{InGreek}]c +\ud800\udc61bc +true \ud800\udc61bc 0 + +\ud800\udc61[{^InGreek}]c +\ud800\udc61nc +true \ud800\udc61nc 0 + +\ud800\udc61[{^InGreek}]c +\ud800\udc61zc +false 0 + +\ud800\udc61[\p{^InGreek}]c +- +error + +\ud800\udc61[\P{^InGreek}]c +- +error + +\ud800\udc61[\p{InGreek}] +\ud800\udc61\u0370 +true \ud800\udc61\u0370 0 + +\ud800\udc61[r\p{InGreek}]c +\ud800\udc61rc +true \ud800\udc61rc 0 + +\ud800\udc61[\p{InGreek}r]c +\ud800\udc61rc +true \ud800\udc61rc 0 + +\ud800\udc61[r\p{InGreek}]c +\ud800\udc61rc +true \ud800\udc61rc 0 + +\ud800\udc61[^\p{InGreek}]c +\ud800\udc61\u0370c +false 0 + +\ud800\udc61[^\P{InGreek}]c +\ud800\udc61\u0370c +true \ud800\udc61\u0370c 0 + +\ud800\udc61[\p{InGreek}&&[^\u0370]]c +\ud800\udc61\u0370c +false 0 + +// Test the dot metacharacter +\ud800\udc61.c.+ +\ud800\udc61#c%& +true \ud800\udc61#c%& 0 + +\ud800\udc61b. +\ud800\udc61b\n +false 0 + +(?s)\ud800\udc61b. +\ud800\udc61b\n +true \ud800\udc61b\n 0 + +\ud800\udc61[\p{L}&&[\P{InGreek}]]c +\ud800\udc61\u6000c +true \ud800\udc61\u6000c 0 + +\ud800\udc61[\p{L}&&[\P{InGreek}]]c +\ud800\udc61rc +true \ud800\udc61rc 0 + +\ud800\udc61[\p{L}&&[\P{InGreek}]]c +\ud800\udc61\u0370c +false 0 + +\ud800\udc61\p{InGreek}c +\ud800\udc61\u0370c +true \ud800\udc61\u0370c 0 + +\ud800\udc61\p{Sc} +\ud800\udc61$ +true \ud800\udc61$ 0 + +// Test \p{L} +\p{L} +\ud800\udf1e +true \ud800\udf1e 0 + +^a\p{L}z$ +a\ud800\udf1ez +true a\ud800\udf1ez 0 + +// Test \P{InDeseret} + +\ud800\udf00\p{L}{2,3}\P{L}*supp->\ud900\udc00<-\P{InDeseret} +\ud800\udf00\ud800\udf1e\ud800\udf1esupp->\ud900\udc00<-\ud901\udf00 +true \ud800\udf00\ud800\udf1e\ud800\udf1esupp->\ud900\udc00<-\ud901\udf00 0 + +\ud800\udf00\p{L}{2,3}\P{L}*supp->\ud900\udc00<-\P{InDeseret} +\ud800\udf00\ud800\udf1e\ud800\udf1e\ud901\udf00supp->\ud900\udc00<-\ud901\udf00 +true \ud800\udf00\ud800\udf1e\ud800\udf1e\ud901\udf00supp->\ud900\udc00<-\ud901\udf00 0 + +// Test \p{InDeseret} +\ud800\udf00\p{L}{2,3}\P{L}*supp->\ud900\udc00<-\p{InDeseret} +\ud800\udf00\ud800\udf1e\ud800\udf1e\ud901\udf00supp->\ud900\udc00<-\ud801\udc00 +true \ud800\udf00\ud800\udf1e\ud800\udf1e\ud901\udf00supp->\ud900\udc00<-\ud801\udc00 0 + +// Test the word char escape sequence +\ud800\udc61b\wc +\ud800\udc61bcc +true \ud800\udc61bcc 0 + +\ud800\udc61bc[\w] +\ud800\udc61bcd +true \ud800\udc61bcd 0 + +\ud800\udc61bc[\sdef]* +\ud800\udc61bc def +true \ud800\udc61bc def 0 + +\ud800\udc61bc[\sy-z]* +\ud800\udc61bc y z +true \ud800\udc61bc y z 0 + +\ud800\udc01bc[\ud800\udc01-\ud800\udc04\sm-p]* +\ud800\udc01bc\ud800\udc01\ud800\udc01 mn p +true \ud800\udc01bc\ud800\udc01\ud800\udc01 mn p 0 + +// Test the whitespace escape sequence +\ud800\udc61b\s\ud800\udc03 +\ud800\udc61b \ud800\udc03 +true \ud800\udc61b \ud800\udc03 0 + +\s\s\s +bl\ud800\udc61h err +false 0 + +\S\S\s +bl\ud800\udc61h err +true \ud800\udc61h 0 + +// Test the digit escape sequence +\ud800\udc61b\d\ud800\udc03 +\ud800\udc61b9\ud800\udc03 +true \ud800\udc61b9\ud800\udc03 0 + +\d\d\d +bl\ud800\udc61h45 +false 0 + +// Test the caret metacharacter +^\ud800\udc61bc +\ud800\udc61bcdef +true \ud800\udc61bc 0 + +^\ud800\udc61bc +bcd\ud800\udc61bc +false 0 + +// Greedy ? metacharacter +\ud800\udc61?\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc02 0 + +\udc61?\ud800\udc02 +\ud800\udc61\udc61\udc61\ud800\udc02 +true \udc61\ud800\udc02 0 + +\ud800\udc61?\ud800\udc02 +\ud800\udc02 +true \ud800\udc02 0 + +\ud800?\ud800\udc02 +\ud800\udc02 +true \ud800\udc02 0 + +\ud800\udc61?\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc03\ud800\udc03\ud800\udc03 +false 0 + +.?\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc02 0 + +// Reluctant ? metacharacter +\ud800\udc61??\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc02 0 + +\ud800??\ud800\udc02 +\ud800\ud800\ud8001\ud800\ud800\udc02 +true \ud800\ud800\udc02 0 + +\ud800\udc61??\ud800\udc02 +\ud800\udc02 +true \ud800\udc02 0 + +\ud800??\ud800\udc02 +\ud800\udc02 +true \ud800\udc02 0 + +\ud800\udc61??\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61ccc +false 0 + +.??\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc02 0 + +// Possessive ? metacharacter +\ud800\udc61?+\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc02 0 + +\ud800\udc61?+\ud800\udc02 +\ud800\udc02 +true \ud800\udc02 0 + +\ud800\udc61?+\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61ccc +false 0 + +.?+\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc02 0 + +// Greedy + metacharacter +\ud800\udc61+\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 0 + +\udc61+\ud800\udc02 +\ud800\udc61\udc61\udc61\udc61\ud800\udc02 +true \udc61\udc61\udc61\ud800\udc02 0 + +\ud800\udc61+\ud800\udc02 +\ud800\udc02 +false 0 + +\ud800+\ud800\udc02 +\ud800\udc02 +false 0 + +\ud800\udc61+\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61ccc +false 0 + +.+\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 0 + +.+\ud800\udc02 +\ud800\udc61\udc61\udc61\udc61\ud800\udc02 +true \ud800\udc61\udc61\udc61\udc61\ud800\udc02 0 + +// Reluctant + metacharacter +\ud800\udc61+?\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 0 + +\udc61+?\ud800\udc02 +\udc61\udc61\udc61\udc61\ud800\udc02 +true \udc61\udc61\udc61\udc61\ud800\udc02 0 + +\ud800\udc61+?\ud800\udc02 +\ud800\udc02 +false 0 + +\ud800+?\ud800\udc02 +\ud800\udc02 +false 0 + +\ud800\udc61+?\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61ccc +false 0 + +.+?\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 0 + +// Possessive + metacharacter +\ud800\udc61++\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 0 + +\ud800\udc61++\ud800\udc02 +\ud800\udc02 +false 0 + +\ud800\udc61++\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61ccc +false 0 + +.++\ud800\udc02 +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc02 +false 0 + +// Greedy Repetition +\ud800\udc61{2,3} +\ud800\udc61 +false 0 + +\ud800\udc61{2,3} +\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61 0 + +\ud800\udc61{2,3} +\ud800\udc61\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61\ud800\udc61 0 + +\ud800\udc61{2,3} +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61\ud800\udc61 0 + +\ud800\udc61{3,} +zzz\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61zzz +true \ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61 0 + +\ud800\udc61{3,} +zzz\ud800\udc61\ud800\udc61zzz +false 0 + +// Reluctant Repetition +\ud800\udc61{2,3}? +\ud800\udc61 +false 0 + +\ud800\udc61{2,3}? +\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61 0 + +\ud800\udc61{2,3}? +\ud800\udc61\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61 0 + +\ud800\udc61{2,3}? +\ud800\udc61\ud800\udc61\ud800\udc61\ud800\udc61 +true \ud800\udc61\ud800\udc61 0 + +// Zero width Positive lookahead +\ud800\udc61\ud802\udc02\ud803\udc03(?=\ud804\udc04) +zzz\ud800\udc61\ud802\udc02\ud803\udc03\ud804\udc04 +true \ud800\udc61\ud802\udc02\ud803\udc03 0 + +\ud800\udc61\ud802\udc02\ud803\udc03(?=\ud804\udc04) +zzz\ud800\udc61\ud802\udc02\ud803\udc03e\ud804\udc04 +false 0 + +\ud800\udc61\ud802\udc02\ud803\udc03(?=\udcff\ud804\udc04) +zzz\ud800\udc61\ud802\udc02\ud803\udc03\udcff\ud804\udc04 +true \ud800\udc61\ud802\udc02\ud803\udc03 0 + +\ud800\udc61\ud802\udc02\ud803\udc03(?=\udcff\ud804\udc04) +zzz\ud800\udc61\ud802\udc02\ud803\udc03\ud8ff\udcff\ud804\udc04 +false 0 + +// Zero width Negative lookahead +\ud800\udc61\ud802\udc02\ud803\udc03(?!\ud804\udc04) +zz\ud800\udc61\ud802\udc02\ud803\udc03\ud804\udc04 +false 0 + +a\ud802\udc02\ud803\udc03(?!\ud804\udc04) +zza\ud802\udc02\ud803\udc03\udc04\ud804\udc04 +true a\ud802\udc02\ud803\udc03 0 + +\ud800\udc61\ud802\udc02\ud803\udc03(?!\ud804\udc04\ud8ff) +zz\ud800\udc61\ud802\udc02\ud803\udc03\ud804\udc04\ud8ffX +false 0 + +a\ud802\udc02\ud803\udc03(?!\ud804\udc04\ud8ff) +zza\ud802\udc02\ud803\udc03e\ud804\udc04\ud8ff\udcff +true a\ud802\udc02\ud803\udc03 0 + +// Zero width Positive lookbehind +(?<=\ud801\udc01\ud802\udc02)\ud803\udc03 +\ud801\udc01\ud802\udc02\ud803\udc03 +true \ud803\udc03 0 + +// Zero width Negative lookbehind +(?3 +// So that the BM optimization is part of test +\Q***\E\ud801\udc01\ud802\udc02\ud800\udc03 +***\ud801\udc01\ud802\udc02\ud800\udc03 +true ***\ud801\udc01\ud802\udc02\ud800\udc03 0 + +\ud802\udc02l\Q***\E\ud801\udc01\ud802\udc02\ud800\udc03 +\ud802\udc02l***\ud801\udc01\ud802\udc02\ud800\udc03 +true \ud802\udc02l***\ud801\udc01\ud802\udc02\ud800\udc03 0 + +\Q***\ud801\udc01\ud802\udc02\ud800\udc03 +***\ud801\udc01\ud802\udc02\ud800\udc03 +true ***\ud801\udc01\ud802\udc02\ud800\udc03 0 + +\ud802\udc02l\ud801\udc01h\Q***\E\ud801\udc01\ud802\udc02\ud800\udc03 +\ud802\udc02l\ud801\udc01h***\ud801\udc01\ud802\udc02\ud800\udc03 +true \ud802\udc02l\ud801\udc01h***\ud801\udc01\ud802\udc02\ud800\udc03 0 + +\Q***\ud801\udc01\ud802\udc02\ud800\udc03 +***\ud801\udc01\ud802\udc02\ud800\udc03 +true ***\ud801\udc01\ud802\udc02\ud800\udc03 0 + +\Q*\ud801\udc01\ud802\udc02 +*\ud801\udc01\ud802\udc02 +true *\ud801\udc01\ud802\udc02 0 + +\ud802\udc02l\ud801\udc01h\Q***\ud801\udc01\ud802\udc02\ud800\udc03 +\ud802\udc02l\ud801\udc01h***\ud801\udc01\ud802\udc02\ud800\udc03 +true \ud802\udc02l\ud801\udc01h***\ud801\udc01\ud802\udc02\ud800\udc03 0 + +\ud802\udc02l\ud801\udc01\Q***\ud801\udc01\ud802\udc02\ud800\udc03 +\ud802\udc02l\ud801\udc01***\ud801\udc01\ud802\udc02\ud800\udc03 +true \ud802\udc02l\ud801\udc01***\ud801\udc01\ud802\udc02\ud800\udc03 0 + +//Test cases below copied from i18n QE's RegexSupplementaryTests.txt +\uD800\uDFFF\uD801\uDFF1\uDB00\uDC00 +\uD800\uDFFF\uD801\uDFF1\uDB00\uDC00 +true \uD800\uDFFF\uD801\uDFF1\uDB00\uDC00 0 + +\uD800\uDFFF\uD801\uDFF1\uDB00\uDC00 +\u1000\uD801\uDFF1\uDB00\uDC00 +false 0 + +\uD800\uDFFF\uD801\uDFF1\uDB00\uDC00 +\uD800\uDFFF\uFFFF\uDB00\uDC00 +false 0 + +\uD800\uDFFF\uD801\uDFF1\uDB00\uDC00 +\uD800\uDFFF\uD801\uDFF1\uFFFF +false 0 + +\u1000.\uFFFF +\u1000\uD800\uDFFF\uFFFF +true \u1000\uD800\uDFFF\uFFFF 0 + +//======= +// Ranges +//======= +[a-\uD800\uDFFF] +\uDFFF +true \uDFFF 0 + +[a-\uD800\uDFFF] +\uD800 +true \uD800 0 + +[a-\uD800\uDFFF] +\uD800\uDFFF +true \uD800\uDFFF 0 + +[\uD800\uDC00-\uDBFF\uDFFF] +\uDBFF +false 0 + +[\uD800\uDC00-\uDBFF\uDFFF] +\uDC00 +false 0 + +[\uD800-\uDFFF] +\uD800\uDFFF +false 0 + +[\uD800-\uDFFF] +\uDFFF\uD800 +true \uDFFF 0 + +foo[^\uD800-\uDFFF] +foo\uD800\uDFFF +true foo\uD800\uDFFF 0 + +foo[^\uD800-\uDFFF] +foo\uDFFF\uD800 +false 0 + +//fo\uD800[\uDC00-\uDFFF] + +//================== +// Character Classes +//================== +// Simple class +[ab\uD800\uDFFFcd]at +\uD800at +false 0 + +[ab\uD800\uDFFFcd]at +\uD800\uDFFFat +true \uD800\uDFFFat 0 + +// Negation +[^\uD800\uDFFFcd]at +\uD800at +true \uD800at 0 + +[^\uD800\uDFFFcd]at +\uDFFFat +true \uDFFFat 0 + +// Inclusive range +[\u0000-\uD800\uDFFF-\uFFFF] +\uD800\uDFFF +true \uD800\uDFFF 0 + +// Unions +[\u0000-\uD800[\uDFFF-\uFFFF]] +\uD800\uDFFF +false 0 + + +// Intersection +[\u0000-\uFFFF&&[\uD800\uDFFF]] +\uD800\uDFFF +false 0 + +[\u0000-\uFFFF&&[\uD800\uDFFF]] +\uD800 +false 0 + +[\u0000-\uFFFF&&[\uDFFF\uD800]] +\uD800 +true \uD800 0 + +[\u0000-\uFFFF&&[\uDFFF\uD800\uDC00]] +\uDC00 +false 0 + +[\u0000-\uDFFF&&[\uD800-\uFFFF]] +\uD800\uDFFF +false 0 + +[\u0000-\uDFFF&&[\uD800-\uFFFF]] +\uDFFF\uD800 +true \uDFFF 0 + +// Subtraction +[\u0000-\uD800\uDFFF&&[^\uD800\uDC00]] +\uD800 +true \uD800 0 + +[\u0000-\uD800\uDFFF&&[^\uD800\uDC00]] +\uDC00 +true \uDC00 0 + +[\u0000-\uD800\uDFFF&&[^\uD800\uDC00]] +\uD800\uDFFF +true \uD800\uDFFF 0 + +[\u0000-\uD800\uDFFF&&[^\uD800\uDBFF\uDC00]] +\uD800 +false 0 + +[\u0000-\uD800\uDFFF&&[^\uDC00\uD800\uDBFF]] +\uD800\uDC00 +true \uD800\uDC00 0 + +// Quantifiers +a\uD800\uDFFF? +a\uD800 +true a 0 + +a\uD800\uDFFF? +a\uDFFF +true a 0 + +a\uD800\uDFFF? +a\uD800\uDFFF +true a\uD800\uDFFF 0 + +a\uDFFF\uD800? +a\uDFFF +true a\uDFFF 0 + +a\uDFFF\uD800? +a\uD800 +false 0 + +\uD800\uDFFF\uDC00? +\uD800 +false 0 + +\uD800\uDFFF\uDC00? +\uD800\uDFFF +true \uD800\uDFFF 0 + +a\uD800\uDFFF?? +a\uDFFF +true a 0 + +a\uD800\uDFFF* +a +true a 0 + +a\uD800\uDFFF* +a\uD800 +true a 0 + +\uD800\uDFFF* +\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF +true \uD800\uDFFF\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF 0 + +\uD800\uDFFF* +\uD800\uDFFF\uDFFF\uDFFF\uDFFF +true \uD800\uDFFF 0 + +\uD800*\uDFFF +\uD800\uDFFF +false 0 + +a\uD800\uDFFF* +a\uD800 +true a 0 + +\uDFFF\uD800* +\uDFFF +true \uDFFF 0 + +\uDFFF\uD800* +\uDFFF\uD800\uD800\uD800 +true \uDFFF\uD800\uD800\uD800 0 + +\uD800\uDFFF+ +\uD800\uDFFF\uDFFF\uDFFF +true \uD800\uDFFF 0 + +\uD800\uDFFF+ +\uD800 +false 0 + +\uD800\uDFFF+ +\uD800\uDFFF +true \uD800\uDFFF 0 + +\uD800\uDFFF+ +\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF +true \uD800\uDFFF\uD800\uDFFF\uD800\uDFFF 0 + +\uDFFF\uD800+ +\uDFFF\uD800\uDFFF\uD800 +false 0 + +\uD800+\uDFFF +\uD800\uDFFF +false 0 + +\uD800+\uDFFF +\uD800 +false 0 + +\uDFFF+\uD800 +\uD800 +false 0 + +\uDFFF+\uD800 +\uDFFF\uD800 +true \uDFFF\uD800 0 + +\uD800\uDFFF{3} +\uD800\uDFFF\uDFFF\uDFFF +false 0 + +\uD800\uDFFF{3} +\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF +true \uD800\uDFFF\uD800\uDFFF\uD800\uDFFF 0 + +\uDFFF\uD800{3} +\uDFFF\uD800\uDFFF\uD800\uDFFF\uD800 +false 0 + +\uDFFF\uD800{3} +\uDFFF\uD800\uD800\uD800 +true \uDFFF\uD800\uD800\uD800 0 + +\uD800\uDFFF{2,} +\uD800\uDFFF +false 0 + +\uD800\uDFFF{2,} +\uD800\uDFFF\uDFFF +false 0 + +\uD800\uDFFF{2,} +\uD800\uDFFF\uD800\uDFFF +true \uD800\uDFFF\uD800\uDFFF 0 + +\uDFFF\uD800{2,} +\uDFFF\uD800\uDFFF\uD800 +false 0 + +\uDFFF\uD800{2,} +\uDFFF\uD800\uD800\uD800 +true \uDFFF\uD800\uD800\uD800 0 + +\uD800\uDFFF{3,4} +\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF +true \uD800\uDFFF\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF 0 + +\uD800\uDFFF{3,4} +\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF\uD800 +true \uD800\uDFFF\uD800\uDFFF\uD800\uDFFF 0 + +\uD800\uDFFF{3,4} +\uD800\uDFFF\uD800\uD800\uDFFF\uD800\uDFFF +false 0 + +\uDFFF\uD800{3,5} +\uDFFF\uD800\uD800\uD800\uD800\uD800\uD800\uD800 +true \uDFFF\uD800\uD800\uD800\uD800\uD800 0 + +\uD800\uDFFF{3,5} +\uD800\uDFFF\uDFFF\uDFFF +false 0 + +\uD800\uDFFF{3,5} +\uD800\uDFFF\uD800\uD800\uDFFF\uD800\uDFFF\uD800\uDFFF +true \uD800\uDFFF\uD800\uDFFF\uD800\uDFFF 0 + +// Groupings +(\uD800(\uDFFF)) +\uD800\uDFFF +false 2 + +(\uD800(\uDC00)(\uDFFF)) +\uD800\uDC00\uDFFF +false 3 + +((\uD800)(\uDFFF)) +\uD800\uDFFF +false 3 + +(\uD800(\uDFFF)\uDFFF) +\uD800\uDFFF +false 2 + +(\uDFFF(\uD800)(\uDBFF)) +\uDFFF\uD800\uDBFF +true \uDFFF\uD800\uDBFF 3 \uDFFF\uD800\uDBFF \uD800 \uDBFF + +(\uDFFF(\uD800)(\uDC00)) +\uDFFF\uD800\uDC00 +false 3 + +(\uDFFF\uD800(\uDC00\uDBFF)) +\uDFFF\uD800\uDC00\uDBFF +false 2 + +(\uD800\uDFFF(\uDBFF)(\uDC00)) +\uD800\uDFFF\uDBFF\uDC00 +false 3 + +(\uD800\uDFFF(\uDBFF\uDC00)) +\uD800\uDFFF\uDBFF\uDC00 +true \uD800\uDFFF\uDBFF\uDC00 2 \uD800\uDFFF\uDBFF\uDC00 \uDBFF\uDC00 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/util/regex/TestCases.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/regex/TestCases.txt Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,1092 @@ +// +// Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute 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. +// +// +// This file contains test cases for regular expressions. +// A test case consists of three lines: +// The first line is a pattern used in the test +// The second line is the input to search for the pattern in +// The third line is a concatentation of the match, the number of groups, +// and the contents of the first four subexpressions. +// Empty lines and lines beginning with comment slashes are ignored. +// +// Test unsetting of backed off groups +^(a)?a +a +true a 1 + +^(aa(bb)?)+$ +aabbaa +true aabbaa 2 aa bb + +((a|b)?b)+ +b +true b 2 b + +(aaa)?aaa +aaa +true aaa 1 + +^(a(b)?)+$ +aba +true aba 2 a b + +^(a(b(c)?)?)?abc +abc +true abc 3 + +^(a(b(c))).* +abc +true abc 3 abc bc c + +// use of x modifier +abc(?x)blah +abcblah +true abcblah 0 + +abc(?x) blah +abcblah +true abcblah 0 + +abc(?x) blah blech +abcblahblech +true abcblahblech 0 + +abc(?x) blah # ignore comment +abcblah +true abcblah 0 + +// Simple alternation +a|b +a +true a 0 + +a|b +z +false 0 + +a|b +b +true b 0 + +a|b|cd +cd +true cd 0 + +a|ad +ad +true a 0 + +z(a|ac)b +zacb +true zacb 1 ac + +// Simple char class +[abc]+ +ababab +true ababab 0 + +[abc]+ +defg +false 0 + +[abc]+[def]+[ghi]+ +zzzaaddggzzz +true aaddgg 0 + +// Range char class +[a-g]+ +zzzggg +true ggg 0 + +[a-g]+ +mmm +false 0 + +[a-]+ +za-9z +true a- 0 + +[a-\\u4444]+ +za-9z +true za 0 + +// Negated char class +[^abc]+ +ababab +false 0 + +[^abc]+ +aaabbbcccdefg +true defg 0 + +// Making sure a ^ not in first position matches literal ^ +[abc^b] +b +true b 0 + +[abc^b] +^ +true ^ 0 + +// Class union and intersection +[abc[def]] +b +true b 0 + +[abc[def]] +e +true e 0 + +[a-d[0-9][m-p]] +a +true a 0 + +[a-d[0-9][m-p]] +o +true o 0 + +[a-d[0-9][m-p]] +4 +true 4 0 + +[a-d[0-9][m-p]] +e +false 0 + +[a-d[0-9][m-p]] +u +false 0 + +[[a-d][0-9][m-p]] +b +true b 0 + +[[a-d][0-9][m-p]] +z +false 0 + +[a-c[d-f[g-i]]] +a +true a 0 + +[a-c[d-f[g-i]]] +e +true e 0 + +[a-c[d-f[g-i]]] +h +true h 0 + +[a-c[d-f[g-i]]] +m +false 0 + +[a-c[d-f[g-i]]m] +m +true m 0 + +[abc[def]ghi] +a +true a 0 + +[abc[def]ghi] +d +true d 0 + +[abc[def]ghi] +h +true h 0 + +[abc[def]ghi] +w +false 0 + +[a-c&&[d-f]] +a +false 0 + +[a-c&&[d-f]] +e +false 0 + +[a-c&&[d-f]] +z +false 0 + +[[a-c]&&[d-f]] +a +false 0 + +[[a-c]&&[d-f]] +e +false 0 + +[[a-c]&&[d-f]] +z +false 0 + +[a-c&&d-f] +a +false 0 + +[a-m&&m-z] +m +true m 0 + +[a-m&&m-z&&a-c] +m +false 0 + +[a-m&&m-z&&a-z] +m +true m 0 + +[[a-m]&&[m-z]] +a +false 0 + +[[a-m]&&[m-z]] +m +true m 0 + +[[a-m]&&[m-z]] +z +false 0 + +[[a-m]&&[^a-c]] +a +false 0 + +[[a-m]&&[^a-c]] +d +true d 0 + +[a-m&&[^a-c]] +a +false 0 + +[a-m&&[^a-c]] +d +true d 0 + +[a-cd-f&&[d-f]] +a +false 0 + +[a-cd-f&&[d-f]] +e +true e 0 + +[[a-c]&&d-fa-c] +a +true a 0 + +[[a-c]&&[d-f][a-c]] +a +true a 0 + +[[a-c][d-f]&&abc] +a +true a 0 + +[[a-c][d-f]&&abc[def]] +e +true e 0 + +[[a-c]&&[b-d]&&[c-e]] +a +false 0 + +[[a-c]&&[b-d]&&[c-e]] +c +true c 0 + +[[a-c]&&[b-d][c-e]&&[u-z]] +c +false 0 + +[abc[^bcd]] +a +true a 0 + +[abc[^bcd]] +d +false 0 + +[a-c&&a-d&&a-eghi] +b +true b 0 + +[a-c&&a-d&&a-eghi] +g +false 0 + +[[a[b]]&&[b[a]]] +a +true a 0 + +[[a]&&[b][c][a]&&[^d]] +a +true a 0 + +[[a]&&[b][c][a]&&[^d]] +d +false 0 + +[[[a-d]&&[c-f]]] +a +false 0 + +[[[a-d]&&[c-f]]] +c +true c 0 + +[[[a-d]&&[c-f]]&&[c]] +c +true c 0 + +[[[a-d]&&[c-f]]&&[c]&&c] +c +true c 0 + +[[[a-d]&&[c-f]]&&[c]&&c&&c] +c +true c 0 + +[[[a-d]&&[c-f]]&&[c]&&c&&[cde]] +c +true c 0 + +[z[abc&&bcd]] +c +true c 0 + +[z[abc&&bcd]&&[u-z]] +z +true z 0 + +[x[abc&&bcd[z]]&&[u-z]] +z +false 0 + +[x[[wz]abc&&bcd[z]]&&[u-z]] +z +true z 0 + +[[abc]&&[def]abc] +a +true a 0 + +[[abc]&&[def]xyz[abc]] +a +true a 0 + +\pL +a +true a 0 + +\pL +7 +false 0 + +\p{L} +a +true a 0 + +\p{LC} +a +true a 0 + +\p{LC} +A +true A 0 + +\p{IsL} +a +true a 0 + +\p{IsLC} +a +true a 0 + +\p{IsLC} +A +true A 0 + +\p{IsLC} +9 +false 0 + +\P{IsLC} +9 +true 9 0 + +// Guillemet left is initial quote punctuation +\p{Pi} +\u00ab +true \u00ab 0 + +\P{Pi} +\u00ac +true \u00ac 0 + +// Guillemet right is final quote punctuation +\p{IsPf} +\u00bb +true \u00bb 0 + +\p{P} +\u00bb +true \u00bb 0 + +\p{P}+ +\u00bb +true \u00bb 0 + +\P{IsPf} +\u00bc +true \u00bc 0 + +\P{IsP} +\u00bc +true \u00bc 0 + +\p{L1} +\u00bc +true \u00bc 0 + +\p{L1}+ +\u00bc +true \u00bc 0 + +\p{L1} +\u02bc +false 0 + +\p{ASCII} +a +true a 0 + +\p{IsASCII} +a +true a 0 + +\p{IsASCII} +\u0370 +false 0 + +\pLbc +abc +true abc 0 + +a[r\p{InGreek}]c +a\u0370c +true a\u0370c 0 + +a\p{InGreek} +a\u0370 +true a\u0370 0 + +a\P{InGreek} +a\u0370 +false 0 + +a\P{InGreek} +ab +true ab 0 + +a{^InGreek} +- +error + +a\p{^InGreek} +- +error + +a\P{^InGreek} +- +error + +a\p{InGreek} +a\u0370 +true a\u0370 0 + +a[\p{InGreek}]c +a\u0370c +true a\u0370c 0 + +a[\P{InGreek}]c +a\u0370c +false 0 + +a[\P{InGreek}]c +abc +true abc 0 + +a[{^InGreek}]c +anc +true anc 0 + +a[{^InGreek}]c +azc +false 0 + +a[\p{^InGreek}]c +- +error + +a[\P{^InGreek}]c +- +error + +a[\p{InGreek}] +a\u0370 +true a\u0370 0 + +a[r\p{InGreek}]c +arc +true arc 0 + +a[\p{InGreek}r]c +arc +true arc 0 + +a[r\p{InGreek}]c +arc +true arc 0 + +a[^\p{InGreek}]c +a\u0370c +false 0 + +a[^\P{InGreek}]c +a\u0370c +true a\u0370c 0 + +a[\p{InGreek}&&[^\u0370]]c +a\u0370c +false 0 + +// Test the dot metacharacter +a.c.+ +a#c%& +true a#c%& 0 + +ab. +ab\n +false 0 + +(?s)ab. +ab\n +true ab\n 0 + +a[\p{L}&&[\P{InGreek}]]c +a\u6000c +true a\u6000c 0 + +a[\p{L}&&[\P{InGreek}]]c +arc +true arc 0 + +a[\p{L}&&[\P{InGreek}]]c +a\u0370c +false 0 + +a\p{InGreek}c +a\u0370c +true a\u0370c 0 + +a\p{Sc} +a$ +true a$ 0 + +// Test the word char escape sequence +ab\wc +abcc +true abcc 0 + +\W\w\W +#r# +true #r# 0 + +\W\w\W +rrrr#ggg +false 0 + +abc[\w] +abcd +true abcd 0 + +abc[\sdef]* +abc def +true abc def 0 + +abc[\sy-z]* +abc y z +true abc y z 0 + +abc[a-d\sm-p]* +abcaa mn p +true abcaa mn p 0 + +// Test the whitespace escape sequence +ab\sc +ab c +true ab c 0 + +\s\s\s +blah err +false 0 + +\S\S\s +blah err +true ah 0 + +// Test the digit escape sequence +ab\dc +ab9c +true ab9c 0 + +\d\d\d +blah45 +false 0 + +// Test the caret metacharacter +^abc +abcdef +true abc 0 + +^abc +bcdabc +false 0 + +// Greedy ? metacharacter +a?b +aaaab +true ab 0 + +a?b +b +true b 0 + +a?b +aaaccc +false 0 + +.?b +aaaab +true ab 0 + +// Reluctant ? metacharacter +a??b +aaaab +true ab 0 + +a??b +b +true b 0 + +a??b +aaaccc +false 0 + +.??b +aaaab +true ab 0 + +// Possessive ? metacharacter +a?+b +aaaab +true ab 0 + +a?+b +b +true b 0 + +a?+b +aaaccc +false 0 + +.?+b +aaaab +true ab 0 + +// Greedy + metacharacter +a+b +aaaab +true aaaab 0 + +a+b +b +false 0 + +a+b +aaaccc +false 0 + +.+b +aaaab +true aaaab 0 + +// Reluctant + metacharacter +a+?b +aaaab +true aaaab 0 + +a+?b +b +false 0 + +a+?b +aaaccc +false 0 + +.+?b +aaaab +true aaaab 0 + +// Possessive + metacharacter +a++b +aaaab +true aaaab 0 + +a++b +b +false 0 + +a++b +aaaccc +false 0 + +.++b +aaaab +false 0 + +// Greedy Repetition +a{2,3} +a +false 0 + +a{2,3} +aa +true aa 0 + +a{2,3} +aaa +true aaa 0 + +a{2,3} +aaaa +true aaa 0 + +a{3,} +zzzaaaazzz +true aaaa 0 + +a{3,} +zzzaazzz +false 0 + +// Reluctant Repetition +a{2,3}? +a +false 0 + +a{2,3}? +aa +true aa 0 + +a{2,3}? +aaa +true aa 0 + +a{2,3}? +aaaa +true aa 0 + +// Zero width Positive lookahead +abc(?=d) +zzzabcd +true abc 0 + +abc(?=d) +zzzabced +false 0 + +// Zero width Negative lookahead +abc(?!d) +zzabcd +false 0 + +abc(?!d) +zzabced +true abc 0 + +// Zero width Positive lookbehind +\w(?<=a) +###abc### +true a 0 + +\w(?<=a) +###ert### +false 0 + +// Zero width Negative lookbehind +(?3 +// So that the BM optimization is part of test +\Q***\Eabc +***abc +true ***abc 0 + +bl\Q***\Eabc +bl***abc +true bl***abc 0 + +\Q***abc +***abc +true ***abc 0 + +blah\Q***\Eabc +blah***abc +true blah***abc 0 + +\Q***abc +***abc +true ***abc 0 + +\Q*ab +*ab +true *ab 0 + +blah\Q***abc +blah***abc +true blah***abc 0 + +bla\Q***abc +bla***abc +true bla***abc 0 + +// Escapes in char classes +[ab\Qdef\E] +d +true d 0 + +[ab\Q[\E] +[ +true [ 0 + +[\Q]\E] +] +true ] 0 + +[\Q\\E] +\ +true \ 0 + +[\Q(\E] +( +true ( 0 + +[\n-#] +! +true ! 0 + +[\n-#] +- +false 0 + +[\w-#] +! +false 0 + +[\w-#] +a +true a 0 + +[\w-#] +- +true - 0 + +[\w-#] +# +true # 0 + +[\043]+ +blahblah#blech +true # 0 + +[\042-\044]+ +blahblah#blech +true # 0 + +[\u1234-\u1236] +blahblah\u1235blech +true \u1235 0 + +[^\043]* +blahblah#blech +true blahblah 0 + +(|f)?+ +foo +true 1 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/java/util/zip/ZipFile/LargeZipFile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/zip/ZipFile/LargeZipFile.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,138 @@ +import java.io.*; +import java.nio.*; +import java.util.*; +import java.util.zip.*; + +public class LargeZipFile { + // If true, don't delete large ZIP file created for test. + static final boolean debug = System.getProperty("debug") != null; + + static final int DATA_LEN = 1024 * 1024; + static final int DATA_SIZE = 8; + + static long fileSize = 3L * 1024L * 1024L * 1024L; // 3GB + + static boolean userFile = false; + + static byte[] data; + static File largeFile; + static String lastEntryName; + + /* args can be empty, in which case check a 3 GB file which is created for + * this test (and then deleted). Or it can be a number, in which case + * that designates the size of the file that's created for this test (and + * then deleted). Or it can be the name of a file to use for the test, in + * which case it is *not* deleted. Note that in this last case, the data + * comparison might fail. + */ + static void realMain (String[] args) throws Throwable { + if (args.length > 0) { + try { + fileSize = Long.parseLong(args[0]); + System.out.println("Testing with file of size " + fileSize); + } catch (NumberFormatException ex) { + largeFile = new File(args[0]); + if (!largeFile.exists()) { + throw new Exception("Specified file " + args[0] + " does not exist"); + } + userFile = true; + System.out.println("Testing with user-provided file " + largeFile); + } + } + File testDir = null; + if (largeFile == null) { + testDir = new File(System.getProperty("test.scratch", "."), + "LargeZip"); + if (testDir.exists()) { + if (!testDir.delete()) { + throw new Exception("Cannot delete already-existing test directory"); + } + } + check(!testDir.exists() && testDir.mkdirs()); + largeFile = new File(testDir, "largezip.zip"); + createLargeZip(); + } + + readLargeZip(); + + if (!userFile && !debug) { + check(largeFile.delete()); + check(testDir.delete()); + } + } + + static void createLargeZip() throws Throwable { + int iterations = DATA_LEN / DATA_SIZE; + ByteBuffer bb = ByteBuffer.allocate(DATA_SIZE); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < iterations; i++) { + bb.putDouble(0, Math.random()); + baos.write(bb.array(), 0, DATA_SIZE); + } + data = baos.toByteArray(); + + ZipOutputStream zos = new ZipOutputStream( + new BufferedOutputStream(new FileOutputStream(largeFile))); + long length = 0; + while (length < fileSize) { + ZipEntry ze = new ZipEntry("entry-" + length); + lastEntryName = ze.getName(); + zos.putNextEntry(ze); + zos.write(data, 0, data.length); + zos.closeEntry(); + length = largeFile.length(); + } + System.out.println("Last entry written is " + lastEntryName); + zos.close(); + } + + static void readLargeZip() throws Throwable { + ZipFile zipFile = new ZipFile(largeFile); + ZipEntry entry = null; + String entryName = null; + int count = 0; + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + entry = entries.nextElement(); + entryName = entry.getName(); + count++; + } + System.out.println("Number of entries read: " + count); + System.out.println("Last entry read is " + entryName); + check(!entry.isDirectory()); + if (check(entryName.equals(lastEntryName))) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream is = zipFile.getInputStream(entry); + byte buf[] = new byte[4096]; + int len; + while ((len = is.read(buf)) >= 0) { + baos.write(buf, 0, len); + } + baos.close(); + is.close(); + check(Arrays.equals(data, baos.toByteArray())); + } + try { + zipFile.close(); + } catch (IOException ioe) {/* what can you do */ } + } + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + static void pass() {passed++;} + static void pass(String msg) {System.out.println(msg); passed++;} + static void fail() {failed++; Thread.dumpStack();} + static void fail(String msg) {System.out.println(msg); fail();} + static void unexpected(Throwable t) {failed++; t.printStackTrace();} + static void unexpected(Throwable t, String msg) { + System.out.println(msg); failed++; t.printStackTrace();} + static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;} + static void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + try {realMain(args);} catch (Throwable t) {unexpected(t);} + System.out.println("\nPassed = " + passed + " failed = " + failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} + diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/sun/security/krb5/ParseCAPaths.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/krb5/ParseCAPaths.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,98 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 6789935 + * @summary cross-realm capath search error + */ + +import java.util.Arrays; +import sun.security.krb5.Realm; + +public class ParseCAPaths { + static boolean failed = false; + public static void main(String[] args) throws Exception { + System.setProperty("java.security.krb5.conf", System.getProperty("test.src", ".") +"/krb5-capaths.conf"); + //System.setProperty("sun.security.krb5.debug", "true"); + + // Standard example + check("ANL.GOV", "TEST.ANL.GOV", "ANL.GOV"); + check("ANL.GOV", "ES.NET", "ANL.GOV"); + check("ANL.GOV", "PNL.GOV", "ANL.GOV", "ES.NET"); + check("ANL.GOV", "NERSC.GOV", "ANL.GOV", "ES.NET"); + // Hierachical + check("N1.N.COM", "N2.N.COM", "N1.N.COM", "N.COM"); // 2 common + check("N1.N.COM", "N2.N3.COM", "N1.N.COM", "N.COM", // 1 common + "COM", "N3.COM"); + check("N1.COM", "N2.COM", "N1.COM", "COM"); // 1 common + check("N1", "N2", "N1"); // 0 common + // Extra garbages + check("A1.COM", "A4.COM", "A1.COM", "A2.COM"); + check("B1.COM", "B3.COM", "B1.COM", "B2.COM"); + // Missing is "." + check("C1.COM", "C3.COM", "C1.COM", "C2.COM"); + // Multiple path + check("D1.COM", "D4.COM", "D1.COM", "D2.COM"); + check("E1.COM", "E4.COM", "E1.COM", "E2.COM"); + check("F1.COM", "F4.COM", "F1.COM", "F9.COM"); + // Infinite loop + check("G1.COM", "G3.COM", "G1.COM", "COM"); + check("H1.COM", "H3.COM", "H1.COM"); + check("I1.COM", "I4.COM", "I1.COM", "I5.COM"); + + if (failed) { + throw new Exception("Failed somewhere."); + } + } + + static void check(String from, String to, String... paths) { + try { + check2(from, to, paths); + } catch (Exception e) { + failed = true; + e.printStackTrace(); + } + } + static void check2(String from, String to, String... paths) + throws Exception { + System.out.println(from + " -> " + to); + System.out.println(" expected: " + Arrays.toString(paths)); + String[] result = Realm.getRealmsList(from, to); + System.out.println(" result: " + Arrays.toString(result)); + if (result == null) { + if (paths.length == 0) { + // OK + } else { + throw new Exception("Shouldn't have a valid path."); + } + } else if(result.length != paths.length) { + throw new Exception("Length of path not correct"); + } else { + for (int i=0; i bs = ((X509Certificate)ks.getCertificate(alias)).getExtendedKeyUsage(); + int found = 0; + for (String p: pos) { + if (bs.contains(p)) { + found++; + } else { + throw new RuntimeException("EKU: not included " + p); + } + } + if (found != bs.size()) { + throw new RuntimeException("EKU: more items than expected"); + } + } + } + CheckEKU cx = new CheckEKU(); + assertTrue(((X509CertImpl)ks.getCertificate("eku1")).getExtension(PKIXExtensions.ExtendedKeyUsage_Id).isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("eku2")).getExtension(PKIXExtensions.ExtendedKeyUsage_Id).isCritical()); + cx.check(ks, "eku1", "1.3.6.1.5.5.7.3.1"); + cx.check(ks, "eku2", "1.3.6.1.5.5.7.3.2"); + cx.check(ks, "eku3", "1.3.6.1.5.5.7.3.3"); + cx.check(ks, "eku4", "1.3.6.1.5.5.7.3.4"); + cx.check(ks, "eku8", "1.3.6.1.5.5.7.3.8"); + cx.check(ks, "eku9", "1.3.6.1.5.5.7.3.9"); + cx.check(ks, "eku10", "2.5.29.37.0"); + cx.check(ks, "eku11", "1.3.6.1.5.5.7.3.4", "1.2.3.4", "1.3.5.7"); + + // SAN + testOK("", pre+"san1 -ext san:critical=email:me@me.org"); + testOK("", pre+"san2 -ext san=uri:http://me.org"); + testOK("", pre+"san3 -ext san=dns:me.org"); + testOK("", pre+"san4 -ext san=ip:192.168.0.1"); + testOK("", pre+"san5 -ext san=oid:1.2.3.4"); + testOK("", pre+"san235 -ext san=uri:http://me.org,dns:me.org,oid:1.2.3.4"); + + ks = loadStore("x.jks", "changeit", "JKS"); + class CheckSAN { + // Please sort items with name type + void check(KeyStore ks, String alias, int type, Object... items) throws Exception { + int pos = 0; + System.err.print("x"); + Object[] names = null; + if (type == 0) names = ((X509Certificate)ks.getCertificate(alias)).getSubjectAlternativeNames().toArray(); + else names = ((X509Certificate)ks.getCertificate(alias)).getIssuerAlternativeNames().toArray(); + Arrays.sort(names, new Comparator() { + public int compare(Object o1, Object o2) { + int i1 = (Integer)((List)o1).get(0); + int i2 = (Integer)((List)o2).get(0); + return i1 - i2; + } + }); + for (Object o: names) { + List l = (List)o; + for (Object o2: l) { + if (!items[pos++].equals(o2)) { + throw new RuntimeException("Not equals at " + pos + + ": " + items[pos-1] + " vs " + o2); + } + } + } + if (pos != items.length) { + throw new RuntimeException("Extra items, pos is " + pos); + } + } + } + CheckSAN csan = new CheckSAN(); + assertTrue(((X509CertImpl)ks.getCertificate("san1")).getSubjectAlternativeNameExtension().isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("san2")).getSubjectAlternativeNameExtension().isCritical()); + csan.check(ks, "san1", 0, 1, "me@me.org"); + csan.check(ks, "san2", 0, 6, "http://me.org"); + csan.check(ks, "san3", 0, 2, "me.org"); + csan.check(ks, "san4", 0, 7, "192.168.0.1"); + csan.check(ks, "san5", 0, 8, "1.2.3.4"); + csan.check(ks, "san235", 0, 2, "me.org", 6, "http://me.org", 8, "1.2.3.4"); + + // IAN + testOK("", pre+"ian1 -ext ian:critical=email:me@me.org"); + testOK("", pre+"ian2 -ext ian=uri:http://me.org"); + testOK("", pre+"ian3 -ext ian=dns:me.org"); + testOK("", pre+"ian4 -ext ian=ip:192.168.0.1"); + testOK("", pre+"ian5 -ext ian=oid:1.2.3.4"); + testOK("", pre+"ian235 -ext ian=uri:http://me.org,dns:me.org,oid:1.2.3.4"); + + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(((X509CertImpl)ks.getCertificate("ian1")).getIssuerAlternativeNameExtension().isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("ian2")).getIssuerAlternativeNameExtension().isCritical()); + csan.check(ks, "ian1", 1, 1, "me@me.org"); + csan.check(ks, "ian2", 1, 6, "http://me.org"); + csan.check(ks, "ian3", 1, 2, "me.org"); + csan.check(ks, "ian4", 1, 7, "192.168.0.1"); + csan.check(ks, "ian5", 1, 8, "1.2.3.4"); + csan.check(ks, "ian235", 1, 2, "me.org", 6, "http://me.org", 8, "1.2.3.4"); + + // SIA + testOK("", pre+"sia1 -ext sia=care:uri:ldap://ca.com/cn=CA"); + testOK("", pre+"sia2 -ext sia=ts:email:ts@ca.com"); + testFail("SIA never critical", pre+"sia3 -ext sia:critical=ts:email:ts@ca.com"); + + ks = loadStore("x.jks", "changeit", "JKS"); + class CheckSia { + void check(KeyStore ks, String alias, int type, Object... items) throws Exception { + int pos = 0; + System.err.print("x"); + AccessDescription[] ads = null; + if (type == 0) { + SubjectInfoAccessExtension siae = (SubjectInfoAccessExtension)((X509CertImpl)ks.getCertificate(alias)).getExtension(PKIXExtensions.SubjectInfoAccess_Id); + ads = siae.getAccessDescriptions().toArray(new AccessDescription[0]); + } else { + AuthorityInfoAccessExtension aiae = (AuthorityInfoAccessExtension)((X509CertImpl)ks.getCertificate(alias)).getExtension(PKIXExtensions.AuthInfoAccess_Id); + ads = aiae.getAccessDescriptions().toArray(new AccessDescription[0]); + } + Arrays.sort(ads, new Comparator() { + @Override + public int compare(AccessDescription o1, AccessDescription o2) { + return o1.getAccessMethod().toString().compareTo(o2.getAccessMethod().toString()); + } + }); + for (AccessDescription ad: ads) { + if (!ad.getAccessMethod().equals(items[pos++]) || + !new Integer(ad.getAccessLocation().getType()).equals(items[pos++])) { + throw new RuntimeException("Not same type at " + pos); + } + String name = null; + switch (ad.getAccessLocation().getType()) { + case 1: + name = ((RFC822Name)ad.getAccessLocation().getName()).getName(); + break; + case 6: + name = ((URIName)ad.getAccessLocation().getName()).getURI().toString(); + break; + default: + throw new RuntimeException("Not implemented: " + ad); + } + if (!name.equals(items[pos++])) { + throw new Exception("Name not same for " + ad + " at pos " + pos); + } + } + } + } + CheckSia csia = new CheckSia(); + assertTrue(!((X509CertImpl)ks.getCertificate("sia1")).getExtension(PKIXExtensions.SubjectInfoAccess_Id).isCritical()); + csia.check(ks, "sia1", 0, AccessDescription.Ad_CAREPOSITORY_Id, 6, "ldap://ca.com/cn=CA"); + csia.check(ks, "sia2", 0, AccessDescription.Ad_TIMESTAMPING_Id, 1, "ts@ca.com"); + + // AIA + testOK("", pre+"aia1 -ext aia=cai:uri:ldap://ca.com/cn=CA"); + testOK("", pre+"aia2 -ext aia=ocsp:email:ocsp@ca.com"); + testFail("AIA never critical", pre+"aia3 -ext aia:critical=ts:email:ts@ca.com"); + + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(!((X509CertImpl)ks.getCertificate("aia1")).getExtension(PKIXExtensions.AuthInfoAccess_Id).isCritical()); + csia.check(ks, "aia1", 1, AccessDescription.Ad_CAISSUERS_Id, 6, "ldap://ca.com/cn=CA"); + csia.check(ks, "aia2", 1, AccessDescription.Ad_OCSP_Id, 1, "ocsp@ca.com"); + + // OID + testOK("", pre+"oid1 -ext 1.2.3:critical=0102"); + testOK("", pre+"oid2 -ext 1.2.3"); + testOK("", pre+"oid12 -ext 1.2.3 -ext 1.2.4=01:02:03"); + + ks = loadStore("x.jks", "changeit", "JKS"); + class CheckOid { + void check(KeyStore ks, String alias, String oid, byte[] value) throws Exception { + int pos = 0; + System.err.print("x"); + Extension ex = ((X509CertImpl)ks.getCertificate(alias)).getExtension(new ObjectIdentifier(oid)); + if (!Arrays.equals(value, ex.getValue())) { + throw new RuntimeException("Not same content in " + alias + " for " + oid); + } + } + } + CheckOid coid = new CheckOid(); + assertTrue(((X509CertImpl)ks.getCertificate("oid1")).getExtension(new ObjectIdentifier("1.2.3")).isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("oid2")).getExtension(new ObjectIdentifier("1.2.3")).isCritical()); + coid.check(ks, "oid1", "1.2.3", new byte[]{1,2}); + coid.check(ks, "oid2", "1.2.3", new byte[]{}); + coid.check(ks, "oid12", "1.2.3", new byte[]{}); + coid.check(ks, "oid12", "1.2.4", new byte[]{1,2,3}); + + // honored + testOK("", pre+"ca"); + testOK("", pre+"a"); + // request: BC,KU,1.2.3,1.2.4,1.2.5 + testOK("", simple+"-alias a -certreq " + + "-ext BC=1 -ext KU=crl " + + "-ext 1.2.3=01 -ext 1.2.4:critical=0102 -ext 1.2.5=010203 " + + "-rfc -file test.req"); + // printcertreq + testOK("", "-printcertreq -file test.req"); + // issue: deny KU, change criticality of 1.2.3 and 1.2.4, change content of BC, add 2.3.4 + testOK("", simple+"-gencert -alias ca -infile test.req -ext " + + "honored=all,-KU,1.2.3:critical,1.2.4:non-critical " + + "-ext BC=2 -ext 2.3.4=01020304 " + + "-debug -rfc -outfile test.cert"); + testOK("", simple+"-importcert -file test.cert -alias a"); + ks = loadStore("x.jks", "changeit", "JKS"); + X509CertImpl a = (X509CertImpl)ks.getCertificate("a"); + assertTrue(a.getAuthorityKeyIdentifierExtension() != null); + assertTrue(a.getSubjectKeyIdentifierExtension() != null); + assertTrue(a.getKeyUsage() == null); + assertTrue(a.getExtension(new ObjectIdentifier("1.2.3")).isCritical()); + assertTrue(!a.getExtension(new ObjectIdentifier("1.2.4")).isCritical()); + assertTrue(!a.getExtension(new ObjectIdentifier("1.2.5")).isCritical()); + assertTrue(a.getExtensionValue("1.2.3").length == 3); + assertTrue(a.getExtensionValue("1.2.4").length == 4); + assertTrue(a.getExtensionValue("1.2.5").length == 5); + assertTrue(a.getBasicConstraints() == 2); + assertTrue(!a.getExtension(new ObjectIdentifier("2.3.4")).isCritical()); + assertTrue(a.getExtensionValue("2.3.4").length == 6); + + remove("x.jks"); + remove("test.req"); + remove("test.cert"); + } + void i18nTest() throws Exception { // 1. keytool -help remove("x.jks"); - try { - test("", "-help"); - assertTrue(false, "Cannot come here"); - } catch(RuntimeException e) { - assertTrue(e.getMessage().indexOf("NO ERROR, SORRY") != -1, "No error"); - } + testOK("", "-help"); + // 2. keytool -genkey -v -keysize 512 Enter "a" for the keystore password. Check error (password too short). Enter "password" for the keystore password. Hit 'return' for "first and last name", "organizational unit", "City", "State", and "Country Code". Type "yes" when they ask you if everything is correct. Type 'return' for new key password. testOK("a\npassword\npassword\nMe\nHere\nNow\nPlace\nPlace\nUS\nyes\n\n", "-genkey -v -keysize 512 -keystore x.jks"); // 3. keytool -list -v -storepass password testOK("", "-list -v -storepass password -keystore x.jks"); // 4. keytool -list -v Type "a" for the keystore password. Check error (wrong keystore password). testFail("a\n", "-list -v -keystore x.jks"); - assertTrue(ex.indexOf("password was incorrect") != -1, ""); + assertTrue(ex.indexOf("password was incorrect") != -1); // 5. keytool -genkey -v -keysize 512 Enter "password" as the password. Check error (alias 'mykey' already exists). testFail("password\n", "-genkey -v -keysize 512 -keystore x.jks"); - assertTrue(ex.indexOf("alias already exists") != -1, ""); + assertTrue(ex.indexOf("alias already exists") != -1); // 6. keytool -genkey -v -keysize 512 -alias mykey2 -storepass password Hit 'return' for "first and last name", "organizational unit", "City", "State", and "Country Code". Type "yes" when they ask you if everything is correct. Type 'return' for new key password. testOK("\n\n\n\n\n\nyes\n\n", "-genkey -v -keysize 512 -alias mykey2 -storepass password -keystore x.jks"); // 7. keytool -list -v Type 'password' for the store password. testOK("password\n", "-list -v -keystore x.jks"); // 8. keytool -keypasswd -v -alias mykey2 -storepass password Type "a" for the new key password. Type "aaaaaa" for the new key password. Type "bbbbbb" when re-entering the new key password. Type "a" for the new key password. Check Error (too many failures). testFail("a\naaaaaa\nbbbbbb\na\n", "-keypasswd -v -alias mykey2 -storepass password -keystore x.jks"); - assertTrue(ex.indexOf("Too many failures - try later") != -1, ""); + assertTrue(ex.indexOf("Too many failures - try later") != -1); // 9. keytool -keypasswd -v -alias mykey2 -storepass password Type "aaaaaa" for the new key password. Type "aaaaaa" when re-entering the new key password. testOK("aaaaaa\naaaaaa\n", "-keypasswd -v -alias mykey2 -storepass password -keystore x.jks"); // 10. keytool -selfcert -v -alias mykey -storepass password @@ -864,7 +1207,7 @@ testOK("", "-export -v -alias mykey -file cert -storepass password -keystore x.jks"); // 13. keytool -import -v -file cert -storepass password Check error (Certificate reply and cert are the same) testFail("", "-import -v -file cert -storepass password -keystore x.jks"); - assertTrue(ex.indexOf("Certificate reply and certificate in keystore are identical") != -1, ""); + assertTrue(ex.indexOf("Certificate reply and certificate in keystore are identical") != -1); // 14. keytool -printcert -file cert testOK("", "-printcert -file cert -keystore x.jks"); remove("cert"); @@ -875,26 +1218,26 @@ // 1. keytool -storepasswd -storepass password -new abc Check error (password too short) testFail("", "-storepasswd -storepass password -new abc"); - assertTrue(ex.indexOf("New password must be at least 6 characters") != -1, ""); + assertTrue(ex.indexOf("New password must be at least 6 characters") != -1); // Changed, no NONE needed now // 2. keytool -list -storetype PKCS11 Check error (-keystore must be NONE) //testFail("", "-list -storetype PKCS11"); - //assertTrue(err.indexOf("keystore must be NONE") != -1, ""); + //assertTrue(err.indexOf("keystore must be NONE") != -1); // 3. keytool -storepasswd -storetype PKCS11 -keystore NONE Check error (unsupported operation) testFail("", "-storepasswd -storetype PKCS11 -keystore NONE"); - assertTrue(ex.indexOf("UnsupportedOperationException") != -1, ""); + assertTrue(ex.indexOf("UnsupportedOperationException") != -1); // 4. keytool -keypasswd -storetype PKCS11 -keystore NONE Check error (unsupported operation) testFail("", "-keypasswd -storetype PKCS11 -keystore NONE"); - assertTrue(ex.indexOf("UnsupportedOperationException") != -1, ""); + assertTrue(ex.indexOf("UnsupportedOperationException") != -1); // 5. keytool -list -protected -storepass password Check error (password can not be specified with -protected) testFail("", "-list -protected -storepass password -keystore x.jks"); - assertTrue(ex.indexOf("if -protected is specified, then") != -1, ""); + assertTrue(ex.indexOf("if -protected is specified, then") != -1); // 6. keytool -keypasswd -protected -keypass password Check error (password can not be specified with -protected) testFail("", "-keypasswd -protected -keypass password -keystore x.jks"); - assertTrue(ex.indexOf("if -protected is specified, then") != -1, ""); + assertTrue(ex.indexOf("if -protected is specified, then") != -1); // 7. keytool -keypasswd -protected -new password Check error (password can not be specified with -protected) testFail("", "-keypasswd -protected -new password -keystore x.jks"); - assertTrue(ex.indexOf("if -protected is specified, then") != -1, ""); + assertTrue(ex.indexOf("if -protected is specified, then") != -1); remove("x.jks"); } @@ -911,11 +1254,11 @@ testOK("", "-printcert -file genkey.cert"); testOK("", p11Arg + "-storepass test12 -selfcert -alias genkey -dname cn=selfCert"); testOK("", p11Arg + "-storepass test12 -list -alias genkey -v"); - assertTrue(out.indexOf("Owner: CN=selfCert") != -1, ""); + assertTrue(out.indexOf("Owner: CN=selfCert") != -1); //(check that cert subject DN is [cn=selfCert]) testOK("", p11Arg + "-storepass test12 -delete -alias genkey"); testOK("", p11Arg + "-storepass test12 -list"); - assertTrue(out.indexOf("Your keystore contains 0 entries") != -1, ""); + assertTrue(out.indexOf("Your keystore contains 0 entries") != -1); //(check for empty database listing) //Runtime.getRuntime().exec("/usr/ccs/bin/sccs unedit cert8.db key3.db"); remove("genkey.cert"); @@ -943,6 +1286,15 @@ t.sqeTest(); t.testAll(); t.i18nTest(); + t.v3extTest("RSA"); + t.v3extTest("DSA"); + boolean testEC = true; + try { + KeyPairGenerator.getInstance("EC"); + } catch (NoSuchAlgorithmException nae) { + testEC = false; + } + if (testEC) t.v3extTest("EC"); } if (System.getProperty("nss") != null) { diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/sun/security/tools/keytool/autotest.sh --- a/jdk/test/sun/security/tools/keytool/autotest.sh Wed Jul 05 16:47:52 2017 +0200 +++ b/jdk/test/sun/security/tools/keytool/autotest.sh Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ # -# Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2006-2009 Sun Microsystems, Inc. All Rights Reserved. # 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,8 @@ # @summary (almost) all keytool behaviors # @author Weijun Wang # +# This test is only executed on several platforms +# # set a few environment variables so that the shell-script can run stand-alone # in the source directory if [ "${TESTSRC}" = "" ] ; then @@ -88,7 +90,7 @@ chmod u+w key3.db chmod u+w cert8.db -echo | ${TESTJAVA}${FS}bin${FS}java -Dfile -Dnss \ +echo | ${TESTJAVA}${FS}bin${FS}java -Dnss \ -Dnss.lib=${NSS}${FS}lib${FS}${PF}${FS}${LIBNAME} \ KeyToolTest status=$? @@ -99,8 +101,8 @@ rm -f secmod.db rm HumanInputStream*.class -rm KeyToolTest.class -rm TestException.class +rm KeyToolTest*.class +rm TestException.class exit $status diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/sun/security/tools/keytool/standard.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/tools/keytool/standard.sh Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,64 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute 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 (almost) all keytool behaviors +# @author Weijun Wang +# +# This test is always excecuted. +# +# set a few environment variables so that the shell-script can run stand-alone +# in the source directory +if [ "${TESTSRC}" = "" ] ; then + TESTSRC="." +fi +if [ "${TESTCLASSES}" = "" ] ; then + TESTCLASSES="." +fi +if [ "${TESTJAVA}" = "" ] ; then + JAVAC_CMD=`which javac` + TESTJAVA=`dirname $JAVAC_CMD`/.. +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + Windows_* ) + FS="\\" + ;; + * ) + FS="/" + ;; +esac + +${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}KeyToolTest.java || exit 10 + +echo | ${TESTJAVA}${FS}bin${FS}java -Dfile KeyToolTest +status=$? + +rm HumanInputStream*.class +rm KeyToolTest*.class +rm TestException.class + +exit $status + diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/sun/security/util/DerValue/EmptyValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/util/DerValue/EmptyValue.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,44 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 6804045 + * @summary DerValue does not accept empty OCTET STRING + */ + +import sun.security.util.DerValue; + +public class EmptyValue { + + public static void main(String[] args) throws Exception { + DerValue v = new DerValue(new byte[]{4,0}); + if (v.getOctetString().length != 0) { + throw new Exception("Get octet string error"); + } + v = new DerValue(new byte[]{0x30,0}); + if (v.data.available() != 0) { + throw new Exception("Get sequence error"); + } + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 jdk/test/sun/security/x509/Extensions/BCNull.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/x509/Extensions/BCNull.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,37 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 BasicConstraintsExtension does not encode when (ca==false && pathLen<0) + * @bug 6803376 + */ + +import sun.security.x509.BasicConstraintsExtension; +import java.io.ByteArrayOutputStream; + +public class BCNull { + public static void main(String [] args) throws Exception { + new BasicConstraintsExtension(false, -1).encode(new ByteArrayOutputStream()); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/.hgtags --- a/langtools/.hgtags Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/.hgtags Wed Jul 05 16:48:21 2017 +0200 @@ -23,3 +23,4 @@ be546a6c08e3c31fba2edcae1de43ae3515d2e59 jdk7-b46 2b8f6bab23926aa32b9cf7e4c540b9d1ce74b7d5 jdk7-b47 c53007f34195f69223bdd4125ec6c0740f7d6736 jdk7-b48 +d17d927ad9bdfafae32451645d182acb7bed7be6 jdk7-b49 diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java Wed Jul 05 16:48:21 2017 +0200 @@ -245,6 +245,29 @@ } /** + * Check whether there are any tags to be printed. + * + * @param doc the Doc object to check for tags. + * @return true if there are tags to be printed else return false. + */ + protected boolean hasTagsToPrint(Doc doc) { + if (doc instanceof MethodDoc) { + ClassDoc[] intfacs = ((MethodDoc)doc).containingClass().interfaces(); + MethodDoc overriddenMethod = ((MethodDoc)doc).overriddenMethod(); + if ((intfacs.length > 0 && + new ImplementedMethods((MethodDoc)doc, this.configuration).build().length > 0) || + overriddenMethod != null) { + return true; + } + } + TagletOutputImpl output = new TagletOutputImpl(""); + TagletWriter.genTagOuput(configuration.tagletManager, doc, + configuration.tagletManager.getCustomTags(doc), + getTagletWriterInstance(false), output); + return (output.toString().trim().isEmpty()); + } + + /** * Returns a TagletWriter that knows how to write HTML. * * @return a TagletWriter that knows how to write HTML. diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlSerialFieldWriter.java --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlSerialFieldWriter.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlSerialFieldWriter.java Wed Jul 05 16:48:21 2017 +0200 @@ -164,4 +164,20 @@ public void writeMemberFooter(FieldDoc member) { writer.dlEnd(); } + + /** + * Check to see if member details should be printed. If + * nocomment option set or if there is no text to be printed + * for deprecation info, inline comment, no serial tag or inline tags, + * do not print member details. + */ + public boolean shouldPrintMemberDetails(FieldDoc field) { + if (!configuration().nocomment) + if((field.inlineTags().length > 0) || + (field.tags("serial").length > 0) || (writer.hasTagsToPrint(field))) + return true; + if (!Util.isDeprecated(field)) + return true; + return false; + } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/doclets/formats/html/TagletOutputImpl.java --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TagletOutputImpl.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TagletOutputImpl.java Wed Jul 05 16:48:21 2017 +0200 @@ -67,4 +67,10 @@ return output.toString(); } + /** + * Check whether the taglet output is empty. + */ + public boolean isEmpty() { + return (toString().trim().isEmpty()); + } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/SerializedFormWriter.java --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/SerializedFormWriter.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/SerializedFormWriter.java Wed Jul 05 16:48:21 2017 +0200 @@ -152,6 +152,17 @@ * @param member the member to write the header for. */ public void writeMemberFooter(FieldDoc member); + + /** + * Check to see if member details should be printed. If + * nocomment option set or if there is no text to be printed + * for deprecation info, inline comment, no serial tag or inline tags, + * do not print member details. + * + * @param member the member to check details for. + * @return true if details need to be printed + */ + public boolean shouldPrintMemberDetails(FieldDoc member); } /** diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/SerializedFormBuilder.java --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/SerializedFormBuilder.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/builders/SerializedFormBuilder.java Wed Jul 05 16:48:21 2017 +0200 @@ -403,16 +403,17 @@ if (classDoc.definesSerializableFields()) { FieldDoc serialPersistentField = Util.asList(classDoc.serializableFields()).get(0); - String comment = serialPersistentField.commentText(); - if (comment.length() > 0) { + // Check to see if there are inline comments, tags or deprecation + // information to be printed. + if (fieldWriter.shouldPrintMemberDetails(serialPersistentField)) { fieldWriter.writeHeader( configuration.getText("doclet.Serialized_Form_class")); + fieldWriter.writeMemberDeprecatedInfo(serialPersistentField); if (!configuration.nocomment) { - fieldWriter.writeMemberDeprecatedInfo(serialPersistentField); fieldWriter.writeMemberDescription(serialPersistentField); fieldWriter.writeMemberTags(serialPersistentField); - fieldWriter.writeMemberFooter(serialPersistentField); } + fieldWriter.writeMemberFooter(serialPersistentField); } } } @@ -429,6 +430,16 @@ } /** + * Build the field deprecation information. + */ + public void buildFieldDeprecationInfo() { + if (!currentClass.definesSerializableFields()) { + FieldDoc field = (FieldDoc)currentMember; + fieldWriter.writeMemberDeprecatedInfo(field); + } + } + + /** * Build the field information. */ public void buildFieldInfo() { @@ -459,7 +470,6 @@ "doclet.MissingSerialTag", cd.qualifiedName(), field.name()); } - fieldWriter.writeMemberDeprecatedInfo(field); fieldWriter.writeMemberDescription(field); fieldWriter.writeMemberTags(field); } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclet.xml Wed Jul 05 16:48:21 2017 +0200 @@ -1,30 +1,30 @@ - - - + + + @@ -183,8 +183,8 @@ + - @@ -193,6 +193,7 @@ + diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/javac/api/DiagnosticFormatter.java --- a/langtools/src/share/classes/com/sun/tools/javac/api/DiagnosticFormatter.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/api/DiagnosticFormatter.java Wed Jul 05 16:48:21 2017 +0200 @@ -25,16 +25,18 @@ package com.sun.tools.javac.api; import java.util.Locale; +import java.util.Set; import javax.tools.Diagnostic; +import com.sun.tools.javac.api.DiagnosticFormatter.*; /** - * Provides simple functionalities for javac diagnostic formatting + * Provides simple functionalities for javac diagnostic formatting. * @param type of diagnostic handled by this formatter */ public interface DiagnosticFormatter> { /** - * Whether the source code output for this diagnostic is to be displayed + * Whether the source code output for this diagnostic is to be displayed. * * @param diag diagnostic to be formatted * @return true if the source line this diagnostic refers to is to be displayed @@ -42,7 +44,7 @@ boolean displaySource(D diag); /** - * Format the contents of a diagnostics + * Format the contents of a diagnostics. * * @param diag the diagnostic to be formatted * @param l locale object to be used for i18n @@ -115,4 +117,97 @@ */ OFFSET } + + /** + * Get a list of all the enabled verbosity options. + * @return verbosity options + */ + public Configuration getConfiguration(); + //where + + /** + * This interface provides functionalities for tuning the output of a + * diagnostic formatter in multiple ways. + */ + interface Configuration { + /** + * Configure the set of diagnostic parts that should be displayed + * by the formatter. + * @param options options to set + */ + public void setVisible(Set visibleParts); + + /** + * Retrieve the set of diagnostic parts that should be displayed + * by the formatter. + * @return verbosity options + */ + public Set getVisible(); + + //where + /** + * A given diagnostic message can be divided into sub-parts each of which + * might/might not be displayed by the formatter, according to the + * current configuration settings. + */ + public enum DiagnosticPart { + /** + * Short description of the diagnostic - usually one line long. + */ + SUMMARY, + /** + * Longer description that provides additional details w.r.t. the ones + * in the diagnostic's description. + */ + DETAILS, + /** + * Source line the diagnostic refers to (if applicable). + */ + SOURCE, + /** + * Subdiagnostics attached to a given multiline diagnostic. + */ + SUBDIAGNOSTICS, + /** + * JLS paragraph this diagnostic might refer to (if applicable). + */ + JLS; + } + + /** + * Set a limit for multiline diagnostics. + * Note: Setting a limit has no effect if multiline diagnostics are either + * fully enabled or disabled. + * + * @param limit the kind of limit to be set + * @param value the limit value + */ + public void setMultilineLimit(MultilineLimit limit, int value); + + /** + * Get a multiline diagnostic limit. + * + * @param limit the kind of limit to be retrieved + * @return limit value or -1 if no limit is set + */ + public int getMultilineLimit(MultilineLimit limit); + //where + /** + * A multiline limit control the verbosity of multiline diagnostics + * either by setting a maximum depth of nested multidiagnostics, + * or by limiting the amount of subdiagnostics attached to a given + * diagnostic (or both). + */ + public enum MultilineLimit { + /** + * Controls the maximum depth of nested multiline diagnostics. + */ + DEPTH, + /** + * Controls the maximum amount of subdiagnostics that are part of a + * given multiline diagnostic. + */ + LENGTH; + } + } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/javac/api/Messages.java --- a/langtools/src/share/classes/com/sun/tools/javac/api/Messages.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/api/Messages.java Wed Jul 05 16:48:21 2017 +0200 @@ -44,7 +44,7 @@ void add(String bundleName) throws MissingResourceException; /** - * Get a localized formatted string + * Get a localized formatted string. * @param l locale in which the text is to be localized * @param key locale-independent message key * @param args misc message arguments diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/javac/main/OptionName.java --- a/langtools/src/share/classes/com/sun/tools/javac/main/OptionName.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/main/OptionName.java Wed Jul 05 16:48:21 2017 +0200 @@ -40,6 +40,7 @@ G_CUSTOM("-g:"), XLINT("-Xlint"), XLINT_CUSTOM("-Xlint:"), + DIAGS("-XDdiags="), NOWARN("-nowarn"), VERBOSE("-verbose"), DEPRECATION("-deprecation"), diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/javac/main/RecognizedOptions.java --- a/langtools/src/share/classes/com/sun/tools/javac/main/RecognizedOptions.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/main/RecognizedOptions.java Wed Jul 05 16:48:21 2017 +0200 @@ -145,6 +145,7 @@ TARGET, VERSION, FULLVERSION, + DIAGS, HELP, A, X, @@ -372,6 +373,21 @@ return super.process(options, option); } }, + new HiddenOption(DIAGS) { + @Override + public boolean process(Options options, String option) { + Option xd = getOptions(helper, EnumSet.of(XD))[0]; + option = option.substring(option.indexOf('=') + 1); + String diagsOption = option.contains("%") ? + "-XDdiagsFormat=" : + "-XDdiags="; + diagsOption += option; + if (xd.matches(diagsOption)) + return xd.process(options, diagsOption); + else + return false; + } + }, new Option(HELP, "opt.help") { @Override public boolean process(Options options, String option) { diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java --- a/langtools/src/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java Wed Jul 05 16:48:21 2017 +0200 @@ -125,7 +125,7 @@ return this; defaultAction(e, true); - printFormalTypeParameters(e); + printFormalTypeParameters(e, true); switch(kind) { case CONSTRUCTOR: @@ -207,7 +207,7 @@ writer.print(" "); writer.print(e.getSimpleName()); - printFormalTypeParameters(e); + printFormalTypeParameters(e, false); // Print superclass information if informative if (kind == CLASS) { @@ -364,16 +364,9 @@ } } - private void printFormalTypeParameters(ExecutableElement executable) { - printFormalTypeParameters(executable.getTypeParameters(), true); - } - - private void printFormalTypeParameters(TypeElement type) { - printFormalTypeParameters(type.getTypeParameters(), false); - } - - private void printFormalTypeParameters(List typeParams, + private void printFormalTypeParameters(Parameterizable e, boolean pad) { + List typeParams = e.getTypeParameters(); if (typeParams.size() > 0) { writer.print("<"); diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Jul 05 16:48:21 2017 +0200 @@ -907,16 +907,16 @@ compiler.err.prob.found.req=\ {0}\n\ -found : {1}\n\ -required: {2} +required: {2}\n\ +found: {1} compiler.warn.prob.found.req=\ {0}\n\ -found : {1}\n\ -required: {2} +required: {2}\n\ +found: {1} compiler.err.prob.found.req.1=\ {0} {3}\n\ -found : {1}\n\ -required: {2} +required: {2}\n\ +found: {1} ## The following are all possible strings for the first argument ({0}) of the ## above strings. @@ -951,8 +951,8 @@ compiler.err.type.found.req=\ unexpected type\n\ -found : {0}\n\ -required: {1} +required: {1}\n\ +found: {0} ## The following are all possible strings for the first argument ({0}) of the ## above string. @@ -1003,7 +1003,7 @@ compiler.err.unexpected.type=\ unexpected type\n\ required: {0}\n\ -found : {1} +found: {1} ## The first argument {0} is a "kindname" (e.g. 'constructor', 'field', etc.) ## The second argument {1} is the non-resolved symbol @@ -1026,17 +1026,17 @@ ## The sixth argument {5} is the location type compiler.err.cant.resolve.location=\ cannot find symbol\n\ - symbol : {0} {1}\n\ + symbol: {0} {1}\n\ location: {4} {5} compiler.err.cant.resolve.location.args=\ cannot find symbol\n\ - symbol : {0} {1}({3})\n\ + symbol: {0} {1}({3})\n\ location: {4} {5} compiler.err.cant.resolve.location.args.params=\ cannot find symbol\n\ - symbol : {0} <{2}>{1}({3})\n\ + symbol: {0} <{2}>{1}({3})\n\ location: {4} {5} ## The following are all possible string for "kindname". diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java --- a/langtools/src/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java Wed Jul 05 16:48:21 2017 +0200 @@ -24,16 +24,23 @@ */ package com.sun.tools.javac.util; +import java.util.Arrays; import java.util.Collection; +import java.util.EnumSet; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; +import java.util.Set; import javax.tools.JavaFileObject; import com.sun.tools.javac.api.DiagnosticFormatter; +import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.DiagnosticPart; +import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.MultilineLimit; +import com.sun.tools.javac.api.DiagnosticFormatter.PositionKind; import com.sun.tools.javac.api.Formattable; -import com.sun.tools.javac.api.DiagnosticFormatter.PositionKind; import com.sun.tools.javac.file.JavacFileManager; + import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*; -import static com.sun.tools.javac.util.LayoutCharacters.*; /** * This abstract class provides a basic implementation of the functionalities that should be provided @@ -50,35 +57,19 @@ public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter { /** - * JavacMessages object used by this formatter for i18n + * JavacMessages object used by this formatter for i18n. */ protected JavacMessages messages; - protected boolean showSource; + private SimpleConfiguration config; + protected int depth = 0; /** - * Initialize an AbstractDiagnosticFormatter by setting its JavacMessages object + * Initialize an AbstractDiagnosticFormatter by setting its JavacMessages object. * @param messages */ - protected AbstractDiagnosticFormatter(JavacMessages messages, Options options, boolean showSource) { - this.messages = messages; - this.showSource = options.get("showSource") == null ? showSource : - options.get("showSource").equals("true"); - } - - protected AbstractDiagnosticFormatter(JavacMessages messages, boolean showSource) { + protected AbstractDiagnosticFormatter(JavacMessages messages, SimpleConfiguration config) { this.messages = messages; - this.showSource = showSource; - } - - public String formatMessage(JCDiagnostic d, Locale l) { - //this code should rely on the locale settings but it's not! See RFE 6443132 - StringBuilder buf = new StringBuilder(); - Collection args = formatArguments(d, l); - buf.append(localize(l, d.getCode(), args.toArray())); - if (d.isMultiline()) { - buf.append(formatSubdiagnostics(d, l)); - } - return buf.toString(); + this.config = config; } public String formatKind(JCDiagnostic d, Locale l) { @@ -96,8 +87,8 @@ assert (d.getPosition() != Position.NOPOS); return String.valueOf(getPosition(d, pk)); } - //WHERE - public long getPosition(JCDiagnostic d, PositionKind pk) { + //where + private long getPosition(JCDiagnostic d, PositionKind pk) { switch (pk) { case START: return d.getIntStartPosition(); case END: return d.getIntEndPosition(); @@ -138,8 +129,17 @@ * @return string representation of the diagnostic argument */ protected String formatArgument(JCDiagnostic d, Object arg, Locale l) { - if (arg instanceof JCDiagnostic) - return format((JCDiagnostic)arg, l); + if (arg instanceof JCDiagnostic) { + String s = null; + depth++; + try { + s = formatMessage((JCDiagnostic)arg, l); + } + finally { + depth--; + } + return s; + } else if (arg instanceof Iterable) { return formatIterable(d, (Iterable)arg, l); } @@ -171,45 +171,74 @@ } /** - * Format all the subdiagnostics attached to a given diagnostic + * Format all the subdiagnostics attached to a given diagnostic. * * @param d diagnostic whose subdiagnostics are to be formatted * @param l locale object to be used for i18n + * @return list of all string representations of the subdiagnostics + */ + protected List formatSubdiagnostics(JCDiagnostic d, Locale l) { + List subdiagnostics = List.nil(); + int maxDepth = config.getMultilineLimit(MultilineLimit.DEPTH); + if (maxDepth == -1 || depth < maxDepth) { + depth++; + try { + int maxCount = config.getMultilineLimit(MultilineLimit.LENGTH); + int count = 0; + for (JCDiagnostic d2 : d.getSubdiagnostics()) { + if (maxCount == -1 || count < maxCount) { + subdiagnostics = subdiagnostics.append(formatSubdiagnostic(d, d2, l)); + count++; + } + else + break; + } + } + finally { + depth--; + } + } + return subdiagnostics; + } + + /** + * Format a subdiagnostics attached to a given diagnostic. + * + * @param parent multiline diagnostic whose subdiagnostics is to be formatted + * @param sub subdiagnostic to be formatted + * @param l locale object to be used for i18n * @return string representation of the subdiagnostics */ - protected String formatSubdiagnostics(JCDiagnostic d, Locale l) { - StringBuilder buf = new StringBuilder(); - for (JCDiagnostic d2 : d.getSubdiagnostics()) { - buf.append('\n'); - String subdiagMsg = format(d2, l); - buf.append(indent(subdiagMsg, DiagInc)); - } - return buf.toString(); + protected String formatSubdiagnostic(JCDiagnostic parent, JCDiagnostic sub, Locale l) { + return formatMessage(sub, l); } /** Format the faulty source code line and point to the error. * @param d The diagnostic for which the error line should be printed */ - protected String formatSourceLine(JCDiagnostic d) { + protected String formatSourceLine(JCDiagnostic d, int nSpaces) { StringBuilder buf = new StringBuilder(); DiagnosticSource source = d.getDiagnosticSource(); int pos = d.getIntPosition(); - if (d.getIntPosition() != Position.NOPOS) { - String line = (source == null ? null : source.getLine(pos)); - if (line == null) - return ""; - buf.append(line+"\n"); - int col = source.getColumnNumber(pos, false); + if (d.getIntPosition() == Position.NOPOS) + throw new AssertionError(); + String line = (source == null ? null : source.getLine(pos)); + if (line == null) + return ""; + buf.append(indent(line, nSpaces)); + int col = source.getColumnNumber(pos, false); + if (config.isCaretEnabled()) { + buf.append("\n"); for (int i = 0; i < col - 1; i++) { buf.append((line.charAt(i) == '\t') ? "\t" : " "); } - buf.append("^"); - } - return buf.toString(); + buf.append(indent("^", nSpaces)); + } + return buf.toString(); } /** - * Converts a String into a locale-dependent representation accordingly to a given locale + * Converts a String into a locale-dependent representation accordingly to a given locale. * * @param l locale object to be used for i18n * @param key locale-independent key used for looking up in a resource file @@ -221,7 +250,9 @@ } public boolean displaySource(JCDiagnostic d) { - return showSource && d.getType() != FRAGMENT; + return config.getVisible().contains(DiagnosticPart.SOURCE) && + d.getType() != FRAGMENT && + d.getIntPosition() != Position.NOPOS; } /** @@ -245,7 +276,7 @@ /** * Indent a string by prepending a given amount of empty spaces to each line - * of the string + * of the string. * * @param s the string to be indented * @param nSpaces the amount of spaces that should be prepended to each line @@ -263,4 +294,114 @@ } return buf.toString(); } + + public SimpleConfiguration getConfiguration() { + return config; + } + + static public class SimpleConfiguration implements Configuration { + + protected Map multilineLimits; + protected EnumSet visibleParts; + protected boolean caretEnabled; + + public SimpleConfiguration(Set parts) { + multilineLimits = new HashMap(); + setVisible(parts); + setMultilineLimit(MultilineLimit.DEPTH, -1); + setMultilineLimit(MultilineLimit.LENGTH, -1); + setCaretEnabled(true); + } + + @SuppressWarnings("fallthrough") + public SimpleConfiguration(Options options, Set parts) { + this(parts); + String showSource = null; + if ((showSource = options.get("showSource")) != null) { + if (showSource.equals("true")) + visibleParts.add(DiagnosticPart.SOURCE); + else if (showSource.equals("false")) + visibleParts.remove(DiagnosticPart.SOURCE); + } + String diagOpts = options.get("diags"); + if (diagOpts != null) {//override -XDshowSource + Collection args = Arrays.asList(diagOpts.split(",")); + if (args.contains("short")) { + visibleParts.remove(DiagnosticPart.DETAILS); + visibleParts.remove(DiagnosticPart.SUBDIAGNOSTICS); + } + if (args.contains("source")) + visibleParts.add(DiagnosticPart.SOURCE); + if (args.contains("-source")) + visibleParts.remove(DiagnosticPart.SOURCE); + } + String multiPolicy = null; + if ((multiPolicy = options.get("multilinePolicy")) != null) { + if (multiPolicy.equals("disabled")) + visibleParts.remove(DiagnosticPart.SUBDIAGNOSTICS); + else if (multiPolicy.startsWith("limit:")) { + String limitString = multiPolicy.substring("limit:".length()); + String[] limits = limitString.split(":"); + try { + switch (limits.length) { + case 2: { + if (!limits[1].equals("*")) + setMultilineLimit(MultilineLimit.DEPTH, Integer.parseInt(limits[1])); + } + case 1: { + if (!limits[0].equals("*")) + setMultilineLimit(MultilineLimit.LENGTH, Integer.parseInt(limits[0])); + } + } + } + catch(NumberFormatException ex) { + setMultilineLimit(MultilineLimit.DEPTH, -1); + setMultilineLimit(MultilineLimit.LENGTH, -1); + } + } + } + String showCaret = null; + if (((showCaret = options.get("showCaret")) != null) && + showCaret.equals("false")) + setCaretEnabled(false); + else + setCaretEnabled(true); + } + + public int getMultilineLimit(MultilineLimit limit) { + return multilineLimits.get(limit); + } + + public EnumSet getVisible() { + return EnumSet.copyOf(visibleParts); + } + + public void setMultilineLimit(MultilineLimit limit, int value) { + multilineLimits.put(limit, value < -1 ? -1 : value); + } + + + public void setVisible(Set diagParts) { + visibleParts = EnumSet.copyOf(diagParts); + } + + /** + * Shows a '^' sign under the source line displayed by the formatter + * (if applicable). + * + * @param caretEnabled if true enables caret + */ + public void setCaretEnabled(boolean caretEnabled) { + this.caretEnabled = caretEnabled; + } + + /** + * Tells whether the caret display is active or not. + * + * @param caretEnabled if true the caret is enabled + */ + public boolean isCaretEnabled() { + return caretEnabled; + } + } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/javac/util/BasicDiagnosticFormatter.java --- a/langtools/src/share/classes/com/sun/tools/javac/util/BasicDiagnosticFormatter.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/util/BasicDiagnosticFormatter.java Wed Jul 05 16:48:21 2017 +0200 @@ -25,13 +25,20 @@ package com.sun.tools.javac.util; +import java.util.Collection; +import java.util.EnumSet; import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.regex.Matcher; import javax.tools.JavaFileObject; -import static com.sun.tools.javac.util.BasicDiagnosticFormatter.BasicFormatKind.*; +import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration; +import com.sun.tools.javac.util.BasicDiagnosticFormatter.BasicConfiguration; + import static com.sun.tools.javac.api.DiagnosticFormatter.PositionKind.*; +import static com.sun.tools.javac.util.BasicDiagnosticFormatter.BasicConfiguration.*; +import static com.sun.tools.javac.util.LayoutCharacters.*; /** * A basic formatter for diagnostic messages. @@ -53,7 +60,7 @@ */ public class BasicDiagnosticFormatter extends AbstractDiagnosticFormatter { - protected Map availableFormats; + protected int currentIndentation = 0; /** * Create a basic formatter based on the supplied options. @@ -62,21 +69,8 @@ * @param msgs JavacMessages object used for i18n */ @SuppressWarnings("fallthrough") - BasicDiagnosticFormatter(Options opts, JavacMessages msgs) { - super(msgs, opts, true); - initAvailableFormats(); - String fmt = opts.get("diags"); - if (fmt != null) { - String[] formats = fmt.split("\\|"); - switch (formats.length) { - case 3: - availableFormats.put(DEFAULT_CLASS_FORMAT, formats[2]); - case 2: - availableFormats.put(DEFAULT_NO_POS_FORMAT, formats[1]); - default: - availableFormats.put(DEFAULT_POS_FORMAT, formats[0]); - } - } + public BasicDiagnosticFormatter(Options options, JavacMessages msgs) { + super(msgs, new BasicConfiguration(options)); } /** @@ -85,15 +79,7 @@ * @param msgs JavacMessages object used for i18n */ public BasicDiagnosticFormatter(JavacMessages msgs) { - super(msgs, true); - initAvailableFormats(); - } - - public void initAvailableFormats() { - availableFormats = new HashMap(); - availableFormats.put(DEFAULT_POS_FORMAT, "%f:%l:%_%t%m"); - availableFormats.put(DEFAULT_NO_POS_FORMAT, "%p%m"); - availableFormats.put(DEFAULT_CLASS_FORMAT, "%f:%_%t%m"); + super(msgs, new BasicConfiguration()); } public String format(JCDiagnostic d, Locale l) { @@ -110,10 +96,55 @@ } buf.append(meta ? formatMeta(c, d, l) : String.valueOf(c)); } - if (displaySource(d)) { - buf.append("\n" + formatSourceLine(d)); + if (depth == 0) + return addSourceLineIfNeeded(d, buf.toString()); + else + return buf.toString(); + } + + public String formatMessage(JCDiagnostic d, Locale l) { + int prevIndentation = currentIndentation; + try { + StringBuilder buf = new StringBuilder(); + Collection args = formatArguments(d, l); + String msg = localize(l, d.getCode(), args.toArray()); + String[] lines = msg.split("\n"); + if (getConfiguration().getVisible().contains(DiagnosticPart.SUMMARY)) { + currentIndentation += getConfiguration().getIndentation(DiagnosticPart.SUMMARY); + buf.append(indent(lines[0], currentIndentation)); //summary + } + if (lines.length > 1 && getConfiguration().getVisible().contains(DiagnosticPart.DETAILS)) { + currentIndentation += getConfiguration().getIndentation(DiagnosticPart.DETAILS); + for (int i = 1;i < lines.length; i++) { + buf.append("\n" + indent(lines[i], currentIndentation)); + } + } + if (d.isMultiline() && getConfiguration().getVisible().contains(DiagnosticPart.SUBDIAGNOSTICS)) { + currentIndentation += getConfiguration().getIndentation(DiagnosticPart.SUBDIAGNOSTICS); + for (String sub : formatSubdiagnostics(d, l)) { + buf.append("\n" + sub); + } + } + return buf.toString(); } - return buf.toString(); + finally { + currentIndentation = prevIndentation; + } + } + + protected String addSourceLineIfNeeded(JCDiagnostic d, String msg) { + if (!displaySource(d)) + return msg; + else { + BasicConfiguration conf = getConfiguration(); + int indentSource = conf.getIndentation(DiagnosticPart.SOURCE); + String sourceLine = "\n" + formatSourceLine(d, indentSource); + boolean singleLine = msg.indexOf("\n") == -1; + if (singleLine || getConfiguration().getSourcePosition() == SourcePosition.BOTTOM) + return msg + sourceLine; + else + return msg.replaceFirst("\n", Matcher.quoteReplacement(sourceLine) + "\n"); + } } protected String formatMeta(char c, JCDiagnostic d, Locale l) { @@ -164,34 +195,199 @@ private String selectFormat(JCDiagnostic d) { DiagnosticSource source = d.getDiagnosticSource(); - String format = availableFormats.get(DEFAULT_NO_POS_FORMAT); + String format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT); if (source != null) { if (d.getIntPosition() != Position.NOPOS) { - format = availableFormats.get(DEFAULT_POS_FORMAT); + format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_POS_FORMAT); } else if (source.getFile() != null && source.getFile().getKind() == JavaFileObject.Kind.CLASS) { - format = availableFormats.get(DEFAULT_CLASS_FORMAT); + format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_CLASS_FORMAT); } } return format; } - /** - * This enum contains all the kinds of formatting patterns supported - * by a basic diagnostic formatter. - */ - public enum BasicFormatKind { + @Override + public BasicConfiguration getConfiguration() { + return (BasicConfiguration)super.getConfiguration(); + } + + static public class BasicConfiguration extends SimpleConfiguration { + + protected Map indentationLevels; + protected Map availableFormats; + protected SourcePosition sourcePosition; + + @SuppressWarnings("fallthrough") + public BasicConfiguration(Options options) { + super(options, EnumSet.of(DiagnosticPart.SUMMARY, + DiagnosticPart.DETAILS, + DiagnosticPart.SUBDIAGNOSTICS, + DiagnosticPart.SOURCE)); + initFormat(); + initIndentation(); + String fmt = options.get("diagsFormat"); + if (fmt != null) { + String[] formats = fmt.split("\\|"); + switch (formats.length) { + case 3: + setFormat(BasicFormatKind.DEFAULT_CLASS_FORMAT, formats[2]); + case 2: + setFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT, formats[1]); + default: + setFormat(BasicFormatKind.DEFAULT_POS_FORMAT, formats[0]); + } + } + String sourcePosition = null; + if ((((sourcePosition = options.get("sourcePosition")) != null)) && + sourcePosition.equals("bottom")) + setSourcePosition(SourcePosition.BOTTOM); + else + setSourcePosition(SourcePosition.AFTER_SUMMARY); + String indent = options.get("diagsIndentation"); + if (indent != null) { + String[] levels = indent.split("\\|"); + try { + switch (levels.length) { + case 5: + setIndentation(DiagnosticPart.JLS, + Integer.parseInt(levels[4])); + case 4: + setIndentation(DiagnosticPart.SUBDIAGNOSTICS, + Integer.parseInt(levels[3])); + case 3: + setIndentation(DiagnosticPart.SOURCE, + Integer.parseInt(levels[2])); + case 2: + setIndentation(DiagnosticPart.DETAILS, + Integer.parseInt(levels[1])); + default: + setIndentation(DiagnosticPart.SUMMARY, + Integer.parseInt(levels[0])); + } + } + catch (NumberFormatException ex) { + initIndentation(); + } + } + } + + public BasicConfiguration() { + super(EnumSet.of(DiagnosticPart.SUMMARY, + DiagnosticPart.DETAILS, + DiagnosticPart.SUBDIAGNOSTICS, + DiagnosticPart.SOURCE)); + initFormat(); + initIndentation(); + } + //where + private void initFormat() { + availableFormats = new HashMap(); + setFormat(BasicFormatKind.DEFAULT_POS_FORMAT, "%f:%l:%_%t%m"); + setFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT, "%p%m"); + setFormat(BasicFormatKind.DEFAULT_CLASS_FORMAT, "%f:%_%t%m"); + } + //where + private void initIndentation() { + indentationLevels = new HashMap(); + setIndentation(DiagnosticPart.SUMMARY, 0); + setIndentation(DiagnosticPart.DETAILS, DetailsInc); + setIndentation(DiagnosticPart.SUBDIAGNOSTICS, DiagInc); + setIndentation(DiagnosticPart.SOURCE, 0); + } + /** - * A format string to be used for diagnostics with a given position. - */ - DEFAULT_POS_FORMAT, + * Get the amount of spaces for a given indentation kind + * @param diagPart the diagnostic part for which the indentation is + * to be retrieved + * @return the amount of spaces used for the specified indentation kind + */ + public int getIndentation(DiagnosticPart diagPart) { + return indentationLevels.get(diagPart); + } + + /** + * Set the indentation level for various element of a given diagnostic - + * this might lead to more readable diagnostics + * + * @param indentationKind kind of indentation to be set + * @param nSpaces amount of spaces for the specified diagnostic part + */ + public void setIndentation(DiagnosticPart diagPart, int nSpaces) { + indentationLevels.put(diagPart, nSpaces); + } + + /** + * Set the source line positioning used by this formatter + * + * @param sourcePos a positioning value for source line + */ + public void setSourcePosition(SourcePosition sourcePos) { + sourcePosition = sourcePos; + } + + /** + * Get the source line positioning used by this formatter + * + * @return the positioning value used by this formatter + */ + public SourcePosition getSourcePosition() { + return sourcePosition; + } + //where /** - * A format string to be used for diagnostics without a given position. - */ - DEFAULT_NO_POS_FORMAT, + * A source positioning value controls the position (within a given + * diagnostic message) in which the source line the diagnostic refers to + * should be displayed (if applicable) + */ + public enum SourcePosition { + /** + * Source line is displayed after the diagnostic message + */ + BOTTOM, + /** + * Source line is displayed after the first line of the diagnostic + * message + */ + AFTER_SUMMARY; + } + + /** + * Set a metachar string for a specific format + * + * @param kind the format kind to be set + * @param s the metachar string specifying the format + */ + public void setFormat(BasicFormatKind kind, String s) { + availableFormats.put(kind, s); + } + /** - * A format string to be used for diagnostics regarding classfiles - */ - DEFAULT_CLASS_FORMAT; + * Get a metachar string for a specific format + * + * @param sourcePos a positioning value for source line + */ + public String getFormat(BasicFormatKind kind) { + return availableFormats.get(kind); + } + //where + /** + * This enum contains all the kinds of formatting patterns supported + * by a basic diagnostic formatter. + */ + public enum BasicFormatKind { + /** + * A format string to be used for diagnostics with a given position. + */ + DEFAULT_POS_FORMAT, + /** + * A format string to be used for diagnostics without a given position. + */ + DEFAULT_NO_POS_FORMAT, + /** + * A format string to be used for diagnostics regarding classfiles + */ + DEFAULT_CLASS_FORMAT; + } } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/javac/util/LayoutCharacters.java --- a/langtools/src/share/classes/com/sun/tools/javac/util/LayoutCharacters.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/util/LayoutCharacters.java Wed Jul 05 16:48:21 2017 +0200 @@ -39,9 +39,13 @@ */ final static int TabInc = 8; - /** Diagnostic standard indentation + /** Standard indentation for subdiagnostics */ - final static int DiagInc = 2; + final static int DiagInc = 4; + + /** Standard indentation for additional diagnostic lines + */ + final static int DetailsInc = 2; /** Tabulator character. */ diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/javac/util/Log.java --- a/langtools/src/share/classes/com/sun/tools/javac/util/Log.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/util/Log.java Wed Jul 05 16:48:21 2017 +0200 @@ -93,17 +93,17 @@ protected DiagnosticListener diagListener; /** - * Formatter for diagnostics + * Formatter for diagnostics. */ private DiagnosticFormatter diagFormatter; /** - * Keys for expected diagnostics + * Keys for expected diagnostics. */ public Set expectDiagKeys; /** - * JavacMessages object used for localization + * JavacMessages object used for localization. */ private JavacMessages messages; @@ -206,6 +206,18 @@ return source == null ? null : source.getFile(); } + /** Get the current diagnostic formatter. + */ + public DiagnosticFormatter getDiagnosticFormatter() { + return diagFormatter; + } + + /** Set the current diagnostic formatter. + */ + public void setDiagnosticFormatter(DiagnosticFormatter diagFormatter) { + this.diagFormatter = diagFormatter; + } + /** Flush the logs */ public void flush() { diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java --- a/langtools/src/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/com/sun/tools/javac/util/RawDiagnosticFormatter.java Wed Jul 05 16:48:21 2017 +0200 @@ -24,9 +24,14 @@ */ package com.sun.tools.javac.util; +import java.util.Collection; +import java.util.EnumSet; import java.util.Locale; +import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.*; import com.sun.tools.javac.api.Formattable; +import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration; + import static com.sun.tools.javac.api.DiagnosticFormatter.PositionKind.*; /** @@ -35,14 +40,17 @@ * or not the source name and position are set. This formatter provides a standardized, localize-independent * implementation of a diagnostic formatter; as such, this formatter is best suited for testing purposes. */ -public class RawDiagnosticFormatter extends AbstractDiagnosticFormatter { +public final class RawDiagnosticFormatter extends AbstractDiagnosticFormatter { /** * Create a formatter based on the supplied options. * @param msgs */ - public RawDiagnosticFormatter(Options opts) { - super(null, opts, false); + public RawDiagnosticFormatter(Options options) { + super(null, new SimpleConfiguration(options, + EnumSet.of(DiagnosticPart.SUMMARY, + DiagnosticPart.DETAILS, + DiagnosticPart.SUBDIAGNOSTICS))); } //provide common default formats @@ -62,7 +70,7 @@ buf.append(' '); buf.append(formatMessage(d, null)); if (displaySource(d)) - buf.append("\n" + formatSourceLine(d)); + buf.append("\n" + formatSourceLine(d, 0)); return buf.toString(); } catch (Exception e) { @@ -71,6 +79,32 @@ } } + public String formatMessage(JCDiagnostic d, Locale l) { + StringBuilder buf = new StringBuilder(); + Collection args = formatArguments(d, l); + buf.append(d.getCode()); + String sep = ": "; + for (Object o : args) { + buf.append(sep); + buf.append(o); + sep = ", "; + } + if (d.isMultiline() && getConfiguration().getVisible().contains(DiagnosticPart.SUBDIAGNOSTICS)) { + List subDiags = formatSubdiagnostics(d, null); + if (subDiags.nonEmpty()) { + sep = ""; + buf.append(",{"); + for (String sub : formatSubdiagnostics(d, null)) { + buf.append(sep); + buf.append("(" + sub + ")"); + sep = ","; + } + buf.append('}'); + } + } + return buf.toString(); + } + @Override protected String formatArgument(JCDiagnostic diag, Object arg, Locale l) { String s; @@ -83,31 +117,4 @@ else return s; } - - @Override - protected String formatSubdiagnostics(JCDiagnostic d, Locale l) { - StringBuilder buf = new StringBuilder(); - String sep = ""; - buf.append(",{"); - for (JCDiagnostic d2 : d.getSubdiagnostics()) { - buf.append(sep); - buf.append("(" + format(d2, l) + ")"); - sep = ","; - } - buf.append('}'); - return buf.toString(); - } - - @Override - protected String localize(Locale l, String s, Object... args) { - StringBuffer buf = new StringBuffer(); - buf.append(s); - String sep = ": "; - for (Object o : args) { - buf.append(sep); - buf.append(o); - sep = ", "; - } - return buf.toString(); - } } diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/javax/lang/model/element/ExecutableElement.java --- a/langtools/src/share/classes/javax/lang/model/element/ExecutableElement.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/javax/lang/model/element/ExecutableElement.java Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 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 @@ -40,7 +40,7 @@ * @see ExecutableType * @since 1.6 */ -public interface ExecutableElement extends Element { +public interface ExecutableElement extends Element, Parameterizable { /** * Returns the formal type parameters of this executable * in declaration order. diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/javax/lang/model/element/PackageElement.java --- a/langtools/src/share/classes/javax/lang/model/element/PackageElement.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/javax/lang/model/element/PackageElement.java Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 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 @@ -25,7 +25,6 @@ package javax.lang.model.element; - /** * Represents a package program element. Provides access to information * about the package and its members. @@ -36,8 +35,7 @@ * @see javax.lang.model.util.Elements#getPackageOf * @since 1.6 */ - -public interface PackageElement extends Element { +public interface PackageElement extends Element, QualifiedNameable { /** * Returns the fully qualified name of this package. diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/javax/lang/model/element/Parameterizable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/javax/lang/model/element/Parameterizable.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.lang.model.element; + +import java.util.List; + +/** + * A mixin interface for an element that has type parameters. + * + * @author Joseph D. Darcy + * @since 1.7 + */ +public interface Parameterizable extends Element { + /** + * Returns the formal type parameters of the type element in + * declaration order. + * + * @return the formal type parameters, or an empty list + * if there are none + */ + List getTypeParameters(); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/javax/lang/model/element/QualifiedNameable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/share/classes/javax/lang/model/element/QualifiedNameable.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package javax.lang.model.element; + +/** + * A mixin interface for an element that has a qualified name. + * + * @author Joseph D. Darcy + * @since 1.7 + */ +public interface QualifiedNameable extends Element { + /** + * Returns the fully qualified name of an element. + * + * @return the fully qualified name of an element + */ + Name getQualifiedName(); +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/src/share/classes/javax/lang/model/element/TypeElement.java --- a/langtools/src/share/classes/javax/lang/model/element/TypeElement.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/src/share/classes/javax/lang/model/element/TypeElement.java Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 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 @@ -59,7 +59,7 @@ * @see DeclaredType * @since 1.6 */ -public interface TypeElement extends Element { +public interface TypeElement extends Element, Parameterizable, QualifiedNameable { /** * Returns the nesting kind of this type element. diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/TestSerializedFormDeprecationInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/TestSerializedFormDeprecationInfo.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,151 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun 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 6802694 + * @summary This test verifies deprecation info in serialized-form.html. + * @author Bhavesh Patel + * @library ../lib/ + * @build JavadocTester + * @build TestSerializedFormDeprecationInfo + * @run main TestSerializedFormDeprecationInfo + */ + +public class TestSerializedFormDeprecationInfo extends JavadocTester { + + private static final String BUG_ID = "6802694"; + + // Test for normal run of javadoc. The serialized-form.html should + // display the inline comments, tags and deprecation information if any. + private static final String[][] TEST_CMNT_DEPR = { + {BUG_ID + FS + "serialized-form.html", "
" + NL + "
" + NL + NL + + "
Throws:" + NL + "
" + + "java.io.IOException
See Also:" + + "
" + + "C1.setUndecorated(boolean)
" + NL + + "
" + NL + "
"}, + {BUG_ID + FS + "serialized-form.html", "
" + NL + + "
Deprecated. As of JDK version" + + " 1.5, replaced by" + NL + + " " + + "setUndecorated(boolean)." + + "
This field indicates whether the C1 is undecorated." + NL + + "

" + NL + "

 
" + NL + + "
Since:
" + NL + + "
1.4
" + NL + "
See Also:" + + "
" + + "C1.setUndecorated(boolean)
" + NL + + "
"}, + {BUG_ID + FS + "serialized-form.html", "
" + NL + + "
Deprecated. As of JDK version" + + " 1.5, replaced by" + NL + + " " + + "setUndecorated(boolean)." + NL + "

" + NL + + "

Reads the object stream." + NL + "

" + NL + + "

" + NL + NL + "
Throws:" + + "" + NL + "
" + + "IOException" + NL + + "
java.io.IOException
" + NL + + "
" + NL + "
"}, + {BUG_ID + FS + "serialized-form.html", "
" + NL + + "
Deprecated. 
" + + "The name for this class." + NL + "

" + NL + + "

 
" + NL + "
" + NL + "
"}}; + + // Test with -nocomment option. The serialized-form.html should + // not display the inline comments and tags but should display deprecation + // information if any. + private static final String[][] TEST_NOCMNT = { + {BUG_ID + FS + "serialized-form.html", "
" + NL + "boolean " +
+                 "undecorated
" + NL + "
" + NL + "
" + + "Deprecated. As of JDK version 1.5, replaced by" + NL + + " " + + "setUndecorated(boolean).
"}, + {BUG_ID + FS + "serialized-form.html", "
" + NL + "
" + + "Deprecated. As of JDK version" + + " 1.5, replaced by" + NL + + " " + + "setUndecorated(boolean)." + NL + "

" + NL + + "

"}, + {BUG_ID + FS + "serialized-form.html", "
" + NL + "int " +
+                 "publicKey
" + NL + "
" + NL + "
" + + "Deprecated. 
"}}; + + // Test with -nodeprecated option. The serialized-form.html should + // ignore the -nodeprecated tag and display the deprecation info. This + // test is similar to the normal run of javadoc in which inline comment, tags + // and deprecation information will be displayed. + private static final String[][] TEST_NODEPR = TEST_CMNT_DEPR; + + // Test with -nodeprecated and -nocomment options. The serialized-form.html should + // ignore the -nodeprecated tag and display the deprecation info but should not + // display the inline comments and tags. This test is similar to the test with + // -nocomment option. + private static final String[][] TEST_NOCMNT_NODEPR = TEST_NOCMNT; + + private static final String[] ARGS1 = + new String[] { + "-d", BUG_ID, "-sourcepath", SRC_DIR, "pkg1"}; + + private static final String[] ARGS2 = + new String[] { + "-d", BUG_ID, "-nocomment", "-sourcepath", SRC_DIR, "pkg1"}; + + private static final String[] ARGS3 = + new String[] { + "-d", BUG_ID, "-nodeprecated", "-sourcepath", SRC_DIR, "pkg1"}; + + private static final String[] ARGS4 = + new String[] { + "-d", BUG_ID, "-nocomment", "-nodeprecated", "-sourcepath", SRC_DIR, "pkg1"}; + + /** + * The entry point of the test. + * @param args the array of command line arguments. + */ + public static void main(String[] args) { + TestSerializedFormDeprecationInfo tester = new TestSerializedFormDeprecationInfo(); + run(tester, ARGS1, TEST_CMNT_DEPR, TEST_NOCMNT); + run(tester, ARGS2, TEST_NOCMNT, TEST_CMNT_DEPR); + run(tester, ARGS3, TEST_NODEPR, TEST_NOCMNT_NODEPR); + run(tester, ARGS4, TEST_NOCMNT_NODEPR, TEST_NODEPR); + tester.printSummary(); + } + + /** + * {@inheritDoc} + */ + public String getBugId() { + return BUG_ID; + } + + /** + * {@inheritDoc} + */ + public String getBugName() { + return getClass().getName(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C1.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,108 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +import java.io.IOException; +import java.io.Serializable; + +/** + * A class comment for testing. + * + * @author Bhavesh Patel + * @see C2 + * @since JDK1.0 + */ + +public class C1 implements Serializable { + + /** + * This field indicates whether the C1 is undecorated. + * + * @see #setUndecorated(boolean) + * @since 1.4 + * @serial + * @deprecated As of JDK version 1.5, replaced by + * {@link C1#setUndecorated(boolean) setUndecorated(boolean)}. + */ + @Deprecated + public boolean undecorated = false; + + private String title; + + /** + * This enum specifies the possible modal exclusion types. + * + * @since 1.6 + */ + public static enum ModalExclusionType { + /** + * No modal exclusion. + */ + NO_EXCLUDE, + /** + * APPLICATION_EXCLUDE indicates that a top-level window + * won't be blocked by any application-modal dialogs. Also, it isn't + * blocked by document-modal dialogs from outside of its child hierarchy. + */ + APPLICATION_EXCLUDE + }; + + /** + * Constructor. + * + * @param title the title + * @param test boolean value + * @exception IllegalArgumentException if the owner's + * GraphicsConfiguration is not from a screen device + * @exception HeadlessException + */ + public C1(String title, boolean test) { + + } + + public C1(String title) { + + } + + /** + * Method comments. + * @param undecorated true if no decorations are + * to be enabled; + * false if decorations are to be enabled. + * @see #readObject() + * @since 1.4 + */ + public void setUndecorated(boolean undecorated) { + /* Make sure we don't run in the middle of peer creation.*/ + } + + /** + * @see #setUndecorated(boolean) + */ + public void readObject() throws IOException { + + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C2.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,86 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +import java.io.ObjectInputStream; +import java.io.IOException; +import java.io.Serializable; + +/** + * A class comment for testing. + * + * @author Bhavesh Patel + * @see C1 + * @since JDK1.0 + */ + +public class C2 implements Serializable { + + /** + * This field indicates title. + */ + String title; + + public static enum ModalType { + NO_EXCLUDE + }; + + /** + * Constructor. + * + */ + public C2() { + + } + + public C2(String title) { + + } + + /** + * Set visible. + * + * @param set boolean + * @since 1.4 + * @deprecated As of JDK version 1.5, replaced by + * {@link C1#setUndecorated(boolean) setUndecorated(boolean)}. + */ + @Deprecated + public void setVisible(boolean set) { + } + + /** + * Reads the object stream. + * + * @param s ObjectInputStream + * @throws IOException + * @deprecated As of JDK version 1.5, replaced by + * {@link C1#setUndecorated(boolean) setUndecorated(boolean)}. + */ + @Deprecated + public void readObject(ObjectInputStream s) throws IOException { + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/com/sun/javadoc/testSerializedFormDeprecationInfo/pkg1/C3.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package pkg1; + +import java.io.Serializable; + +/** + * Test for Serializable + * + * @author Bhavesh Patel + * @deprecated This class is no longer used. + */ +@Deprecated +public abstract class C3 implements Serializable { + + /** + * The name for this class. + * + * @serial + */ + private String name; + + /** + * @serial + */ + private int publicKey; + + /** + * Constructor for serialization only. + */ + protected C3() { + + } + + /** + * Prints general information. + * + */ + public void printInfo() { + + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/6304921/T6304921.out --- a/langtools/test/tools/javac/6304921/T6304921.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/6304921/T6304921.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,18 +1,18 @@ T6304921.java:671/671/680: warning: [rawtypes] found raw type: java.util.ArrayList -missing type parameters for generic class java.util.ArrayList List list = new ArrayList(); ^ + missing type parameters for generic class java.util.ArrayList T6304921.java:667/667/682: warning: [unchecked] unchecked conversion -found : java.util.ArrayList -required: java.util.List List list = new ArrayList(); ^ + required: java.util.List + found: java.util.ArrayList error: warnings found and -Werror specified T6304921.java:727/733/737: cannot find symbol -symbol : variable orr -location: class java.lang.System System.orr.println("abc"); // name not found ^ + symbol: variable orr + location: class java.lang.System T6304921.java:812/816/822: operator + cannot be applied to int,boolean return 123 + true; // bad binary expression ^ diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/6668794/badClass/Test.java --- a/langtools/test/tools/javac/6668794/badClass/Test.java Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/6668794/badClass/Test.java Wed Jul 05 16:48:21 2017 +0200 @@ -54,8 +54,8 @@ throw new Error("no diagnostics generated"); String expected = "B.java:6:6: compiler.err.cant.access: p.A, " + - "(- compiler.misc.bad.class.file.header: A.class, " + - "(- compiler.misc.class.file.wrong.class: q.A))"; + "(compiler.misc.bad.class.file.header: A.class, " + + "(compiler.misc.class.file.wrong.class: q.A))"; if (!out[0].equals(expected)) { System.err.println("expected: " + expected); diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/6668794/badSource/Test.out --- a/langtools/test/tools/javac/6668794/badSource/Test.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/6668794/badSource/Test.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,1 +1,1 @@ -Test.java:10:6: compiler.err.cant.access: p.A, (- compiler.misc.bad.source.file.header: A.java, (- compiler.misc.file.doesnt.contain.class: p.A)) +Test.java:10:6: compiler.err.cant.access: p.A, (compiler.misc.bad.source.file.header: A.java, (compiler.misc.file.doesnt.contain.class: p.A)) diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/6758789/T6758789b.out --- a/langtools/test/tools/javac/6758789/T6758789b.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/6758789/T6758789b.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,4 +1,4 @@ -T6758789b.java:39:11: compiler.warn.prob.found.req: (- compiler.misc.unchecked.assign), T6758789a.Foo, T6758789a.Foo +T6758789b.java:39:11: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T6758789a.Foo, T6758789a.Foo T6758789b.java:39:10: compiler.warn.unchecked.meth.invocation.applied: kindname.method, m, T6758789a.Foo, T6758789a.Foo, kindname.class, T6758789a - compiler.err.warnings.and.werror 1 error diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/Diagnostics/6769027/T6769027.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,499 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 6769027 + * @summary Source line should be displayed immediately after the first diagnostic line + * @author Maurizio Cimadamore + * @run main/othervm T6769027 + */ +import java.net.URI; +import java.util.regex.Matcher; +import javax.tools.*; +import com.sun.tools.javac.util.*; + +public class T6769027 { + + enum OutputKind { + RAW("rawDiagnostics","rawDiagnostics"), + BASIC("",""); + + String key; + String value; + + void init(Options opts) { + opts.put(key, value); + } + + OutputKind(String key, String value) { + this.key = key; + this.value = value; + } + } + + enum CaretKind { + DEFAULT("", ""), + SHOW("showCaret","true"), + HIDE("showCaret","false"); + + String key; + String value; + + void init(Options opts) { + opts.put(key, value); + } + + CaretKind(String key, String value) { + this.key = key; + this.value = value; + } + + boolean isEnabled() { + return this == DEFAULT || this == SHOW; + } + } + + enum SourceLineKind { + DEFAULT("", ""), + AFTER_SUMMARY("sourcePosition", "top"), + BOTTOM("sourcePosition", "bottom"); + + String key; + String value; + + void init(Options opts) { + opts.put(key, value); + } + + SourceLineKind(String key, String value) { + this.key = key; + this.value = value; + } + + boolean isAfterSummary() { + return this == DEFAULT || this == AFTER_SUMMARY; + } + } + + enum XDiagsSource { + DEFAULT(""), + SOURCE("source"), + NO_SOURCE("-source"); + + String flag; + + void init(Options opts) { + if (this != DEFAULT) { + String flags = opts.get("diags"); + flags = flags == null ? flag : flags + "," + flag; + opts.put("diags", flags); + } + } + + XDiagsSource(String flag) { + this.flag = flag; + } + + String getOutput(CaretKind caretKind, IndentKind indent, OutputKind outKind) { + String spaces = (outKind == OutputKind.BASIC) ? indent.string : ""; + return "\n" + spaces + "This is a source line" + + (caretKind.isEnabled() ? "\n" + spaces + " ^" : ""); + } + } + + enum XDiagsCompact { + DEFAULT(""), + COMPACT("short"), + NO_COMPACT("-short"); + + String flag; + + void init(Options opts) { + if (this != DEFAULT) { + String flags = opts.get("diags"); + flags = flags == null ? flag : flags + "," + flag; + opts.put("diags", flags); + } + } + + XDiagsCompact(String flag) { + this.flag = flag; + } + } + + enum ErrorKind { + SINGLE("single", + "compiler.err.single: Hello!", + "KXThis is a test error message Hello!"), + DOUBLE("double", + "compiler.err.double: Hello!", + "KXThis is a test error message.\n" + + "KXYThis is another line of the above error message Hello!"); + + String key; + String rawOutput; + String nonRawOutput; + + String key() { + return key; + } + + ErrorKind(String key, String rawOutput, String nonRawOutput) { + this.key = key; + this.rawOutput = rawOutput; + this.nonRawOutput = nonRawOutput; + } + + String getOutput(OutputKind outKind, IndentKind summaryIndent, IndentKind detailsIndent) { + return outKind == OutputKind.RAW ? + rawOutput : + nonRawOutput.replace("X", summaryIndent.string).replace("Y", detailsIndent.string).replace("K", ""); + } + + String getOutput(OutputKind outKind, IndentKind summaryIndent, IndentKind detailsIndent, String indent) { + return outKind == OutputKind.RAW ? + rawOutput : + nonRawOutput.replace("X", summaryIndent.string).replace("Y", detailsIndent.string).replace("K", indent); + } + } + + enum MultilineKind { + NONE(0), + DOUBLE(1), + NESTED(2), + DOUBLE_NESTED(3); + + static String[][] rawTemplates = { + {"", ",{(E),(E)}", ",{(E,{(E)})}", ",{(E,{(E)}),(E,{(E)})}"}, //ENABLED + {"", "", "", "",""}, //DISABLED + {"", ",{(E)}", ",{(E,{(E)})}", ",{(E,{(E)})}"}, //LIMIT_LENGTH + {"", ",{(E),(E)}", ",{(E)}", ",{(E),(E)}"}, //LIMIT_DEPTH + {"", ",{(E)}", ",{(E)}", ",{(E)}"}}; //LIMIT_BOTH + + static String[][] basicTemplates = { + {"", "\nE\nE", "\nE\nQ", "\nE\nQ\nE\nQ"}, //ENABLED + {"", "", "", "",""}, //DISABLED + {"", "\nE", "\nE\nQ", "\nE\nQ"}, //LIMIT_LENGTH + {"", "\nE\nE", "\nE", "\nE\nE"}, //LIMIT_DEPTH + {"", "\nE", "\nE", "\nE"}}; //LIMIT_BOTH + + + int index; + + MultilineKind (int index) { + this.index = index; + } + + boolean isDouble() { + return this == DOUBLE || this == DOUBLE_NESTED; + } + + boolean isNested() { + return this == NESTED || this == DOUBLE_NESTED; + } + + String getOutput(OutputKind outKind, ErrorKind errKind, MultilinePolicy policy, + IndentKind summaryIndent, IndentKind detailsIndent, IndentKind multiIndent) { + String constIndent = (errKind == ErrorKind.DOUBLE) ? + summaryIndent.string + detailsIndent.string : + summaryIndent.string; + constIndent += multiIndent.string; + + String errMsg1 = errKind.getOutput(outKind, summaryIndent, detailsIndent, constIndent); + String errMsg2 = errKind.getOutput(outKind, summaryIndent, detailsIndent, constIndent + constIndent); + + errMsg1 = errMsg1.replaceAll("compiler.err", "compiler.misc"); + errMsg1 = errMsg1.replaceAll("error message", "subdiagnostic"); + errMsg2 = errMsg2.replaceAll("compiler.err", "compiler.misc"); + errMsg2 = errMsg2.replaceAll("error message", "subdiagnostic"); + + String template = outKind == OutputKind.RAW ? + rawTemplates[policy.index][index] : + basicTemplates[policy.index][index]; + + template = template.replaceAll("E", errMsg1); + return template.replaceAll("Q", errMsg2); + } + } + + enum MultilinePolicy { + ENABLED(0, "multilinePolicy", "enabled"), + DISABLED(1, "multilinePolicy", "disabled"), + LIMIT_LENGTH(2, "multilinePolicy", "limit:1:*"), + LIMIT_DEPTH(3, "multilinePolicy", "limit:*:1"), + LIMIT_BOTH(4, "multilinePolicy", "limit:1:1"); + + String name; + String value; + int index; + + MultilinePolicy(int index, String name, String value) { + this.name = name; + this.value = value; + this.index = index; + } + + void init(Options options) { + options.put(name, value); + } + } + + enum PositionKind { + NOPOS(Position.NOPOS, "- ", "error: "), + POS(5, "/Test.java:1:6: ", "myfo:/Test.java:1: "); + + int pos; + String rawOutput; + String nonRawOutput; + + PositionKind(int pos, String rawOutput, String nonRawOutput) { + this.pos = pos; + this.rawOutput = rawOutput; + this.nonRawOutput = nonRawOutput; + } + + JCDiagnostic.DiagnosticPosition pos() { + return new JCDiagnostic.SimpleDiagnosticPosition(pos); + } + + String getOutput(OutputKind outputKind) { + return outputKind == OutputKind.RAW ? + rawOutput : + nonRawOutput; + } + } + + static class MyFileObject extends SimpleJavaFileObject { + private String text; + public MyFileObject(String text) { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + this.text = text; + } + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return text; + } + } + + enum IndentKind { + NONE(""), + CUSTOM(" "); + + String string; + + IndentKind(String indent) { + string = indent; + } + } + + class MyLog extends Log { + MyLog(Context ctx) { + super(ctx); + } + + @Override + protected java.io.PrintWriter getWriterForDiagnosticType(JCDiagnostic.DiagnosticType dt) { + return new java.io.PrintWriter(System.out); + } + + @Override + protected boolean shouldReport(JavaFileObject jfo, int pos) { + return true; + } + } + + int nerrors = 0; + + void exec(OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind, + MultilinePolicy multiPolicy, PositionKind posKind, XDiagsSource xdiagsSource, + XDiagsCompact xdiagsCompact, CaretKind caretKind, SourceLineKind sourceLineKind, + IndentKind summaryIndent, IndentKind detailsIndent, IndentKind sourceIndent, + IndentKind subdiagsIndent) { + Context ctx = new Context(); + Options options = Options.instance(ctx); + outputKind.init(options); + multiPolicy.init(options); + xdiagsSource.init(options); + xdiagsCompact.init(options); + caretKind.init(options); + sourceLineKind.init(options); + String indentString = ""; + indentString = (summaryIndent == IndentKind.CUSTOM) ? "3" : "0"; + indentString += (detailsIndent == IndentKind.CUSTOM) ? "|3" : "|0"; + indentString += (sourceIndent == IndentKind.CUSTOM) ? "|3" : "|0"; + indentString += (subdiagsIndent == IndentKind.CUSTOM) ? "|3" : "|0"; + options.put("diagsIndentation", indentString); + MyLog log = new MyLog(ctx); + JavacMessages messages = JavacMessages.instance(ctx); + messages.add("tester"); + JCDiagnostic.Factory diags = JCDiagnostic.Factory.instance(ctx); + log.useSource(new MyFileObject("This is a source line")); + JCDiagnostic d = diags.error(log.currentSource(), + posKind.pos(), + errorKind.key(), "Hello!"); + if (multiKind != MultilineKind.NONE) { + JCDiagnostic sub = diags.fragment(errorKind.key(), "Hello!"); + if (multiKind.isNested()) + sub = new JCDiagnostic.MultilineDiagnostic(sub, List.of(sub)); + List subdiags = multiKind.isDouble() ? + List.of(sub, sub) : + List.of(sub); + d = new JCDiagnostic.MultilineDiagnostic(d, subdiags); + } + String diag = log.getDiagnosticFormatter().format(d, messages.getCurrentLocale()); + checkOutput(diag, + outputKind, + errorKind, + multiKind, + multiPolicy, + posKind, + xdiagsSource, + xdiagsCompact, + caretKind, + sourceLineKind, + summaryIndent, + detailsIndent, + sourceIndent, + subdiagsIndent); + } + + void test() { + for (OutputKind outputKind : OutputKind.values()) { + for (ErrorKind errKind : ErrorKind.values()) { + for (MultilineKind multiKind : MultilineKind.values()) { + for (MultilinePolicy multiPolicy : MultilinePolicy.values()) { + for (PositionKind posKind : PositionKind.values()) { + for (XDiagsSource xdiagsSource : XDiagsSource.values()) { + for (XDiagsCompact xdiagsCompact : XDiagsCompact.values()) { + for (CaretKind caretKind : CaretKind.values()) { + for (SourceLineKind sourceLineKind : SourceLineKind.values()) { + for (IndentKind summaryIndent : IndentKind.values()) { + for (IndentKind detailsIndent : IndentKind.values()) { + for (IndentKind sourceIndent : IndentKind.values()) { + for (IndentKind subdiagsIndent : IndentKind.values()) { + exec(outputKind, + errKind, + multiKind, + multiPolicy, + posKind, + xdiagsSource, + xdiagsCompact, + caretKind, + sourceLineKind, + summaryIndent, + detailsIndent, + sourceIndent, + subdiagsIndent); + } + } + } + } + } + } + } + } + } + } + } + } + } + if (nerrors != 0) + throw new AssertionError(nerrors + " errors found"); + } + + void printInfo(String msg, OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind, + MultilinePolicy multiPolicy, PositionKind posKind, XDiagsSource xdiagsSource, + XDiagsCompact xdiagsCompact, CaretKind caretKind, SourceLineKind sourceLineKind, + IndentKind summaryIndent, IndentKind detailsIndent, IndentKind sourceIndent, + IndentKind subdiagsIndent, String errorLine) { + String sep = "*********************************************************"; + String desc = "raw=" + outputKind + " pos=" + posKind + " key=" + errorKind.key() + + " multiline=" + multiKind +" multiPolicy=" + multiPolicy.value + + " diags= " + java.util.Arrays.asList(xdiagsSource.flag, xdiagsCompact.flag) + + " caret=" + caretKind + " sourcePosition=" + sourceLineKind + + " summaryIndent=" + summaryIndent + " detailsIndent=" + detailsIndent + + " sourceIndent=" + sourceIndent + " subdiagsIndent=" + subdiagsIndent; + System.out.println(sep); + System.out.println(desc); + System.out.println(sep); + System.out.println(msg); + System.out.println("Diagnostic formatting problem - expected diagnostic...\n" + errorLine); + } + + void checkOutput(String msg, OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind, + MultilinePolicy multiPolicy, PositionKind posKind, XDiagsSource xdiagsSource, + XDiagsCompact xdiagsCompact, CaretKind caretKind, SourceLineKind sourceLineKind, + IndentKind summaryIndent, IndentKind detailsIndent, IndentKind sourceIndent, + IndentKind subdiagsIndent) { + boolean shouldPrintSource = posKind == PositionKind.POS && + xdiagsSource != XDiagsSource.NO_SOURCE && + (xdiagsSource == XDiagsSource.SOURCE || + outputKind == OutputKind.BASIC); + String errorLine = posKind.getOutput(outputKind) + + errorKind.getOutput(outputKind, summaryIndent, detailsIndent); + if (xdiagsCompact != XDiagsCompact.COMPACT) + errorLine += multiKind.getOutput(outputKind, errorKind, multiPolicy, summaryIndent, detailsIndent, subdiagsIndent); + String[] lines = errorLine.split("\n"); + if (xdiagsCompact == XDiagsCompact.COMPACT) { + errorLine = lines[0]; + lines = new String[] {errorLine}; + } + if (shouldPrintSource) { + if (sourceLineKind.isAfterSummary()) { + String sep = "\n"; + if (lines.length == 1) { + errorLine += "\n"; + sep = ""; + } + errorLine = errorLine.replaceFirst("\n", + Matcher.quoteReplacement(xdiagsSource.getOutput(caretKind, sourceIndent, outputKind) + sep)); + } + else + errorLine += xdiagsSource.getOutput(caretKind, sourceIndent, outputKind); + } + + if (!msg.equals(errorLine)) { + printInfo(msg, + outputKind, + errorKind, + multiKind, + multiPolicy, + posKind, + xdiagsSource, + xdiagsCompact, + caretKind, + sourceLineKind, + summaryIndent, + detailsIndent, + sourceIndent, + subdiagsIndent, + errorLine); + nerrors++; + } + } + + public static void main(String... args) throws Exception { + new T6769027().test(); + } +} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/Diagnostics/6769027/tester.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/Diagnostics/6769027/tester.properties Wed Jul 05 16:48:21 2017 +0200 @@ -0,0 +1,13 @@ +compiler.err.single=\ + This is a test error message {0} + +compiler.err.double=\ + This is a test error message.\n\ + This is another line of the above error message {0} + +compiler.misc.single=\ + This is a test subdiagnostic {0} + +compiler.misc.double=\ + This is a test subdiagnostic.\n\ + This is another line of the above subdiagnostic {0} diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/ExtendArray.out --- a/langtools/test/tools/javac/ExtendArray.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/ExtendArray.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,6 +1,6 @@ ExtendArray.java:11: unexpected type -found : java.lang.Object[] -required: class public class ExtendArray extends Object[] {} ^ + required: class + found: java.lang.Object[] 1 error diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/T5048776b.out --- a/langtools/test/tools/javac/T5048776b.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/T5048776b.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,3 +1,3 @@ -T5048776.java:12:10: compiler.warn.override.varargs.missing: (- compiler.misc.varargs.override: foo(java.lang.Object...), A1a, foo(java.lang.Object[]), A1) -T5048776.java:20:10: compiler.warn.override.varargs.extra: (- compiler.misc.varargs.override: foo(java.lang.Object[]), A2a, foo(java.lang.Object...), A2) +T5048776.java:12:10: compiler.warn.override.varargs.missing: (compiler.misc.varargs.override: foo(java.lang.Object...), A1a, foo(java.lang.Object[]), A1) +T5048776.java:20:10: compiler.warn.override.varargs.extra: (compiler.misc.varargs.override: foo(java.lang.Object[]), A2a, foo(java.lang.Object...), A2) 2 warnings diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/T6214885a.out --- a/langtools/test/tools/javac/T6214885a.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/T6214885a.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,6 +1,6 @@ T6214885.java:11 cannot find symbol -symbol : variable x -location: class T6214885 x = 1; ^ + symbol: variable x + location: class T6214885 1 error diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/T6214885b.out --- a/langtools/test/tools/javac/T6214885b.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/T6214885b.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,6 +1,6 @@ T6214885.java:11:9 cannot find symbol -symbol : variable x -location: class T6214885 x = 1; ^ + symbol: variable x + location: class T6214885 1 error diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/T6230128.out --- a/langtools/test/tools/javac/T6230128.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/T6230128.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,2 +1,2 @@ -T6230128.java:11:10: compiler.err.override.weaker.access: (- compiler.misc.cant.override: foo(java.lang.Object...), A1a, foo(java.lang.Object[]), A1), public +T6230128.java:11:10: compiler.err.override.weaker.access: (compiler.misc.cant.override: foo(java.lang.Object...), A1a, foo(java.lang.Object[]), A1), public 1 error diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/annotations/6365854/test1.out --- a/langtools/test/tools/javac/annotations/6365854/test1.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/annotations/6365854/test1.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,2 +1,2 @@ -- compiler.warn.annotation.method.not.found.reason: test.annotation.TestAnnotation, test, (- compiler.misc.class.file.not.found: test.annotation.TestAnnotation) +- compiler.warn.annotation.method.not.found.reason: test.annotation.TestAnnotation, test, (compiler.misc.class.file.not.found: test.annotation.TestAnnotation) 1 warning diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/cast/6557182/T6557182.out --- a/langtools/test/tools/javac/cast/6557182/T6557182.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/cast/6557182/T6557182.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,4 +1,4 @@ -T6557182.java:35:56: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T, java.lang.Comparable -T6557182.java:39:56: compiler.warn.prob.found.req: (- compiler.misc.unchecked.cast.to.type), T, java.lang.Comparable +T6557182.java:35:56: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T, java.lang.Comparable +T6557182.java:39:56: compiler.warn.prob.found.req: (compiler.misc.unchecked.cast.to.type), T, java.lang.Comparable 1 error 1 warning diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/cast/6665356/T6665356.out --- a/langtools/test/tools/javac/cast/6665356/T6665356.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/cast/6665356/T6665356.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,8 +1,8 @@ -T6665356.java:54:55: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6665356.Outer.Inner, T6665356.Outer.Inner -T6665356.java:58:58: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6665356.Outer.Inner, T6665356.Outer.Inner -T6665356.java:62:65: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6665356.Outer.Inner, T6665356.Outer.Inner -T6665356.java:66:57: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6665356.Outer.Inner, T6665356.Outer.Inner -T6665356.java:70:60: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6665356.Outer.Inner, T6665356.Outer.Inner -T6665356.java:74:55: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6665356.Outer.Inner, T6665356.Outer.Inner -T6665356.java:78:58: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6665356.Outer.Inner, T6665356.Outer.Inner +T6665356.java:54:55: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer.Inner, T6665356.Outer.Inner +T6665356.java:58:58: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer.Inner, T6665356.Outer.Inner +T6665356.java:62:65: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer.Inner, T6665356.Outer.Inner +T6665356.java:66:57: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer.Inner, T6665356.Outer.Inner +T6665356.java:70:60: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer.Inner, T6665356.Outer.Inner +T6665356.java:74:55: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer.Inner, T6665356.Outer.Inner +T6665356.java:78:58: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6665356.Outer.Inner, T6665356.Outer.Inner 7 errors \ No newline at end of file diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/cast/6795580/T6795580.out --- a/langtools/test/tools/javac/cast/6795580/T6795580.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/cast/6795580/T6795580.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,8 +1,8 @@ -T6795580.java:54:57: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6795580.Outer.Inner[], T6795580.Outer.Inner[] -T6795580.java:58:60: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6795580.Outer.Inner[], T6795580.Outer.Inner[] -T6795580.java:62:67: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6795580.Outer.Inner[], T6795580.Outer.Inner[] -T6795580.java:66:59: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6795580.Outer.Inner[], T6795580.Outer.Inner[] -T6795580.java:70:62: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6795580.Outer.Inner[], T6795580.Outer.Inner[] -T6795580.java:74:57: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6795580.Outer.Inner[], T6795580.Outer.Inner[] -T6795580.java:78:60: compiler.err.prob.found.req: (- compiler.misc.inconvertible.types), T6795580.Outer.Inner[], T6795580.Outer.Inner[] +T6795580.java:54:57: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer.Inner[], T6795580.Outer.Inner[] +T6795580.java:58:60: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer.Inner[], T6795580.Outer.Inner[] +T6795580.java:62:67: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer.Inner[], T6795580.Outer.Inner[] +T6795580.java:66:59: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer.Inner[], T6795580.Outer.Inner[] +T6795580.java:70:62: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer.Inner[], T6795580.Outer.Inner[] +T6795580.java:74:57: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer.Inner[], T6795580.Outer.Inner[] +T6795580.java:78:60: compiler.err.prob.found.req: (compiler.misc.inconvertible.types), T6795580.Outer.Inner[], T6795580.Outer.Inner[] 7 errors diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/generics/6207386/T6207386.out --- a/langtools/test/tools/javac/generics/6207386/T6207386.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/generics/6207386/T6207386.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,2 +1,2 @@ -T6207386.java:13:30: compiler.err.prob.found.req: (- compiler.misc.incompatible.types), X, T6207386.F +T6207386.java:13:30: compiler.err.prob.found.req: (compiler.misc.incompatible.types), X, T6207386.F 1 error diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/generics/inference/6315770/T6315770.out --- a/langtools/test/tools/javac/generics/inference/6315770/T6315770.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/generics/inference/6315770/T6315770.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,3 +1,3 @@ -T6315770.java:39:42: compiler.err.undetermined.type.1: T6315770, (- compiler.misc.no.unique.maximal.instance.exists: T, java.lang.String,java.lang.Integer,java.lang.Runnable) -T6315770.java:40:40: compiler.err.prob.found.req: (- compiler.misc.incompatible.types.1: (- compiler.misc.no.conforming.instance.exists: T, T6315770, T6315770)), T6315770, T6315770 +T6315770.java:39:42: compiler.err.undetermined.type.1: T6315770, (compiler.misc.no.unique.maximal.instance.exists: T, java.lang.String,java.lang.Integer,java.lang.Runnable) +T6315770.java:40:40: compiler.err.prob.found.req: (compiler.misc.incompatible.types.1: (compiler.misc.no.conforming.instance.exists: T, T6315770, T6315770)), T6315770, T6315770 2 errors diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/generics/inference/6718364/T6718364.out --- a/langtools/test/tools/javac/generics/inference/6718364/T6718364.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/generics/inference/6718364/T6718364.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,3 +1,3 @@ -T6718364.java:36:32: compiler.warn.prob.found.req: (- compiler.misc.unchecked.assign), T6718364.X, T6718364.X +T6718364.java:36:32: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T6718364.X, T6718364.X T6718364.java:36:10: compiler.warn.unchecked.meth.invocation.applied: kindname.method, m, T6718364.X,T, T6718364.X>,T6718364.X, kindname.class, T6718364 2 warnings \ No newline at end of file diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/generics/typevars/6680106/T6680106.out --- a/langtools/test/tools/javac/generics/typevars/6680106/T6680106.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/generics/typevars/6680106/T6680106.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,13 +1,13 @@ -T6680106.java:34:25: compiler.err.type.found.req: T[], (- compiler.misc.type.req.class) -T6680106.java:35:25: compiler.err.type.found.req: S[], (- compiler.misc.type.req.class) -T6680106.java:35:40: compiler.err.type.found.req: T[], (- compiler.misc.type.req.class) -T6680106.java:36:25: compiler.err.type.found.req: S[], (- compiler.misc.type.req.class) -T6680106.java:36:40: compiler.err.type.found.req: U[], (- compiler.misc.type.req.class) -T6680106.java:36:55: compiler.err.type.found.req: T[], (- compiler.misc.type.req.class) -T6680106.java:37:30: compiler.err.type.found.req: T[], (- compiler.misc.type.req.class) -T6680106.java:38:30: compiler.err.type.found.req: S[], (- compiler.misc.type.req.class) -T6680106.java:38:50: compiler.err.type.found.req: T[], (- compiler.misc.type.req.class) -T6680106.java:39:30: compiler.err.type.found.req: S[], (- compiler.misc.type.req.class) -T6680106.java:39:50: compiler.err.type.found.req: U[], (- compiler.misc.type.req.class) -T6680106.java:39:70: compiler.err.type.found.req: T[], (- compiler.misc.type.req.class) +T6680106.java:34:25: compiler.err.type.found.req: T[], (compiler.misc.type.req.class) +T6680106.java:35:25: compiler.err.type.found.req: S[], (compiler.misc.type.req.class) +T6680106.java:35:40: compiler.err.type.found.req: T[], (compiler.misc.type.req.class) +T6680106.java:36:25: compiler.err.type.found.req: S[], (compiler.misc.type.req.class) +T6680106.java:36:40: compiler.err.type.found.req: U[], (compiler.misc.type.req.class) +T6680106.java:36:55: compiler.err.type.found.req: T[], (compiler.misc.type.req.class) +T6680106.java:37:30: compiler.err.type.found.req: T[], (compiler.misc.type.req.class) +T6680106.java:38:30: compiler.err.type.found.req: S[], (compiler.misc.type.req.class) +T6680106.java:38:50: compiler.err.type.found.req: T[], (compiler.misc.type.req.class) +T6680106.java:39:30: compiler.err.type.found.req: S[], (compiler.misc.type.req.class) +T6680106.java:39:50: compiler.err.type.found.req: U[], (compiler.misc.type.req.class) +T6680106.java:39:70: compiler.err.type.found.req: T[], (compiler.misc.type.req.class) 12 errors \ No newline at end of file diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/missingSuperRecovery/MissingSuperRecovery.out --- a/langtools/test/tools/javac/missingSuperRecovery/MissingSuperRecovery.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/missingSuperRecovery/MissingSuperRecovery.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,5 +1,5 @@ MissingSuperRecovery.java:15: cannot access base -class file for base not found public class MissingSuperRecovery extends impl { ^ + class file for base not found 1 error diff -r 804c6c2cd89c -r 5da0e6b9f4f1 langtools/test/tools/javac/unicode/UnicodeNewline.out --- a/langtools/test/tools/javac/unicode/UnicodeNewline.out Wed Jul 05 16:47:52 2017 +0200 +++ b/langtools/test/tools/javac/unicode/UnicodeNewline.out Wed Jul 05 16:48:21 2017 +0200 @@ -1,6 +1,6 @@ UnicodeNewline.java:11: cannot find symbol -symbol : class xyzzy -location: class UnicodeNewline xyzzy plugh; // error should be HERE ^ + symbol: class xyzzy + location: class UnicodeNewline 1 error