changeset 769:5291d2324a3a

File system updates for b97: API updates: - Rename Access to AccessMode; eliminate EXISTS; FileRef#checkAccess checks existances when no access modes specified - PosixFileAttributeView should extend FileOwnerAttributeView - Add GroupPrincipal; eliminate UserPrincipal#isGroup method - DirectoryStreamFilers#newCaseSensitiveGlobFilter and newCaseInsensitiveGlobFilter methods confusing - Watch* should be abstract classes - Misc. clarifications Implementation updates: - Avoid copying to native buffer where possible - Eliminate need to store path for system calls (Solaris/Linux) - Improve open option processing (Solaris/Linux) - Added support for volume attributes (Windows)
author alanb
date Mon, 20 Oct 2008 19:20:24 +0100
parents 889050324044
children 2b9ea59279b9
files make/java/nio/FILES_java.gmk make/java/nio/Makefile make/java/nio/mapfile-linux make/java/nio/mapfile-solaris src/share/classes/java/nio/file/Access.java src/share/classes/java/nio/file/AccessMode.java src/share/classes/java/nio/file/DirectoryStream.java src/share/classes/java/nio/file/DirectoryStreamFilters.java src/share/classes/java/nio/file/FileAction.java src/share/classes/java/nio/file/FileRef.java src/share/classes/java/nio/file/FileSystem.java src/share/classes/java/nio/file/PathMatcher.java src/share/classes/java/nio/file/SimpleFileVisitor.java src/share/classes/java/nio/file/WatchEvent.java src/share/classes/java/nio/file/WatchKey.java src/share/classes/java/nio/file/WatchService.java src/share/classes/java/nio/file/Watchable.java src/share/classes/java/nio/file/attribute/AttributeView.java src/share/classes/java/nio/file/attribute/Attributes.java src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java src/share/classes/java/nio/file/attribute/GroupPrincipal.java src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java src/share/classes/java/nio/file/attribute/PosixFileAttributes.java src/share/classes/java/nio/file/attribute/UserPrincipal.java src/share/classes/java/nio/file/attribute/UserPrincipalLookupService.java src/share/classes/java/nio/file/attribute/package-info.java src/share/classes/java/nio/file/spi/AbstractPath.java src/share/classes/sun/nio/fs/AbstractWatchKey.java src/share/classes/sun/nio/fs/AbstractWatchService.java src/share/classes/sun/nio/fs/NativeBuffer.java src/share/classes/sun/nio/fs/NativeBuffers.java src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFilePath.java src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFileStream.java src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFileSystem.java src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFileSystemProvider.java src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java src/solaris/classes/sun/nio/fs/LinuxFileStore.java src/solaris/classes/sun/nio/fs/LinuxWatchService.java src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java src/solaris/classes/sun/nio/fs/SolarisFileStore.java src/solaris/classes/sun/nio/fs/SolarisFileSystem.java src/solaris/classes/sun/nio/fs/SolarisWatchService.java src/solaris/classes/sun/nio/fs/UnixChannelFactory.java src/solaris/classes/sun/nio/fs/UnixCopyFile.java src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java src/solaris/classes/sun/nio/fs/UnixFileAttributes.java src/solaris/classes/sun/nio/fs/UnixFileStore.java src/solaris/classes/sun/nio/fs/UnixFileStoreAttributes.java src/solaris/classes/sun/nio/fs/UnixFileSystem.java src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java src/solaris/classes/sun/nio/fs/UnixPath.java src/solaris/classes/sun/nio/fs/UnixSecureDirectoryStream.java src/solaris/classes/sun/nio/fs/UnixUriUtils.java src/solaris/classes/sun/nio/fs/UnixUserPrincipal.java src/solaris/classes/sun/nio/fs/UnixUserPrincipals.java src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java src/windows/classes/sun/nio/fs/WindowsConstants.java src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java src/windows/classes/sun/nio/fs/WindowsException.java src/windows/classes/sun/nio/fs/WindowsFileCopy.java src/windows/classes/sun/nio/fs/WindowsFileStore.java src/windows/classes/sun/nio/fs/WindowsFileSystem.java src/windows/classes/sun/nio/fs/WindowsLinkSupport.java src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java src/windows/classes/sun/nio/fs/WindowsPath.java src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java src/windows/classes/sun/nio/fs/WindowsUserPrincipal.java src/windows/classes/sun/nio/fs/WindowsUserPrincipals.java src/windows/classes/sun/nio/fs/WindowsWatchService.java test/demo/nio/ZipFileSystem/Sanity.java test/java/nio/file/DirectoryStream/Basic.java test/java/nio/file/DirectoryStream/Filters.java test/java/nio/file/Path/Misc.java test/java/nio/file/attribute/FileStoreAttributeView/Basic.java test/java/nio/file/attribute/FileStoreSpaceAttributeView/Basic.java test/java/nio/file/attribute/PosixFileAttributeView/Basic.java
diffstat 78 files changed, 1577 insertions(+), 1405 deletions(-) [+]
line wrap: on
line diff
--- a/make/java/nio/FILES_java.gmk	Mon Oct 20 11:19:56 2008 +0100
+++ b/make/java/nio/FILES_java.gmk	Mon Oct 20 19:20:24 2008 +0100
@@ -75,8 +75,8 @@
 	\
 	java/nio/charset/spi/CharsetProvider.java \
 	\
-	java/nio/file/Access.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 \
@@ -138,6 +138,7 @@
 	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/NamedAttributeView.java \
 	java/nio/file/attribute/PosixFileAttributeView.java \
 	java/nio/file/attribute/PosixFileAttributes.java \
--- a/make/java/nio/Makefile	Mon Oct 20 11:19:56 2008 +0100
+++ b/make/java/nio/Makefile	Mon Oct 20 19:20:24 2008 +0100
@@ -92,7 +92,7 @@
 	sun/nio/fs/UnixPath.java \
 	sun/nio/fs/UnixSecureDirectoryStream.java \
 	sun/nio/fs/UnixUriUtils.java \
-	sun/nio/fs/UnixUserPrincipal.java
+	sun/nio/fs/UnixUserPrincipals.java
 
 FILES_c += \
         DevPollArrayWrapper.c \
@@ -160,7 +160,7 @@
 	sun/nio/fs/WindowsSecurity.java \
 	sun/nio/fs/WindowsSecurityDescriptor.java \
 	sun/nio/fs/WindowsUriSupport.java \
-	sun/nio/fs/WindowsUserPrincipal.java \
+	sun/nio/fs/WindowsUserPrincipals.java \
 	sun/nio/fs/WindowsWatchService.java
 
 FILES_c += \
@@ -224,7 +224,7 @@
 	sun/nio/fs/UnixPath.java \
 	sun/nio/fs/UnixSecureDirectoryStream.java \
 	sun/nio/fs/UnixUriUtils.java \
-	sun/nio/fs/UnixUserPrincipal.java
+	sun/nio/fs/UnixUserPrincipals.java
 
 FILES_c += \
 	EPollArrayWrapper.c \
--- a/make/java/nio/mapfile-linux	Mon Oct 20 11:19:56 2008 +0100
+++ b/make/java/nio/mapfile-linux	Mon Oct 20 19:20:24 2008 +0100
@@ -138,6 +138,7 @@
 		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;
--- a/make/java/nio/mapfile-solaris	Mon Oct 20 11:19:56 2008 +0100
+++ b/make/java/nio/mapfile-solaris	Mon Oct 20 19:20:24 2008 +0100
@@ -121,6 +121,7 @@
 		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;
--- a/src/share/classes/java/nio/file/Access.java	Mon Oct 20 11:19:56 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright 2007-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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package java.nio.file;
-
-/**
- * Defines access modes used to test the existence or accessibility of a file.
- *
- * @since 1.7
- *
- * @see FileRef#checkAccess
- */
-
-public enum Access {
-    /**
-     * Test existence.
-     */
-    EXISTS,
-    /**
-     * Test read access.
-     */
-    READ,
-    /**
-     * Test write access.
-     */
-    WRITE,
-    /**
-     * Test execute access.
-     */
-    EXECUTE;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/nio/file/AccessMode.java	Mon Oct 20 19:20:24 2008 +0100
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2007-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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Defines access modes used to test the accessibility of a file.
+ *
+ * @since 1.7
+ *
+ * @see FileRef#checkAccess
+ */
+
+public enum AccessMode {
+    /**
+     * Test read access.
+     */
+    READ,
+    /**
+     * Test write access.
+     */
+    WRITE,
+    /**
+     * Test execute access.
+     */
+    EXECUTE;
+}
--- a/src/share/classes/java/nio/file/DirectoryStream.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/DirectoryStream.java	Mon Oct 20 19:20:24 2008 +0100
@@ -98,10 +98,11 @@
     extends Closeable, Iterable<T>
 {
     /**
-     * A task that decides if a directory entry should be accepted or filtered.
-     * A {@code Filter} is passed as the parameter to the {@link
-     * Path#newDirectoryStream(DirectoryStream.Filter) newDirectoryStream} method
-     * when opening a directory to iterate over the entries in the directory.
+     * An interface that is implemented by objects that decide if a directory
+     * entry should be accepted or filtered. A {@code Filter} is passed as the
+     * parameter to the {@link Path#newDirectoryStream(DirectoryStream.Filter)
+     * newDirectoryStream} method when opening a directory to iterate over the
+     * entries in the directory.
      *
      * <p> The {@link DirectoryStreamFilters} class defines factory methods to
      * create filters for a number of common usages and also methods to combine
--- a/src/share/classes/java/nio/file/DirectoryStreamFilters.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/DirectoryStreamFilters.java	Mon Oct 20 19:20:24 2008 +0100
@@ -25,7 +25,6 @@
 
 package java.nio.file;
 
-import java.util.regex.Pattern;
 import java.io.IOException;
 import java.io.IOError;
 import sun.nio.fs.MimeType;
@@ -42,63 +41,6 @@
 
     /**
      * Constructs a directory stream filter that filters directory entries by
-     * matching the {@code String} representation of their file {@link
-     * Path#getName names} against a case sensitive <em>glob</em>.
-     *
-     * <p> The expression language supported by this method is exactly as
-     * specified by the {@link java.nio.file.FileSystem#getNameMatcher
-     * getNameMatcher} method for the "glob" syntax.
-     *
-     * @param   glob
-     *          The pattern to match file names
-     *
-     * @return  A new directory stream filter
-     *
-     * @throws  java.util.regex.PatternSyntaxException
-     *          If the pattern is invalid
-     */
-    public static DirectoryStream.Filter<Path> newCaseSensitiveGlobFilter(String glob) {
-        String regex = sun.nio.fs.Globs.toRegexPattern(glob);
-        final Pattern pattern = Pattern.compile(regex);
-        return new DirectoryStream.Filter<Path>() {
-            @Override
-            public boolean accept(Path entry)  {
-                return pattern.matcher(entry.getName().toString()).matches();
-            }
-        };
-    }
-
-    /**
-     * Constructs a directory stream filter that filters directory entries by
-     * matching the {@code String} representation of their file {@link
-     * Path#getName names} against a given case insensitive <em>glob</em>.
-     *
-     * <p> The expression language supported by this method is exactly as
-     * specified by the {@link java.nio.file.FileSystem#getNameMatcher
-     * getNameMatcher} method for the "glob" syntax.
-     *
-     * @param   glob
-     *          The pattern to match file names
-     *
-     * @return  A new directory stream filter
-     *
-     * @throws  java.util.regex.PatternSyntaxException
-     *          If the pattern is invalid
-     */
-    public static DirectoryStream.Filter<Path> newCaseInsensitiveGlobFilter(String glob) {
-        String regex = sun.nio.fs.Globs.toRegexPattern(glob);
-        final Pattern pattern = Pattern.compile(regex,
-            (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE));
-        return new DirectoryStream.Filter<Path>() {
-            @Override
-            public boolean accept(Path entry)  {
-                return pattern.matcher(entry.getName().toString()).matches();
-            }
-        };
-    }
-
-    /**
-     * Constructs a directory stream filter that filters directory entries by
      * their  <a href="http://www.ietf.org/rfc/rfc2045.txt">MIME</a> content
      * type. The directory stream filter's {@link
      * java.nio.file.DirectoryStream.Filter#accept accept} method returns {@code
--- a/src/share/classes/java/nio/file/FileAction.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/FileAction.java	Mon Oct 20 19:20:24 2008 +0100
@@ -28,10 +28,11 @@
 import java.io.IOException;
 
 /**
- * A task that operates on a file. An implementation of this interface is provided
- * to the {@link Files#withDirectory withDirectory} utility method so that the
- * file action is {@link #invoke invoked} for all accepted entries in the
- * directory, after which, the directory is automatically closed.
+ * An interface that is implemented by objects that operate on a file. An
+ * implementation of this interface is provided to the {@link Files#withDirectory
+ * withDirectory} utility method so that the file action is {@link #invoke
+ * invoked} for all accepted entries in the directory, after which, the directory
+ * is automatically closed.
  *
  * <p> <b>Usage Example:</b>
  * Suppose we require to perform a task on all class files in a directory:
--- a/src/share/classes/java/nio/file/FileRef.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/FileRef.java	Mon Oct 20 19:20:24 2008 +0100
@@ -176,27 +176,23 @@
      *
      * <p> This method checks the existence of a file and that this Java virtual
      * machine has appropriate privileges that would allow it access the file
-     * according to all of access modes specified by the {@code first} and {@code
-     * rest} parameters as follows:
+     * according to all of access modes specified in the {@code modes} parameter
+     * as follows:
      *
      * <table border=1 cellpadding=5 summary="">
      * <tr> <th>Value</th> <th>Description</th> </tr>
      * <tr>
-     *   <td> {@link Access#EXISTS EXISTS} </td>
-     *   <td> Checks the existence of the file. </td>
-     * </tr>
-     * <tr>
-     *   <td> {@link Access#READ READ} </td>
+     *   <td> {@link AccessMode#READ READ} </td>
      *   <td> Checks that the file exists and that the Java virtual machine has
      *     permission to read the file. </td>
      * </tr>
      * <tr>
-     *   <td> {@link Access#WRITE WRITE} </td>
+     *   <td> {@link AccessMode#WRITE WRITE} </td>
      *   <td> Checks that the file exists and that the Java virtual machine has
      *     permission to write to the file, </td>
      * </tr>
      * <tr>
-     *   <td> {@link Access#EXECUTE EXECUTE} </td>
+     *   <td> {@link AccessMode#EXECUTE EXECUTE} </td>
      *   <td> Checks that the file exists and that the Java virtual machine has
      *     permission to {@link Runtime#exec execute} the file. The semantics
      *     may differ when checking access to a directory. For example, on UNIX
@@ -206,6 +202,9 @@
      * </tr>
      * </table>
      *
+     * <p> If the {@code modes} parameter is of length zero, then the existence
+     * of the file is checked.
+     *
      * <p> This method follows symbolic links if the file referenced by this
      * object is a symbolic link. Depending on the implementation, this method
      * may require to read file permissions, access control lists, or other
@@ -218,13 +217,11 @@
      * file). Care should be taken when using this method in security sensitive
      * applications.
      *
-     * @param   first
-     *          An access mode to be check
-     * @param   rest
-     *          Other access modes to check
+     * @param   modes
+     *          The access modes to check; may have zero elements
      *
      * @throws  UnsupportedOperationException
-     *          An implementation is required to support checking for {@code EXISTS},
+     *          An implementation is required to support checking for
      *          {@code READ}, {@code WRITE}, and {@code EXECUTE} access. This
      *          exception is specified to allow for the {@code Access} enum to
      *          be extended in future releases.
@@ -239,13 +236,13 @@
      * @throws  SecurityException
      *          In the case of the default provider, and a security manager is
      *          installed, the {@link SecurityManager#checkRead(String) checkRead}
-     *          is invoked when checking the existence or read access to the file,
-     *          the {@link SecurityManager#checkWrite(String) checkWrite} is
-     *          invoked when checking write access to the file, and {@link
-     *          SecurityManager#checkExec(String) checkExec} is invoked when
-     *          checking execute access.
+     *          is invoked when checking read access to the file or only the
+     *          existence of the file, the {@link SecurityManager#checkWrite(String)
+     *          checkWrite} is invoked when checking write access to the file,
+     *          and {@link SecurityManager#checkExec(String) checkExec} is invoked
+     *          when checking execute access.
      */
-    void checkAccess(Access first, Access... rest) throws IOException;
+    void checkAccess(AccessMode... modes) throws IOException;
 
     /**
      * Returns a file attribute view of a given type.
@@ -320,12 +317,12 @@
      * <li>It is <i>reflexive</i>: for a non-null {@code FileRef} {@code f},
      *     {@code f.isSameFile(f)} should return {@code true}.
      * <li>It is <i>symmetric</i>: for two non-null {@code FileRefs}
-     *     {@code f} and {@code g}, if {@code f.isSameFile(g)} returns {@code true}
-     *     then {@code g.isSameFile(f)} should return {@code true}.
+     *     {@code f} and {@code g}, {@code f.isSameFile(g)} will equal
+     *     {@code g.isSameFile(f)}.
      * <li>It is <i>transitive</i>: for three {@code FileRefs}
      *     {@code f}, {@code g}, and {@code h}, if {@code f.isSameFile(g)} returns
      *     {@code true} and {@code g.isSameFile(h)} returns {@code true}, then
-     *     {@code f.isSameFile(h)} should return return {@code true}.
+     *     {@code f.isSameFile(h)} will return return {@code true}.
      * </ul>
      *
      * @param   other
--- a/src/share/classes/java/nio/file/FileSystem.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/FileSystem.java	Mon Oct 20 19:20:24 2008 +0100
@@ -360,10 +360,7 @@
      * class.
      *
      * <p> For both the glob and regex syntaxes then whether matching is case
-     * sensitive, and other matching details, are implementation-dependent. In
-     * the Sun implementation for example, matching of file names on Unix is case
-     * sensitive, whereas on Windows, file names are converted to uppercase for
-     * matching purposes.
+     * sensitive, and other matching details, are implementation-dependent.
      *
      * <p> The {@code PathMatcher} returned by this method matches on the {@link
      * Path#getName name} component of a {@code Path}. If the {@link
@@ -387,8 +384,9 @@
     public abstract PathMatcher getNameMatcher(String syntax, String pattern);
 
     /**
-     * Returns the {@code UserPrincipalLookupService} for this file system.
-     * The resulting lookup service may be used to lookup user or group names.
+     * Returns the {@code UserPrincipalLookupService} for this file system
+     * <i>(optional operation)</i>. The resulting lookup service may be used to
+     * lookup user or group names.
      *
      * <p> <b>Usage Example:</b>
      * Suppose we want to make "joe" the owner of a file:
@@ -399,8 +397,10 @@
      *     Attributes.setOwner(file, joe);
      * </pre>
      *
-     * @return  The {@code UserPrincipalLookupService} for this file system,
-     *          or {@code null} if the file system does not have a lookup service
+     * @throws  UnsupportedOperationException
+     *          If this {@code FileSystem} does not does have a lookup service
+     *
+     * @return  The {@code UserPrincipalLookupService} for this file system
      */
     public abstract UserPrincipalLookupService getUserPrincipalLookupService();
 
@@ -413,7 +413,7 @@
      * @return  a new watch service
      *
      * @throws  UnsupportedOperationException
-     *          If the {@code FileSystem} does not support watching file system
+     *          If this {@code FileSystem} does not support watching file system
      *          objects for changes and events. This exception is not thrown
      *          by {@code FileSystems} created by the default provider.
      * @throws  IOException
--- a/src/share/classes/java/nio/file/PathMatcher.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/PathMatcher.java	Mon Oct 20 19:20:24 2008 +0100
@@ -26,7 +26,8 @@
 package java.nio.file;
 
 /**
- * A task that performs match operations on paths.
+ * An interface that is implemented by objects that perform match operations on
+ * paths.
  *
  * @since 1.7
  *
--- a/src/share/classes/java/nio/file/SimpleFileVisitor.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/SimpleFileVisitor.java	Mon Oct 20 19:20:24 2008 +0100
@@ -47,12 +47,23 @@
     protected SimpleFileVisitor() {
     }
 
+    /**
+     * Invoked for a directory before entries in the directory are visited.
+     *
+     * <p> Unless overridden, this method returns {@link FileVisitResult#CONTINUE
+     * CONTINUE}.
+     */
     @Override
     public FileVisitResult preVisitDirectory(T dir) {
         return FileVisitResult.CONTINUE;
     }
 
     /**
+     * Invoked for a directory that could not be opened.
+     *
+     * <p> Unless overridden, this method throws {@link IOError} with the I/O
+     * exception as cause.
+     *
      * @throws  IOError
      *          With the I/O exception thrown when the attempt to open the
      *          directory failed
@@ -62,12 +73,23 @@
         throw new IOError(exc);
     }
 
+    /**
+     * Invoked for a file in a directory.
+     *
+     * <p> Unless overridden, this method returns {@link FileVisitResult#CONTINUE
+     * CONTINUE}.
+     */
     @Override
     public FileVisitResult visitFile(T file, BasicFileAttributes attrs) {
         return FileVisitResult.CONTINUE;
     }
 
     /**
+     * Invoked for a file when its basic file attributes could not be read.
+     *
+     * <p> Unless overridden, this method throws {@link IOError} with the I/O
+     * exception as cause.
+     *
      * @throws  IOError
      *          With the I/O exception thrown when the attempt to read the file
      *          attributes failed
@@ -78,6 +100,14 @@
     }
 
     /**
+     * Invoked for a directory after entries in the directory, and all of their
+     * descendants, have been visited.
+     *
+     * <p> Unless overridden, this method returns {@link FileVisitResult#CONTINUE
+     * CONTINUE} if the directory iteration completes without an I/O exception;
+     * otherwise this method throws {@link IOError} with the I/O exception as
+     * cause.
+     *
      * @throws  IOError
      *          If iteration of the directory completed prematurely due to an
      *          I/O error
--- a/src/share/classes/java/nio/file/WatchEvent.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/WatchEvent.java	Mon Oct 20 19:20:24 2008 +0100
@@ -26,8 +26,8 @@
 package java.nio.file;
 
 /**
- * Represents an event or a repeated event for an object that is registered
- * with a {@link WatchService}.
+ * An event or a repeated event for an object that is registered with a {@link
+ * WatchService}.
  *
  * <p> An event is classified by its {@link #getKind() kind} and has a {@link
  * #getCount() count} to indicate the number of times that the event has been
@@ -41,7 +41,7 @@
  * @since 1.7
  */
 
-public interface WatchEvent<T> {
+public abstract class WatchEvent<T> {
 
     /**
      * An event kind, for the purposes of identification.
@@ -62,6 +62,11 @@
     }
 
     /**
+     * Initializes a new instance of this class.
+     */
+    protected WatchEvent() { }
+
+    /**
      * An event modifier that qualifies how a {@link Watchable} is registered
      * with a {@link WatchService}.
      *
@@ -82,7 +87,7 @@
      *
      * @return  The event kind
      */
-    Kind<T> getKind();
+    public abstract Kind<T> getKind();
 
     /**
      * Returns the event count. If the event count is greater than {@code 1}
@@ -90,7 +95,7 @@
      *
      * @return  The event count
      */
-    int getCount();
+    public abstract int getCount();
 
     /**
      * Returns the context for the event.
@@ -104,5 +109,5 @@
      *
      * @return  The event context; may be {@code null}
      */
-    T getContext();
+    public abstract T getContext();
 }
--- a/src/share/classes/java/nio/file/WatchKey.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/WatchKey.java	Mon Oct 20 19:20:24 2008 +0100
@@ -80,7 +80,11 @@
  * @since 1.7
  */
 
-public interface WatchKey {
+public abstract class WatchKey {
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected WatchKey() { }
 
     /**
      * Tells whether or not this watch key is valid.
@@ -90,7 +94,7 @@
      *
      * @return  {@code true} if, and only if, this watch key is valid
      */
-    boolean isValid();
+    public abstract boolean isValid();
 
     /**
      * Retrieves and removes all pending events for this watch key, returning
@@ -100,7 +104,7 @@
      *
      * @return  The list of the events retrieved
      */
-    List<WatchEvent<?>> pollEvents();
+    public abstract List<WatchEvent<?>> pollEvents();
 
     /**
      * Resets this watch key.
@@ -112,11 +116,11 @@
      * events then the watch key is put into the ready state and will remain in
      * that state until an event is detected or the watch key is cancelled.
      *
-     * @return  {@code true} if the watch key has been reset, {@code false} if
-     *          the watch key could not be reset because the key is no longer
-     *          {@link #isValid valid}
+     * @return  {@code true} if the watch key is valid and has been reset;
+     *          {@code false} if the watch key could not be reset because it is
+     *          no longer {@link #isValid valid}
      */
-    boolean reset();
+    public abstract boolean reset();
 
     /**
      * Cancels the registration with the watch service. Upon return the watch key
@@ -129,5 +133,5 @@
      * <p> If this watch key has already been cancelled then invoking this
      * method has no effect.  Once cancelled, a watch key remains forever invalid.
      */
-    void cancel();
+    public abstract void cancel();
 }
--- a/src/share/classes/java/nio/file/WatchService.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/WatchService.java	Mon Oct 20 19:20:24 2008 +0100
@@ -103,10 +103,15 @@
  * @see FileSystem#newWatchService
  */
 
-public interface WatchService
-    extends Closeable
+public abstract class WatchService
+    implements Closeable
 {
     /**
+     * Initializes a new instance of this class.
+     */
+    protected WatchService() { }
+
+    /**
      * Closes this watch service.
      *
      * <p> If a thread is currently blocked in the {@link #take take} or {@link
@@ -124,7 +129,7 @@
      *          If an I/O error occurs
      */
     @Override
-    void close() throws IOException;
+    public abstract void close() throws IOException;
 
     /**
      * Retrieves and removes the next watch key, or {@code null} if none are
@@ -135,7 +140,7 @@
      * @throws  ClosedWatchServiceException
      *          If this watch service is closed
      */
-    WatchKey poll();
+    public abstract WatchKey poll();
 
     /**
      * Retrieves and removes the next watch key, waiting if necessary up to the
@@ -155,7 +160,8 @@
      * @throws  InterruptedException
      *          If interrupted while waiting
      */
-    WatchKey poll(long timeout, TimeUnit unit) throws InterruptedException;
+    public abstract WatchKey poll(long timeout, TimeUnit unit)
+        throws InterruptedException;
 
     /**
      * Retrieves and removes next watch key waiting if none are yet present.
@@ -168,5 +174,5 @@
      * @throws  InterruptedException
      *          If interrupted while waiting
      */
-    WatchKey take() throws InterruptedException;
+    public abstract WatchKey take() throws InterruptedException;
 }
--- a/src/share/classes/java/nio/file/Watchable.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/Watchable.java	Mon Oct 20 19:20:24 2008 +0100
@@ -122,6 +122,6 @@
      *          permission required to monitor this object. Implementations of
      *          this interface should specify the permission checks.
      */
-    WatchKey register(WatchService watcher, WatchEvent.Kind... events)
+    WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events)
         throws IOException;
 }
--- a/src/share/classes/java/nio/file/attribute/AttributeView.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/AttributeView.java	Mon Oct 20 19:20:24 2008 +0100
@@ -106,7 +106,7 @@
      * @param   rest
      *          The names of others attributes to read (case sensitive)
      *
-     * @return  A unmodifiable map of the attributes; may be empty. Its keys are
+     * @return  An unmodifiable map of the attributes; may be empty. Its keys are
      *          the attribute names, its values are the attribute values
      *
      * @throws  IOException
--- a/src/share/classes/java/nio/file/attribute/Attributes.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/Attributes.java	Mon Oct 20 19:20:24 2008 +0100
@@ -32,7 +32,8 @@
 
 /**
  * This class consists exclusively of static methods that operate on or return
- * the attributes of files or file stores.
+ * the attributes of files or file stores. These methods provide for convenient
+ * use of the {@link AttributeView attribute-views} defined in this package.
  *
  * @since 1.7
  */
--- a/src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/FileOwnerAttributeView.java	Mon Oct 20 19:20:24 2008 +0100
@@ -60,7 +60,7 @@
      * Read the file owner.
      *
      * <p> It it implementation specific if the file owner can be a {@link
-     * UserPrincipal#isGroup() group}.
+     * GroupPrincipal group}.
      *
      * @return  the file owner
      *
@@ -79,7 +79,7 @@
      * Updates the file owner.
      *
      * <p> It it implementation specific if the file owner can be a {@link
-     * UserPrincipal#isGroup() group}. To ensure consistent and correct behavior
+     * GroupPrincipal group}. To ensure consistent and correct behavior
      * across platforms it is recommended that this method should only be used
      * to set the file owner to a user principal that is not a group.
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/nio/file/attribute/GroupPrincipal.java	Mon Oct 20 19:20:24 2008 +0100
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2007-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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * A {@code UserPrincipal} representing a <em>group identity</em>, used to
+ * determine access rights to objects in a file system. The exact definition of
+ * a group is implementation specific, but typically, it represents an identity
+ * created for administrative purposes so as to determine the access rights for
+ * the members of the group. Whether an entity can be a member of multiple
+ * groups, and whether groups can be nested, are implementation specified and
+ * therefore not specified.
+ *
+ * @since 1.7
+ *
+ * @see UserPrincipalLookupService#lookupPrincipalByGroupName
+ */
+
+public interface GroupPrincipal extends UserPrincipal { }
--- a/src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/PosixFileAttributeView.java	Mon Oct 20 19:20:24 2008 +0100
@@ -44,10 +44,9 @@
  * file's attributes. The file {@link PosixFileAttributes#owner() owner} is
  * represented by a {@link UserPrincipal} that is the identity of the file owner
  * for the purposes of access control. The {@link PosixFileAttributes#group()
- * group-owner}, also represented by a <tt>UserPrincipal</tt>, is the
- * identity of the group owner. The exact definition of group is implementation
- * specific but typically it represents an identity created for administrative
- * purposes so as to determine the access rights for the members of the group.
+ * group-owner}, represented by a {@link GroupPrincipal}, is the identity of the
+ * group owner, where a group is an identity created for administrative purposes
+ * so as to determine the access rights for the members of the group.
  *
  * <p> The {@link PosixFileAttributes#permissions() permissions} attribute is a
  * set of access permissions. This file attribute view provides access to the nine
@@ -71,9 +70,9 @@
  *
  * <h4> Dynamic Access </h4>
  * <p> Where dynamic access to file attributes is required, the attributes
- * supported by this attribute view are as defined by {@code
- * BasicFileAttributeView}, and in addition, the following attributes are
- * supported:
+ * supported by this attribute view are as defined by {@link
+ * BasicFileAttributeView} and {@link FileOwnerAttributeView}, and in addition,
+ * the following attributes are supported:
  * <blockquote>
  * <table border="1" cellpadding="8">
  *   <tr>
@@ -85,20 +84,17 @@
  *     <td> {@link Set}&lt;{@link PosixFilePermission}&gt; </td>
  *   </tr>
  *   <tr>
- *     <td> "owner" </td>
- *     <td> {@link UserPrincipal} </td>
- *   </tr>
- *   <tr>
  *     <td> "group" </td>
- *     <td> {@link UserPrincipal} </td>
+ *     <td> {@link GroupPrincipal} </td>
  *   </tr>
  * </table>
  * </blockquote>
  *
- * <p> The {@link #getAttribute getAttribute} or {@link #readAttributes(String,String[])
- * readAttributes(String,String[])} methods may be used to read any of these
- * attributes, or any of the attributes defined by {@link BasicFileAttributeView}
- * as if by invoking the {@link #readAttributes readAttributes()} method.
+ * <p> The {@link #getAttribute getAttribute} or {@link
+ * #readAttributes(String,String[]) readAttributes(String,String[])} methods may
+ * be used to read any of these attributes, or any of the attributes defined by
+ * {@link BasicFileAttributeView} as if by invoking the {@link #readAttributes
+ * readAttributes()} method.
  *
  * <p> The {@link #setAttribute setAttribute} method may be used to update the
  * file's last modified time, last access time or create time attributes as
@@ -111,7 +107,7 @@
  * <p> Implementations supporting this attribute view may also support setting
  * the initial permissions when creating a file or directory. The
  * initial permissions are provided to the  {@link Path#createFile createFile}
- * or {@link Path#createDirectory createDirectory} methods as an {@link
+ * or {@link Path#createDirectory createDirectory} methods as a {@link
  * FileAttribute} with {@link FileAttribute#name name} {@code "posix:permissions"}
  * and a {@link FileAttribute#value value} that is the set of permissions. The
  * following example uses the {@link PosixFilePermissions#asFileAttribute
@@ -143,7 +139,7 @@
  */
 
 public interface PosixFileAttributeView
-    extends BasicFileAttributeView
+    extends BasicFileAttributeView, FileOwnerAttributeView
 {
     /**
      * Returns the name of the attribute view. Attribute views of this type
@@ -183,17 +179,11 @@
     void setPermissions(Set<PosixFilePermission> perms) throws IOException;
 
     /**
-     * Updates the file owner.
+     * Updates the file group-owner.
      *
-     * <p> The {@code owner} parameter is a {@link UserPrincipal} representing
-     * the owner. Its {@link UserPrincipal#isGroup() isGroup()} method returns
-     * <tt>false</tt>.
-     *
-     * @param   owner
-     *          The new file owner
-     *
-     * @throws  IllegalArgumentException
-     *          If the pre-conditions for the {@code owner} parameter is not met
+     * @param   group
+     *          The new file group-owner
+
      * @throws  IOException
      *          If an I/O error occurs
      * @throws  SecurityException
@@ -202,27 +192,5 @@
      *          or its {@link SecurityManager#checkWrite(String) checkWrite}
      *          method denies write access to the file.
      */
-    void setOwner(UserPrincipal owner) throws IOException;
-
-    /**
-     * Updates the file group-owner.
-     *
-     * <p> The {@code group} parameter is a {@link UserPrincipal} representing
-     * the group. Its {@link UserPrincipal#isGroup() isGroup()} method returns
-     * {@code true}.
-     *
-     * @param   group
-     *          The new file group-owner
-     *
-     * @throws  IllegalArgumentException
-     *          If the pre-conditions for the {@code group} parameter is not met
-     * @throws  IOException
-     *          If an I/O error occurs
-     * @throws  SecurityException
-     *          In the case of the default provider, and a security manager is
-     *          installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt>
-     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
-     *          method denies write access to the file.
-     */
-    void setGroup(UserPrincipal group) throws IOException;
+    void setGroup(GroupPrincipal group) throws IOException;
 }
--- a/src/share/classes/java/nio/file/attribute/PosixFileAttributes.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/PosixFileAttributes.java	Mon Oct 20 19:20:24 2008 +0100
@@ -60,7 +60,7 @@
      *
      * @see PosixFileAttributeView#setGroup
      */
-    UserPrincipal group();
+    GroupPrincipal group();
 
     /**
      * Returns the permissions of the file. The file permissions are returned
--- a/src/share/classes/java/nio/file/attribute/UserPrincipal.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/UserPrincipal.java	Mon Oct 20 19:20:24 2008 +0100
@@ -41,32 +41,14 @@
  *
  * <p> A {@code UserPrincipal} object is an abstract representation of an
  * identity. It has a {@link #getName() name} that is typically the username or
- * account name that it represents. User principal objects are created by {@link
+ * account name that it represents. User principal objects may be obtained using
+ * a {@link UserPrincipalLookupService}, or returned by {@link
  * FileAttributeView} implementations that provide access to identity related
- * attributes. For example, the {@link PosixFileAttributeView} provides
- * access to a file's {@link PosixFileAttributes#owner owner} and {@link
- * PosixFileAttributes#group group-owner} on platforms and file systems that
- * support these attributes.
- *
- * <p> A {@code UserPrincipal} may represent a single identity or a
- * <em>group</em> identity. The exact definition of group is implementation
- * specific but typically it represents an identity created for administrative
- * purposes so as to determine the access rights for the members of the group.
- * Whether an entity can be a member of multiple groups, and whether
- * groups can be nested, is implementation specific.
+ * attributes. For example, the {@link AclFileAttributeView} and {@link
+ * PosixFileAttributeView} provide access to a file's {@link
+ * PosixFileAttributes#owner owner}.
  *
  * @since 1.7
- *
- * @see UserPrincipalLookupService
  */
 
-public interface UserPrincipal
-    extends Principal
-{
-    /**
-     * Tells whether this user principal represents a group.
-     *
-     * @return  {@code true} if this this user principal represents a group
-     */
-    boolean isGroup();
-}
+public interface UserPrincipal extends Principal { }
--- a/src/share/classes/java/nio/file/attribute/UserPrincipalLookupService.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/UserPrincipalLookupService.java	Mon Oct 20 19:20:24 2008 +0100
@@ -28,29 +28,35 @@
 import java.io.IOException;
 
 /**
- * An object to lookup user principals by name. A {@link UserPrincipal}
+ * An object to lookup user and group principals by name. A {@link UserPrincipal}
  * represents an identity that may be used to determine access rights to objects
- * in a file system. A {@code UserPrincipalLookupService} defines methods to
- * lookup identities by name or group name (which are typically user or account
- * names). Whether names and group names are case sensitive or not depends on
- * the implementation. The exact definition of a group is also implementation
- * specific but typically a group represents an identity created for administrative
- * purposes so as to determine the access rights for the members of the group.
- * In particular it is implementation specific if the <em>namespace</em> for
- * names and groups is the same or is distinct. Where the namespace is the same
- * then invoking {@link #lookupPrincipalByName lookupPrincipalByName} to lookup
- * a name may return a user principal representing a group, and invoking {@link
- * #lookupPrincipalByGroupName lookupPrincipalByGroupName} to lookup a group
- * may return a user principal that is not a group. To ensure consistent and
- * correct behavior across platforms it is recommended that this API be used as
- * if the namespaces are distinct.
+ * in a file system. A {@link GroupPrincipal} represents a <em>group identity</em>.
+ * A {@code UserPrincipalLookupService} defines methods to lookup identities by
+ * name or group name (which are typically user or account names). Whether names
+ * and group names are case sensitive or not depends on the implementation.
+ * The exact definition of a group is implementation specific but typically a
+ * group represents an identity created for administrative purposes so as to
+ * determine the access rights for the members of the group. In particular it is
+ * implementation specific if the <em>namespace</em> for names and groups is the
+ * same or is distinct. To ensure consistent and correct behavior across
+ * platforms it is recommended that this API be used as if the namespaces are
+ * distinct. In other words, the {@link #lookupPrincipalByName
+ * lookupPrincipalByName} should be used to lookup users, and {@link
+ * #lookupPrincipalByGroupName lookupPrincipalByGroupName} should be used to
+ * lookup groups.
  *
  * @since 1.7
  *
  * @see java.nio.file.FileSystem#getUserPrincipalLookupService
  */
 
-public interface UserPrincipalLookupService {
+public abstract class UserPrincipalLookupService {
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected UserPrincipalLookupService() {
+    }
 
     /**
      * Lookup a user principal by name.
@@ -68,13 +74,17 @@
      *          In the case of the default provider, and a security manager is
      *          installed, it checks {@link RuntimePermission}<tt>("lookupUserInformation")</tt>
      */
-    UserPrincipal lookupPrincipalByName(String name) throws IOException;
+    public abstract UserPrincipal lookupPrincipalByName(String name)
+        throws IOException;
 
     /**
-     * Lookup a user principal by group name.
+     * Lookup a group principal by group name.
      *
-     * <p> Where an implementation does not support any notion of groups then
-     * this method always throws {@link UserPrincipalNotFoundException}.
+     * <p> Where an implementation does not support any notion of group then
+     * this method always throws {@link UserPrincipalNotFoundException}. Where
+     * the namespace for user accounts and groups is the same, then this method
+     * is identical to invoking {@link #lookupPrincipalByName
+     * lookupPrincipalByName}.
      *
      * @param   group
      *          The string representation of the group to lookup
@@ -82,12 +92,13 @@
      * @return  A user principal.
      *
      * @throws  UserPrincipalNotFoundException
-     *          The principal does not exist
+     *          The principal does not exist, or it exists but it not a group
      * @throws  IOException
      *          If an I/O error occurs
      * @throws  SecurityException
      *          In the case of the default provider, and a security manager is
      *          installed, it checks {@link RuntimePermission}<tt>("lookupUserInformation")</tt>
      */
-    UserPrincipal lookupPrincipalByGroupName(String group) throws IOException;
+    public abstract GroupPrincipal lookupPrincipalByGroupName(String group)
+        throws IOException;
 }
--- a/src/share/classes/java/nio/file/attribute/package-info.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/attribute/package-info.java	Mon Oct 20 19:20:24 2008 +0100
@@ -95,11 +95,12 @@
  *
  * <ul>
  *
- *   <p><li> The {@link java.nio.file.attribute.UserPrincipal} interface
- *   to represent an identity. </li>
+ *   <p><li> The {@link java.nio.file.attribute.UserPrincipal} and
+ *   {@link java.nio.file.attribute.GroupPrincipal} interfaces represent an
+ *   identity or group identity. </li>
  *
  *   <p><li> The {@link java.nio.file.attribute.UserPrincipalLookupService}
- *   interface defines methods to lookup user principals. </li>
+ *   interface defines methods to lookup user or group principals. </li>
  *
  *   <p><li> The {@link java.nio.file.attribute.Attribute} interface
  *   represents the value of an attribute for cases where the attribute value is
--- a/src/share/classes/java/nio/file/spi/AbstractPath.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/java/nio/file/spi/AbstractPath.java	Mon Oct 20 19:20:24 2008 +0100
@@ -230,7 +230,7 @@
     @Override
     public final boolean exists() {
         try {
-            checkAccess(Access.EXISTS);
+            checkAccess();
             return true;
         } catch (IOException x) {
             // unable to determine if file exists
@@ -241,7 +241,7 @@
     @Override
     public final boolean notExists() {
         try {
-            checkAccess(Access.EXISTS);
+            checkAccess();
             return false;
         } catch (NoSuchFileException x) {
             // file confirmed not to exist
--- a/src/share/classes/sun/nio/fs/AbstractWatchKey.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/sun/nio/fs/AbstractWatchKey.java	Mon Oct 20 19:20:24 2008 +0100
@@ -32,7 +32,7 @@
  * Base implementation class for watch keys.
  */
 
-abstract class AbstractWatchKey implements WatchKey {
+abstract class AbstractWatchKey extends WatchKey {
 
     /**
      * Maximum size of event list (in the future this may be tunable)
@@ -140,7 +140,7 @@
     /**
      * WatchEvent implementation
      */
-    private static class Event<T> implements WatchEvent<T> {
+    private static class Event<T> extends WatchEvent<T> {
         private final WatchEvent.Kind<T> kind;
         private final T context;
 
--- a/src/share/classes/sun/nio/fs/AbstractWatchService.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/sun/nio/fs/AbstractWatchService.java	Mon Oct 20 19:20:24 2008 +0100
@@ -33,7 +33,7 @@
  * Base implementation class for watch services.
  */
 
-abstract class AbstractWatchService implements WatchService {
+abstract class AbstractWatchService extends WatchService {
 
     // signaled keys waiting to be dequeued
     private final LinkedBlockingDeque<WatchKey> pendingKeys =
--- a/src/share/classes/sun/nio/fs/NativeBuffer.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/sun/nio/fs/NativeBuffer.java	Mon Oct 20 19:20:24 2008 +0100
@@ -25,6 +25,7 @@
 
 package sun.nio.fs;
 
+import sun.misc.Unsafe;
 import sun.misc.Cleaner;
 
 /**
@@ -32,13 +33,30 @@
  */
 
 class NativeBuffer {
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
     private final long address;
     private final int size;
-    private Cleaner cleaner;
+    private final Cleaner cleaner;
 
-    NativeBuffer(long address, int size) {
-        this.address = address;
+    // 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() {
@@ -53,11 +71,17 @@
         return size;
     }
 
-    void setCleaner(Cleaner cleaner) {
-        this.cleaner = cleaner;
-    }
-
     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;
+    }
 }
--- a/src/share/classes/sun/nio/fs/NativeBuffers.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/classes/sun/nio/fs/NativeBuffers.java	Mon Oct 20 19:20:24 2008 +0100
@@ -26,7 +26,6 @@
 package sun.nio.fs;
 
 import sun.misc.Unsafe;
-import sun.misc.Cleaner;
 
 /**
  * Factory for native buffers.
@@ -51,25 +50,21 @@
             buffers[i] = new ThreadLocal<NativeBuffer>();
     }
 
-    private static class Deallocator implements Runnable {
-        private final long address;
-
-        Deallocator(long address) {
-            this.address = address;
-        }
-
-        public void run() {
-            unsafe.freeMemory(address);
-        }
+    /**
+     * 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. The buffer is
-     * returned from the per-thread cache if available; otherwise a new buffer
-     * is allocated.
+     * Returns a native buffer, of at least the given size, from the thread
+     * local cache.
      */
-    static NativeBuffer getNativeBuffer(int size) {
-        // Grab a buffer if available
+    static NativeBuffer getNativeBufferFromCache(int size) {
+        // return from cache if possible
         for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
             NativeBuffer buffer = buffers[i].get();
             if (buffer != null && buffer.size() >= size) {
@@ -77,22 +72,29 @@
                 return buffer;
             }
         }
-        // Make a new one of at least 4k
-        if (size < 4096) size = 4096;
-        long address = unsafe.allocateMemory(size);
-        NativeBuffer buffer = new NativeBuffer(address, size);
-        Cleaner cl = Cleaner.create(buffer, new Deallocator(address));
-        buffer.setCleaner(cl);
-        return buffer;
+        return null;
     }
 
     /**
-     * Releases the given buffer. If there is space in the per-thread cache
+     * 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) {
-        if (buffer == null) return;
-
         // Put it in an empty slot if such exists
         for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
             if (buffers[i].get() == null) {
@@ -115,19 +117,23 @@
     }
 
     /**
-     * Allocates a native buffer for the bytes of the given byte array.
+     * Copies a byte array and zero terminator into a given native buffer.
      */
-    static NativeBuffer asNativeBuffer(byte[] path) {
-        int len = path.length;
-        NativeBuffer buffer = getNativeBuffer(len+1);
+    static void copyCStringToNativeBuffer(byte[] cstr, NativeBuffer buffer) {
+        long offset = Unsafe.ARRAY_BYTE_BASE_OFFSET;
+        long len = cstr.length;
+        assert buffer.size() >= (len + 1);
+        unsafe.copyMemory(cstr, offset, null, buffer.address(), len);
+        unsafe.putByte(buffer.address() + len, (byte)0);
+    }
 
-        // FIXME - store reference to object in NativeBuffer to avoid copying
-        // into the buffer for each I/O.
-
-        // copy into buffer and zero terminate
-        long offset = Unsafe.ARRAY_BYTE_BASE_OFFSET;
-        unsafe.copyMemory(path, offset, null, buffer.address(), (long)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;
     }
 }
--- a/src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFilePath.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFilePath.java	Mon Oct 20 19:20:24 2008 +0100
@@ -400,7 +400,7 @@
     @Override
     public ZipFilePath toRealPath(boolean resolveLinks) throws IOException {
         ZipFilePath realPath = new ZipFilePath(this.fileSystem, pathForZip);
-        realPath.checkAccess(Access.EXISTS);
+        realPath.checkAccess();
         return realPath;
     }
 
@@ -952,30 +952,17 @@
     }
 
     @Override
-    public void checkAccess(Access first, Access... rest) throws IOException {
-        boolean e = false;
-        boolean r = false;
+    public void checkAccess(AccessMode... modes) throws IOException {
         boolean w = false;
         boolean x = false;
 
-        if (first == Access.EXISTS) e = true;
-        else if (first == Access.READ) r = true;
-        else if (first == Access.WRITE) w = true;
-        else if (first == Access.EXECUTE) x = true;
-        else {
-            if (first == null)
-                throw new NullPointerException();
-            throw new UnsupportedOperationException();
-        }
-        for (Access access: rest) {
-            if (access == Access.EXISTS) e = true;
-            else if (access == Access.READ) r = true;
-            else if (access == Access.WRITE) w = true;
-            else if (access == Access.EXECUTE) x = true;
-            else {
-                if (access == null)
-                    throw new NullPointerException();
-                throw new UnsupportedOperationException();
+        for (AccessMode mode: modes) {
+            switch (mode) {
+                case READ: break;
+                case WRITE : w = true; break;
+                case EXECUTE : x = true; break;
+                default:
+                    throw new UnsupportedOperationException();
             }
         }
 
@@ -983,15 +970,14 @@
             begin();
             ZipFilePath resolvedZipPath = getResolvedPathForZip();
             int nameCount = resolvedZipPath.getNameCount();
-            if (nameCount == 0) {
-                throw new IOException("entry not found");
-            }
-            ZipEntryInfo ze = ZipUtils.getEntry(resolvedZipPath);
+            if (nameCount == 0)
+                throw new NoSuchFileException(toString());
 
             if (w) {
                 throw new AccessDeniedException("write access denied for the file: " + this.toString());
             }
             if (x) {
+                ZipEntryInfo ze = ZipUtils.getEntry(resolvedZipPath);
                 long attrs = ze.extAttrs;
                 if (!((((attrs << 4) >> 24) & 0x04) == 0x04))
                     throw new AccessDeniedException("execute access denied for the file: " + this.toString());
--- a/src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFileStream.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFileStream.java	Mon Oct 20 19:20:24 2008 +0100
@@ -149,7 +149,7 @@
             throws IOException {
 
         if (zipPath.getNameCount() != 0) { // if path is '/' no need for check existence
-            zipPath.checkAccess(Access.EXISTS);
+            zipPath.checkAccess();
         }
 
         if (!zipPath.isArchiveFile() && !zipPath.isDirectory()) {
--- a/src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFileSystem.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFileSystem.java	Mon Oct 20 19:20:24 2008 +0100
@@ -269,8 +269,18 @@
     @Override
     public PathMatcher getNameMatcher(String syntax, String expr) {
         if (syntax.equalsIgnoreCase("glob")) {
-            final DirectoryStream.Filter<Path> filter =
-                DirectoryStreamFilters.newCaseSensitiveGlobFilter(expr);
+             // Temporary
+             String regex = sun.nio.fs.Globs.toRegexPattern(expr);
+             final Pattern pattern = Pattern.compile(regex,
+                 (Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE));
+             final DirectoryStream.Filter<Path> filter =
+                new DirectoryStream.Filter<Path>() {
+                    @Override
+                    public boolean accept(Path entry)  {
+                        return pattern.matcher(entry.getName().toString()).matches();
+                    }
+                };
+
             return new PathMatcher() {
                 @Override
                 public boolean matches(Path path) {
--- a/src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFileSystemProvider.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/share/demo/nio/ZipFileSystem/com/sun/nio/zipfs/ZipFileSystemProvider.java	Mon Oct 20 19:20:24 2008 +0100
@@ -80,7 +80,7 @@
         if (!checkZipFilePath(nativePath)) {
             throw new InvalidPathException(nativePath.toString(), "file name does not contain zip/jar File");
         }
-        nativePath.checkAccess(Access.EXISTS); // check the existance of the path before proceed
+        nativePath.checkAccess(); // check the existance of the path before proceed
 
         ZipFileSystem fileSystem = null;
         // construct uri to find in cached file systems
@@ -126,7 +126,7 @@
             throw new UnsupportedOperationException();
         }
         try {
-            ((Path) file).checkAccess(Access.EXISTS);
+            ((Path) file).checkAccess();
         } catch (IOException e) {
             throw e;
         }
--- a/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java	Mon Oct 20 19:20:24 2008 +0100
@@ -61,7 +61,7 @@
             return null;
 
         UnixPath path = (UnixPath)obj;
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path.getPathForSysCalls());
+        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path.getByteArrayForSysCalls());
         try {
             if (gioAvailable) {
                 byte[] type = probeUsingGio(buffer.address());
--- a/src/solaris/classes/sun/nio/fs/LinuxFileStore.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/LinuxFileStore.java	Mon Oct 20 19:20:24 2008 +0100
@@ -25,9 +25,6 @@
 
 package sun.nio.fs;
 
-import java.nio.file.*;
-import java.nio.file.attribute.*;
-import java.nio.channels.*;
 import java.util.*;
 import java.io.IOException;
 
@@ -55,7 +52,7 @@
         // step 1: get realpath
         UnixPath path = null;
         try {
-            byte[] rp = UnixNativeDispatcher.realpath(file().getPathForSysCalls());
+            byte[] rp = UnixNativeDispatcher.realpath(file());
             path = new UnixPath(fs, rp);
         } catch (UnixException x) {
             x.rethrowAsIOException(file());
@@ -66,7 +63,7 @@
         while (parent != null) {
             UnixFileAttributes attrs = null;
             try {
-                attrs = UnixFileAttributes.get(parent.asByteArray(), true);
+                attrs = UnixFileAttributes.get(parent, true);
             } catch (UnixException x) {
                 x.rethrowAsIOException(parent);
             }
--- a/src/solaris/classes/sun/nio/fs/LinuxWatchService.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/LinuxWatchService.java	Mon Oct 20 19:20:24 2008 +0100
@@ -236,7 +236,7 @@
             // check file is directory
             UnixFileAttributes attrs = null;
             try {
-                attrs = UnixFileAttributes.get(dir.getPathForSysCalls(), true);
+                attrs = UnixFileAttributes.get(dir, true);
             } catch (UnixException x) {
                 return x.asIOException(dir);
             }
@@ -248,7 +248,7 @@
             int wd = -1;
             try {
                 NativeBuffer buffer =
-                    NativeBuffers.asNativeBuffer(dir.getPathForSysCalls());
+                    NativeBuffers.asNativeBuffer(dir.getByteArrayForSysCalls());
                 try {
                     wd = inotifyAddWatch(ifd, buffer.address(), mask);
                 } finally {
--- a/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java	Mon Oct 20 19:20:24 2008 +0100
@@ -81,9 +81,9 @@
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             if (checkRead)
-                sm.checkRead(file.getPathForPermissionCheck());
+                file.checkRead();
             if (checkWrite)
-                sm.checkWrite(file.getPathForPermissionCheck());
+                file.checkWrite();
             sm.checkPermission(new RuntimePermission("accessUserInformation"));
         }
     }
@@ -98,22 +98,22 @@
 
             // map UserPrincipal to uid and flags
             UserPrincipal who = ace.principal();
-            if (!(who instanceof UnixUserPrincipal))
+            if (!(who instanceof UnixUserPrincipals))
                 throw new ProviderMismatchException();
-            UnixUserPrincipal user = (UnixUserPrincipal)who;
+            UnixUserPrincipals.User user = (UnixUserPrincipals.User)who;
             int uid;
             if (user.isSpecial()) {
                 uid = -1;
-                if (who.getName().equals(UnixUserPrincipal.SPECIAL_OWNER.getName()))
+                if (who.getName().equals(UnixUserPrincipals.SPECIAL_OWNER.getName()))
                     flags |= ACE_OWNER;
-                else if (who.getName().equals(UnixUserPrincipal.SPECIAL_GROUP.getName()))
+                else if (who.getName().equals(UnixUserPrincipals.SPECIAL_GROUP.getName()))
                     flags |= ACE_GROUP;
-                else if (who.getName().equals(UnixUserPrincipal.SPECIAL_EVERYONE.getName()))
+                else if (who.getName().equals(UnixUserPrincipals.SPECIAL_EVERYONE.getName()))
                     flags |= ACE_EVERYONE;
                 else
                     throw new AssertionError("Unable to map special identifier");
             } else {
-                if (user.isGroup()) {
+                if (user instanceof UnixUserPrincipals.Group) {
                     uid = user.gid();
                     flags |= ACE_IDENTIFIER_GROUP;
                 } else {
@@ -208,22 +208,22 @@
             int type = (int)unsafe.getShort(offset + OFFSETOF_TYPE);
 
             // map uid and flags to UserPrincipal
-            UnixUserPrincipal who = null;
+            UnixUserPrincipals.User who = null;
             if (uid == -1) {
                 if ((flags & ACE_OWNER) > 0)
-                    who = UnixUserPrincipal.SPECIAL_OWNER;
+                    who = UnixUserPrincipals.SPECIAL_OWNER;
                 if ((flags & ACE_GROUP) > 0)
-                    who = UnixUserPrincipal.SPECIAL_GROUP;
+                    who = UnixUserPrincipals.SPECIAL_GROUP;
                 if ((flags & ACE_EVERYONE) > 0)
-                    who = UnixUserPrincipal.SPECIAL_EVERYONE;
+                    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 = UnixUserPrincipal.fromGid(uid);
+                    who = UnixUserPrincipals.fromGid(uid);
                 else
-                    who = UnixUserPrincipal.fromUid(uid);
+                    who = UnixUserPrincipals.fromUid(uid);
             }
 
             AclEntryType aceType = null;
@@ -377,8 +377,8 @@
 
         try {
             UnixFileAttributes attrs =
-                UnixFileAttributes.get(file.getPathForSysCalls(), followLinks);
-            return UnixUserPrincipal.fromUid(attrs.uid());
+                UnixFileAttributes.get(file, followLinks);
+            return UnixUserPrincipals.fromUid(attrs.uid());
         } catch (UnixException x) {
             x.rethrowAsIOException(file);
             return null; // keep compile happy
@@ -389,17 +389,17 @@
     public void setOwner(UserPrincipal owner) throws IOException {
         checkAccess(file, true, false);
 
-        if (!(owner instanceof UnixUserPrincipal))
+        if (!(owner instanceof UnixUserPrincipals.User))
             throw new ProviderMismatchException();
-        if (owner.isGroup())
+        if (owner instanceof UnixUserPrincipals.Group)
             throw new IOException("'owner' parameter is a group");
-        int uid = ((UnixUserPrincipal)owner).uid();
+        int uid = ((UnixUserPrincipals.User)owner).uid();
 
         try {
             if (followLinks) {
-                lchown(file.getPathForSysCalls(), uid, -1);
+                lchown(file, uid, -1);
             } else {
-                chown(file.getPathForSysCalls(), uid, -1);
+                chown(file, uid, -1);
             }
         } catch (UnixException x) {
             x.rethrowAsIOException(file);
--- a/src/solaris/classes/sun/nio/fs/SolarisFileStore.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/SolarisFileStore.java	Mon Oct 20 19:20:24 2008 +0100
@@ -57,7 +57,7 @@
     private boolean xattrEnabled() {
         long res = 0L;
         try {
-            res = pathconf(file().getPathForSysCalls(), _PC_XATTR_ENABLED);
+            res = pathconf(file(), _PC_XATTR_ENABLED);
         } catch (UnixException x) {
             // ignore
         }
--- a/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/SolarisFileSystem.java	Mon Oct 20 19:20:24 2008 +0100
@@ -142,7 +142,8 @@
     Iterable<UnixMountEntry> getMountEntries() {
         ArrayList<UnixMountEntry> entries = new ArrayList<UnixMountEntry>();
         try {
-            long fp = fopen("/etc/mnttab".getBytes(), "r".getBytes());
+            UnixPath mnttab = new UnixPath(this, "/etc/mnttab");
+            long fp = fopen(mnttab, "r");
             try {
                 for (;;) {
                     UnixMountEntry entry = new UnixMountEntry();
@@ -169,17 +170,4 @@
     FileStore getFileStore(UnixMountEntry entry) {
         return new SolarisFileStore(this, entry);
     }
-
-    @Override
-    public UserPrincipal lookupPrincipalByName(String name)
-        throws IOException
-    {
-        if (name.equals(UnixUserPrincipal.SPECIAL_OWNER.getName()))
-            return UnixUserPrincipal.SPECIAL_OWNER;
-        if (name.equals(UnixUserPrincipal.SPECIAL_GROUP.getName()))
-            return UnixUserPrincipal.SPECIAL_GROUP;
-        if (name.equals(UnixUserPrincipal.SPECIAL_EVERYONE.getName()))
-            return UnixUserPrincipal.SPECIAL_EVERYONE;
-        return super.lookupPrincipalByName(name);
-    }
 }
--- a/src/solaris/classes/sun/nio/fs/SolarisWatchService.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/SolarisWatchService.java	Mon Oct 20 19:20:24 2008 +0100
@@ -278,12 +278,11 @@
             }
 
             UnixPath dir = (UnixPath)obj;
-            byte[] path = dir.getPathForSysCalls();
 
             // check file is directory
             UnixFileAttributes attrs = null;
             try {
-                attrs = UnixFileAttributes.get(path, true);
+                attrs = UnixFileAttributes.get(dir, true);
             } catch (UnixException x) {
                 return x.asIOException(dir);
             }
@@ -303,7 +302,7 @@
             // register directory
             long object = 0L;
             try {
-                object = registerImpl(path, (FILE_MODIFIED | FILE_ATTRIB));
+                object = registerImpl(dir, (FILE_MODIFIED | FILE_ATTRIB));
             } catch (UnixException x) {
                 return x.asIOException(dir);
             }
@@ -523,8 +522,8 @@
                 // effective when the file is replaced.
                 boolean removed = true;
                 try {
-                    UnixFileAttributes.get(key.getFileRef().resolve(node.name())
-                        .getPathForSysCalls(), false);
+                    UnixFileAttributes
+                        .get(key.getFileRef().resolve(node.name()), false);
                     removed = false;
                 } catch (UnixException x) { }
 
@@ -573,10 +572,9 @@
                     }
 
                     // register it
-                    byte[] path = ((UnixPath)entry).getPathForSysCalls();
                     long object = 0L;
                     try {
-                        object = registerImpl(path, events);
+                        object = registerImpl((UnixPath)entry, events);
                     } catch (UnixException x) {
                         // can't register so ignore for now.
                         continue;
@@ -642,10 +640,11 @@
          * Returns pointer to fileobj structure that is allocated for
          * the registration.
          */
-        long registerImpl(byte[] path, int events)
+        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,
--- a/src/solaris/classes/sun/nio/fs/UnixChannelFactory.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixChannelFactory.java	Mon Oct 20 19:20:24 2008 +0100
@@ -29,7 +29,6 @@
 import java.nio.channels.*;
 import java.io.FileDescriptor;
 import java.util.Set;
-import static java.nio.file.OpenOption.*;
 
 import sun.nio.ch.FileChannelImpl;
 import sun.nio.ch.ThreadPool;
@@ -51,108 +50,124 @@
     private UnixChannelFactory() {
     }
 
+    /**
+     * Represents the flags from a user-supplied set of open options.
+     */
+    private static class Flags {
+        boolean read;
+        boolean write;
+        boolean append;
+        boolean truncateExisting;
+        boolean noFollowLinks;
+        boolean create;
+        boolean createNew;
+        boolean deleteOnClose;
+        boolean sync;
+        boolean dsync;
+
+        static Flags toFlags(Set<? extends OpenOption> options) {
+            Flags flags = new Flags();
+            for (OpenOption option: options) {
+                if (!(option instanceof StandardOpenOption)) {
+                    if (option == null)
+                        throw new NullPointerException();
+                    throw new UnsupportedOperationException("Unsupported open option");
+                }
+                switch ((StandardOpenOption)option) {
+                    case READ : flags.read = true; break;
+                    case WRITE : flags.write = true; break;
+                    case APPEND : flags.append = true; break;
+                    case NOFOLLOW_LINKS: flags.noFollowLinks = 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 AssertionError("Should not get here");
+                }
+            }
+            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,
-                                      byte[] pathForSysCall,
+                                      UnixPath path,
                                       String pathForPermissionCheck,
                                       Set<? extends OpenOption> options,
                                       int mode)
         throws UnixException
     {
-        boolean reading = false;
-        boolean writing = false;
-        boolean append = false;
-        boolean trunc = false;
+        Flags flags = Flags.toFlags(options);
 
-        // check for invalid flags
-        for (OpenOption flag: options) {
-            if (flag == StandardOpenOption.READ) {
-                reading = true; continue;
+        // default is reading; append => writing
+        if (!flags.read && !flags.write) {
+            if (flags.append) {
+                flags.write = true;
+            } else {
+                flags.read = true;
             }
-            if (flag == StandardOpenOption.WRITE) {
-                writing = true; continue;
-            }
-            if (flag == StandardOpenOption.APPEND) {
-                append = true;
-                writing = true;
-                continue;
-            }
-            if (flag == StandardOpenOption.TRUNCATE_EXISTING) {
-                trunc = true; continue;
-            }
-            if (flag == null)
-                throw new NullPointerException();
-            if (!(flag instanceof StandardOpenOption))
-                throw new UnsupportedOperationException("Unsupported open option");
         }
 
-        // default is reading
-        if (!reading && !writing) {
-            reading = true;
-        }
-
-        // check for invalid combinations
-        if (reading && append)
+        // validation
+        if (flags.read && flags.append)
             throw new IllegalArgumentException("READ + APPEND not allowed");
-        if (append && trunc)
+        if (flags.append && flags.truncateExisting)
             throw new IllegalArgumentException("APPEND + TRUNCATE_EXISTING not allowed");
 
-        FileDescriptor fdObj = open(dfd, pathForSysCall, pathForPermissionCheck,
-            reading, writing, append, options, mode);
-        return FileChannelImpl.open(fdObj, reading, writing, null);
+        FileDescriptor fdObj = open(dfd, path, pathForPermissionCheck, flags, mode);
+        return FileChannelImpl.open(fdObj, flags.read, flags.write, null);
     }
 
-    static FileChannel newFileChannel(byte[] pathForSysCall,
-                                      String pathForPermissionCheck,
+    /**
+     * Constructs a file channel by opening the given file.
+     */
+    static FileChannel newFileChannel(UnixPath path,
                                       Set<? extends OpenOption> options,
                                       int mode)
         throws UnixException
     {
-        return newFileChannel(-1, pathForSysCall, pathForPermissionCheck,
-            options, mode);
+        return newFileChannel(-1, path, null, options, mode);
     }
 
-    static AsynchronousFileChannel newAsynchronousFileChannel(byte[] pathForSysCall,
-                                                              String pathForPermissionCheck,
+    /**
+     * Constructs an asynchronous file channel by opening the given file.
+     */
+    static AsynchronousFileChannel newAsynchronousFileChannel(UnixPath path,
                                                               Set<? extends OpenOption> options,
                                                               int mode,
                                                               ThreadPool pool)
         throws UnixException
     {
-        boolean reading = false;
-        boolean writing = false;
+        Flags flags = Flags.toFlags(options);
 
-        // check for invalid flags
-        for (OpenOption flag: options) {
-            if (flag == StandardOpenOption.READ) {
-                reading = true; continue;
-            }
-            if (flag == StandardOpenOption.WRITE) {
-                writing = true; continue;
-            }
-            if (flag == null)
-                throw new NullPointerException();
-            if (!(flag instanceof StandardOpenOption))
-                throw new UnsupportedOperationException("Unsupported open option");
-            if (flag == StandardOpenOption.APPEND)
-                throw new UnsupportedOperationException("'APPEND' not supported");
+        // default is reading
+        if (!flags.read && !flags.write) {
+            flags.read = true;
         }
 
-        // reading or writing not set so default to reading
-        if (!reading && !writing) {
-            reading = true;
-        }
+        // validation
+        if (flags.append)
+            throw new UnsupportedOperationException("APPEND not allowed");
 
         // for now assume that direct/raw I/O is not supported so return
         // "portable" AsynchronousFileChannel based on underlying file channel
-        FileDescriptor fdObj = open(-1, pathForSysCall, pathForPermissionCheck,
-            reading, writing, false, options, mode);
-        return SimpleAsynchronousFileChannelImpl.open(fdObj, reading, writing, pool);
+        FileDescriptor fdObj = open(-1, path, null, flags, mode);
+        return SimpleAsynchronousFileChannelImpl.open(fdObj, flags.read, flags.write, pool);
     }
 
     /**
@@ -160,33 +175,29 @@
      * encapsulating the handle to the open file.
      */
     static FileDescriptor open(int dfd,
-                               byte[] pathForSysCall,
+                               UnixPath path,
                                String pathForPermissionCheck,
-                               boolean reading,
-                               boolean writing,
-                               boolean append,
-                               Set<? extends OpenOption> options,
+                               Flags flags,
                                int mode)
         throws UnixException
     {
-        // will be true if CREATE_NEW specified
-        boolean createNew = false;
-
         // map to oflags
         int oflags;
-        if (reading && writing) {
+        if (flags.read && flags.write) {
             oflags = O_RDWR;
         } else {
-            oflags = (writing) ? O_WRONLY : O_RDONLY;
+            oflags = (flags.write) ? O_WRONLY : O_RDONLY;
         }
-        if (writing) {
-            if (options.contains(StandardOpenOption.TRUNCATE_EXISTING))
+        if (flags.write) {
+            if (flags.truncateExisting)
                 oflags |= O_TRUNC;
-            if (append)
+            if (flags.append)
                 oflags |= O_APPEND;
 
             // create flags
-            if (options.contains(StandardOpenOption.CREATE_NEW)) {
+            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 ||
@@ -195,49 +206,47 @@
                     throw new UnixException(EEXIST);
                 }
                 oflags |= (O_CREAT | O_EXCL);
-                createNew = true;
             } else {
-                if (options.contains(StandardOpenOption.CREATE))
+                if (flags.create)
                     oflags |= O_CREAT;
             }
         }
 
-        // file should be immediatley deleted
-        boolean deleteOnClose = options.contains(StandardOpenOption.DELETE_ON_CLOSE);
-
         // follow links by default
         boolean followLinks = true;
-        if (!createNew &&
-            (options.contains(StandardOpenOption.NOFOLLOW_LINKS) || deleteOnClose))
-        {
+        if (!flags.createNew && (flags.noFollowLinks || flags.deleteOnClose)) {
             followLinks = false;
             oflags |= O_NOFOLLOW;
         }
 
-        if (options.contains(StandardOpenOption.DSYNC)) oflags |= O_DSYNC;
-        if (options.contains(StandardOpenOption.SYNC)) oflags |= O_SYNC;
+        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 (reading)
+            if (pathForPermissionCheck == null)
+                pathForPermissionCheck = path.getPathForPermissionCheck();
+            if (flags.read)
                 sm.checkRead(pathForPermissionCheck);
-            if (writing)
+            if (flags.write)
                 sm.checkWrite(pathForPermissionCheck);
-            if (deleteOnClose)
+            if (flags.deleteOnClose)
                 sm.checkDelete(pathForPermissionCheck);
         }
 
         int fd;
         try {
             if (dfd >= 0) {
-                fd = openat(dfd, pathForSysCall, oflags, mode);
+                fd = openat(dfd, path.asByteArray(), oflags, mode);
             } else {
-                fd = UnixNativeDispatcher.open(pathForSysCall, oflags, mode);
+                fd = UnixNativeDispatcher.open(path, oflags, mode);
             }
         } catch (UnixException x) {
             // Linux error can be EISDIR or EEXIST when file exists
-            if (createNew && (x.errno() == EISDIR)) {
+            if (flags.createNew && (x.errno() == EISDIR)) {
                 x.setError(EEXIST);
             }
 
@@ -252,12 +261,12 @@
         // 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 (deleteOnClose) {
+        if (flags.deleteOnClose) {
             try {
                 if (dfd >= 0) {
-                    unlinkat(dfd, pathForSysCall, 0);
+                    unlinkat(dfd, path.asByteArray(), 0);
                 } else {
-                    unlink(pathForSysCall);
+                    unlink(path);
                 }
             } catch (UnixException ignore) {
                 // best-effort
--- a/src/solaris/classes/sun/nio/fs/UnixCopyFile.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixCopyFile.java	Mon Oct 20 19:20:24 2008 +0100
@@ -53,9 +53,8 @@
                                       boolean failIfUnableToCopyNonPosix)
         throws IOException
     {
-        byte[] path = target.getPathForSysCalls();
         try {
-            mkdir(path, attrs.mode());
+            mkdir(target, attrs.mode());
         } catch (UnixException x) {
             x.rethrowAsIOException(target);
         }
@@ -68,11 +67,11 @@
         // directory for which we don't have read access).
         int dfd = -1;
         try {
-            dfd = open(path, O_RDONLY, 0);
+            dfd = open(target, O_RDONLY, 0);
         } catch (UnixException x) {
             // access to target directory required to copy named attributes
             if (copyNonPosixAttributes && failIfUnableToCopyNonPosix) {
-                try { rmdir(path); } catch (UnixException ignore) { }
+                try { rmdir(target); } catch (UnixException ignore) { }
                 x.rethrowAsIOException(target);
             }
         }
@@ -86,8 +85,8 @@
                         fchown(dfd, attrs.uid(), attrs.gid());
                         fchmod(dfd, attrs.mode());
                     } else {
-                        chown(path, attrs.uid(), attrs.gid());
-                        chmod(path, attrs.mode());
+                        chown(target, attrs.uid(), attrs.gid());
+                        chmod(target, attrs.mode());
                     }
                 } catch (UnixException x) {
                     // unable to set owner/group
@@ -99,7 +98,7 @@
             if (copyNonPosixAttributes && (dfd >= 0)) {
                 int sfd = -1;
                 try {
-                    sfd = open(source.getPathForSysCalls(), O_RDONLY, 0);
+                    sfd = open(source, O_RDONLY, 0);
                 } catch (UnixException x) {
                     if (failIfUnableToCopyNonPosix)
                         x.rethrowAsIOException(source);
@@ -116,7 +115,7 @@
                         futimes(dfd, attrs.lastAccessTime(),
                             attrs.lastModifiedTime());
                     } else {
-                        utimes(path, attrs.lastAccessTime(),
+                        utimes(target, attrs.lastAccessTime(),
                             attrs.lastModifiedTime());
                     }
                 } catch (UnixException x) {
@@ -131,7 +130,7 @@
                 close(dfd);
             if (!done) {
                 // rollback
-                try { rmdir(path); } catch (UnixException ignore) { }
+                try { rmdir(target); } catch (UnixException ignore) { }
             }
         }
     }
@@ -150,7 +149,7 @@
     {
         int fi = -1;
         try {
-            fi = open(source.getPathForSysCalls(), O_RDONLY, 0);
+            fi = open(source, O_RDONLY, 0);
         } catch (UnixException x) {
             x.rethrowAsIOException(source);
         }
@@ -159,7 +158,7 @@
             // open new file
             int fo = -1;
             try {
-                fo = open(target.getPathForSysCalls(),
+                fo = open(target,
                            (O_WRONLY |
                             O_CREAT |
                             O_TRUNC),
@@ -207,7 +206,7 @@
                 // copy of file or attributes failed so rollback
                 if (!complete) {
                     try {
-                        unlink(target.getPathForSysCalls());
+                        unlink(target);
                     } catch (UnixException ignore) { }
                 }
             }
@@ -225,17 +224,16 @@
     {
         byte[] linktarget = null;
         try {
-            linktarget = readlink(source.getPathForSysCalls());
+            linktarget = readlink(source);
         } catch (UnixException x) {
             x.rethrowAsIOException(source);
         }
-        byte[] path = target.getPathForSysCalls();
         try {
-            symlink(linktarget, path);
+            symlink(linktarget, target);
 
             if (copyOwner) {
                 try {
-                    lchown(path, attrs.uid(), attrs.gid());
+                    lchown(target, attrs.uid(), attrs.gid());
                 } catch (UnixException x) {
                     // ignore since link attributes not required to be copied
                 }
@@ -255,9 +253,8 @@
                                     boolean failIfUnableToCopyPosix)
         throws IOException
     {
-        byte[] path = target.getPathForSysCalls();
         try {
-            mknod(path, attrs.mode(), attrs.rdev());
+            mknod(target, attrs.mode(), attrs.rdev());
         } catch (UnixException x) {
             x.rethrowAsIOException(target);
         }
@@ -265,8 +262,8 @@
         try {
             if (copyPosixAttributes) {
                 try {
-                    chown(path, attrs.uid(), attrs.gid());
-                    chmod(path, attrs.mode());
+                    chown(target, attrs.uid(), attrs.gid());
+                    chmod(target, attrs.mode());
                 } catch (UnixException x) {
                     if (failIfUnableToCopyPosix)
                         x.rethrowAsIOException(target);
@@ -274,7 +271,7 @@
             }
             if (copyBasicAttributes) {
                 try {
-                    utimes(path, attrs.lastAccessTime(), attrs.lastModifiedTime());
+                    utimes(target, attrs.lastAccessTime(), attrs.lastModifiedTime());
                 } catch (UnixException x) {
                     if (failIfUnableToCopyBasic)
                         x.rethrowAsIOException(target);
@@ -283,7 +280,7 @@
             done = true;
         } finally {
             if (!done) {
-                try { unlink(path); } catch (UnixException ignore) { }
+                try { unlink(target); } catch (UnixException ignore) { }
             }
         }
     }
@@ -319,7 +316,7 @@
         // handle atomic rename case
         if (atomicMove) {
             try {
-                rename(source.getPathForSysCalls(), target.getPathForSysCalls());
+                rename(source, target);
             } catch (UnixException x) {
                 if (x.errno() == EXDEV) {
                     throw new AtomicMoveNotSupportedException(
@@ -338,14 +335,14 @@
 
         // get attributes of source file (don't follow links)
         try {
-            sourceAttrs = UnixFileAttributes.get(source.getPathForSysCalls(), false);
+            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.getPathForSysCalls(), false);
+            targetAttrs = UnixFileAttributes.get(target, false);
         } catch (UnixException x) {
             // ignore
         }
@@ -366,9 +363,9 @@
             // attempt to delete target
             try {
                 if (targetAttrs.isDirectory()) {
-                    rmdir(target.getPathForSysCalls());
+                    rmdir(target);
                 } else {
-                    unlink(target.getPathForSysCalls());
+                    unlink(target);
                 }
             } catch (UnixException x) {
                 // target is non-empty directory that can't be replaced.
@@ -386,7 +383,7 @@
 
         // first try rename
         try {
-            rename(source.getPathForSysCalls(), target.getPathForSysCalls());
+            rename(source, target);
             return;
         } catch (UnixException x) {
             if (x.errno() != EXDEV && x.errno() != EISDIR) {
@@ -418,18 +415,18 @@
         // delete source
         try {
             if (sourceAttrs.isDirectory()) {
-                rmdir(source.getPathForSysCalls());
+                rmdir(source);
             } else {
-                unlink(source.getPathForSysCalls());
+                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.getPathForSysCalls());
+                    rmdir(target);
                 } else {
-                    unlink(target.getPathForSysCalls());
+                    unlink(target);
                 }
             } catch (UnixException ignore) { }
 
@@ -491,8 +488,7 @@
 
         // get attributes of source file
         try {
-            sourceAttrs = UnixFileAttributes
-                .get(source.getPathForSysCalls(), followLinks);
+            sourceAttrs = UnixFileAttributes.get(source, followLinks);
         } catch (UnixException x) {
             x.rethrowAsIOException(source);
         }
@@ -504,8 +500,7 @@
 
         // get attributes of target file (don't follow links)
         try {
-            targetAttrs = UnixFileAttributes
-                .get(target.getPathForSysCalls(), false);
+            targetAttrs = UnixFileAttributes.get(target, false);
         } catch (UnixException x) {
             // ignore
         }
@@ -523,9 +518,9 @@
                     target.getPathForExecptionMessage());
             try {
                 if (targetAttrs.isDirectory()) {
-                    rmdir(target.getPathForSysCalls());
+                    rmdir(target);
                 } else {
-                    unlink(target.getPathForSysCalls());
+                    unlink(target);
                 }
             } catch (UnixException x) {
                 // target is non-empty directory that can't be replaced.
--- a/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java	Mon Oct 20 19:20:24 2008 +0100
@@ -49,7 +49,7 @@
             file.checkRead();
             try {
                  UnixFileAttributes attrs =
-                     UnixFileAttributes.get(file.getPathForSysCalls(), followLinks);
+                     UnixFileAttributes.get(file, followLinks);
                  return attrs.asBasicFileAttributes();
             } catch (UnixException x) {
                 x.rethrowAsIOException(file);
@@ -134,7 +134,7 @@
         final void checkReadExtended() {
             SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
-                sm.checkRead(file.getPathForPermissionCheck());
+                file.checkRead();
                 sm.checkPermission(new RuntimePermission("accessUserInformation"));
             }
         }
@@ -142,7 +142,7 @@
         final void checkWriteExtended() {
             SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
-                sm.checkWrite(file.getPathForPermissionCheck());
+                file.checkWrite();
                 sm.checkPermission(new RuntimePermission("accessUserInformation"));
             }
         }
@@ -177,7 +177,7 @@
                 return;
             }
             if (attribute.equals(GROUP_NAME)) {
-                setGroup((UserPrincipal)value);
+                setGroup((GroupPrincipal)value);
                 return;
             }
             super.setAttribute(attribute, value);
@@ -213,7 +213,7 @@
         public UnixFileAttributes readAttributes() throws IOException {
             checkReadExtended();
             try {
-                 return UnixFileAttributes.get(file.getPathForSysCalls(), followLinks);
+                 return UnixFileAttributes.get(file, followLinks);
             } catch (UnixException x) {
                 x.rethrowAsIOException(file);
                 return null;    // keep compiler happy
@@ -225,7 +225,7 @@
             checkWriteExtended();
             try {
                 if (followLinks) {
-                    chmod(file.getPathForSysCalls(), mode);
+                    chmod(file, mode);
                 } else {
                     int fd = file.openForAttributeAccess(false);
                     try {
@@ -244,9 +244,9 @@
             checkWriteExtended();
             try {
                 if (followLinks) {
-                    chown(file.getPathForSysCalls(), uid, gid);
+                    chown(file, uid, gid);
                 } else {
-                    lchown(file.getPathForSysCalls(), uid, gid);
+                    lchown(file, uid, gid);
                 }
             } catch (UnixException x) {
                 x.rethrowAsIOException(file);
@@ -264,23 +264,30 @@
         public void setOwner(UserPrincipal owner)
             throws IOException
         {
-            if (owner.isGroup())
-                throw new IllegalArgumentException("'owner' parameter can't be a group");
-            if (!(owner instanceof UnixUserPrincipal))
+            if (owner == null)
+                throw new NullPointerException("'owner' is null");
+            if (!(owner instanceof UnixUserPrincipals.User))
                 throw new ProviderMismatchException();
-            int uid = ((UnixUserPrincipal)owner).uid();
+            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(UserPrincipal group)
+        public UserPrincipal getOwner() throws IOException {
+            return readAttributes().owner();
+        }
+
+        @Override
+        public void setGroup(GroupPrincipal group)
             throws IOException
         {
-            if (!group.isGroup())
-                throw new IllegalArgumentException("'group' parameter must be group");
-            if (!(group instanceof UnixUserPrincipal))
+            if (group == null)
+                throw new NullPointerException("'owner' is null");
+            if (!(group instanceof UnixUserPrincipals.Group))
                 throw new ProviderMismatchException();
-            int gid = ((UnixUserPrincipal)group).gid();
+            int gid = ((UnixUserPrincipals.Group)group).gid();
             setOwners(-1, gid);
         }
     }
--- a/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixFileAttributes.java	Mon Oct 20 19:20:24 2008 +0100
@@ -51,14 +51,14 @@
 
     // created lazily
     private volatile UserPrincipal owner;
-    private volatile UserPrincipal group;
+    private volatile GroupPrincipal group;
     private volatile UnixFileKey key;
 
     private UnixFileAttributes() {
     }
 
     // get the UnixFileAttributes for a given file
-    static UnixFileAttributes get(byte[] path, boolean followLinks)
+    static UnixFileAttributes get(UnixPath path, boolean followLinks)
         throws UnixException
     {
         UnixFileAttributes attrs = new UnixFileAttributes();
@@ -78,12 +78,12 @@
     }
 
     // get the UnixFileAttributes for a given file, relative to open directory
-    static UnixFileAttributes get(int dfd, byte[] path, boolean followLinks)
+    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, flag, attrs);
+        UnixNativeDispatcher.fstatat(dfd, path.asByteArray(), flag, attrs);
         return attrs;
     }
 
@@ -178,7 +178,7 @@
         if (owner == null) {
             synchronized (this) {
                 if (owner == null) {
-                    owner = UnixUserPrincipal.fromUid(st_uid);
+                    owner = UnixUserPrincipals.fromUid(st_uid);
                 }
             }
         }
@@ -186,11 +186,11 @@
     }
 
     @Override
-    public UserPrincipal group() {
+    public GroupPrincipal group() {
         if (group == null) {
             synchronized (this) {
                 if (group == null) {
-                    group = UnixUserPrincipal.fromGid(st_gid);
+                    group = UnixUserPrincipals.fromGid(st_gid);
                 }
             }
         }
--- a/src/solaris/classes/sun/nio/fs/UnixFileStore.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixFileStore.java	Mon Oct 20 19:20:24 2008 +0100
@@ -53,7 +53,7 @@
         // need device ID
         long devID = 0;
         try {
-            devID = UnixFileAttributes.get(file.getPathForSysCalls(), true).dev();
+            devID = UnixFileAttributes.get(file, true).dev();
         } catch (UnixException x) {
             x.rethrowAsIOException(file);
         }
@@ -184,12 +184,12 @@
 
             SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
-                sm.checkRead(file.getPathForPermissionCheck());
+                file.checkRead();
                 sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));
             }
             final UnixFileStoreAttributes attrs;
             try {
-                attrs = UnixFileStoreAttributes.get(file.getPathForSysCalls());
+                attrs = UnixFileStoreAttributes.get(file);
             } catch (UnixException x) {
                 x.rethrowAsIOException(file);
                 return null;    // keep compile happy
--- a/src/solaris/classes/sun/nio/fs/UnixFileStoreAttributes.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixFileStoreAttributes.java	Mon Oct 20 19:20:24 2008 +0100
@@ -34,7 +34,7 @@
     private UnixFileStoreAttributes() {
     }
 
-    static UnixFileStoreAttributes get(byte[] path) throws UnixException {
+    static UnixFileStoreAttributes get(UnixPath path) throws UnixException {
         UnixFileStoreAttributes attrs = new UnixFileStoreAttributes();
         UnixNativeDispatcher.statvfs(path, attrs);
         return attrs;
--- a/src/solaris/classes/sun/nio/fs/UnixFileSystem.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixFileSystem.java	Mon Oct 20 19:20:24 2008 +0100
@@ -40,12 +40,12 @@
  */
 
 abstract class UnixFileSystem
-    extends FileSystem implements UserPrincipalLookupService
+    extends FileSystem
 {
     private final UnixFileSystemProvider provider;
     private final byte[] defaultDirectory;
+    private final boolean needToResolveAgainstDefaultDirectory;
     private final UnixPath rootDirectory;
-    private final boolean chdirAllowed;
 
     // package-private
     UnixFileSystem(UnixFileSystemProvider provider, String dir) {
@@ -54,12 +54,29 @@
         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.
+        PrivilegedAction<Boolean> pa = new GetBooleanAction("sun.nio.fs.chdirAllowed");
+        if (AccessController.doPrivileged(pa).booleanValue()) {
+            this.needToResolveAgainstDefaultDirectory = true;
+        } else {
+            byte[] cwd = UnixNativeDispatcher.getcwd();
+            boolean defaultIsCwd = (cwd.length == defaultDirectory.length);
+            if (defaultIsCwd) {
+                for (int i=0; i<cwd.length; i++) {
+                    if (cwd[i] != defaultDirectory[i]) {
+                        defaultIsCwd = false;
+                        break;
+                    }
+                }
+            }
+            this.needToResolveAgainstDefaultDirectory = !defaultIsCwd;
+        }
+
+        // the root directory
         this.rootDirectory = new UnixPath(this, "/");
-
-        // system property indicates if process-wide chdir is allowed. If so
-        // then access to the file system is via absolute paths.
-        PrivilegedAction<Boolean> pa = new GetBooleanAction("sun.nio.fs.chdirAllowed");
-        this.chdirAllowed = AccessController.doPrivileged(pa).booleanValue();
     }
 
     // package-private
@@ -67,14 +84,14 @@
         return defaultDirectory;
     }
 
+    boolean needToResolveAgainstDefaultDirectory() {
+        return needToResolveAgainstDefaultDirectory;
+    }
+
     UnixPath rootDirectory() {
         return rootDirectory;
     }
 
-    boolean chdirAllowed() {
-        return chdirAllowed;
-    }
-
     boolean isSolaris() {
         return false;
     }
@@ -309,18 +326,23 @@
 
     @Override
     public final UserPrincipalLookupService getUserPrincipalLookupService() {
-        return this;
+        return theLookupService;
     }
 
-    @Override
-    public UserPrincipal lookupPrincipalByName(String name) throws IOException {
-        return UnixUserPrincipal.lookupPrincipalByName(name);
-    }
+    private static final UserPrincipalLookupService theLookupService =
+        new UserPrincipalLookupService() {
+            @Override
+            public UserPrincipal lookupPrincipalByName(String name)
+                throws IOException
+            {
+                return UnixUserPrincipals.lookupUser(name);
+            }
 
-    @Override
-    public UserPrincipal lookupPrincipalByGroupName(String group)
-        throws IOException
-    {
-        return UnixUserPrincipal.lookupPrincipalByGroupName(group);
-    }
+            @Override
+            public GroupPrincipal lookupPrincipalByGroupName(String group)
+                throws IOException
+            {
+                return UnixUserPrincipals.lookupGroup(group);
+            }
+        };
 }
--- a/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixFileSystemProvider.java	Mon Oct 20 19:20:24 2008 +0100
@@ -112,11 +112,7 @@
         int mode = UnixFileModeAttribute
             .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
         try {
-            return UnixChannelFactory
-                .newFileChannel(file.getPathForSysCalls(),
-                                file.getPathForPermissionCheck(),
-                                options,
-                                mode);
+            return UnixChannelFactory.newFileChannel(file, options, mode);
         } catch (UnixException x) {
             x.rethrowAsIOException(file);
             return null;
@@ -136,11 +132,7 @@
             ThreadPool.create(ThreadPoolType.CACHED, executor, 0);
         try {
             return UnixChannelFactory
-                .newAsynchronousFileChannel(file.getPathForSysCalls(),
-                                            file.getPathForPermissionCheck(),
-                                            options,
-                                            mode,
-                                            pool);
+                .newAsynchronousFileChannel(file, options, mode, pool);
         } catch (UnixException x) {
             x.rethrowAsIOException(file);
             return null;
--- a/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixNativeDispatcher.java	Mon Oct 20 19:20:24 2008 +0100
@@ -35,6 +35,28 @@
 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)
      */
@@ -43,8 +65,8 @@
     /**
      * int open(const char* path, int oflag, mode_t mode)
      */
-    static int open(byte[] path, int flags, int mode) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static int open(UnixPath path, int flags, int mode) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             return open0(buffer.address(), flags, mode);
         } finally {
@@ -76,9 +98,9 @@
     /**
      * FILE* fopen(const char *filename, const char* mode);
      */
-    static long fopen(byte[] filename, byte[] mode) throws UnixException {
-        NativeBuffer pathBuffer = NativeBuffers.asNativeBuffer(filename);
-        NativeBuffer modeBuffer = NativeBuffers.asNativeBuffer(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 {
@@ -97,9 +119,9 @@
     /**
      * link(const char* existing, const char* new)
      */
-    static void link(byte[] existing, byte[] newfile) throws UnixException {
-        NativeBuffer existingBuffer = NativeBuffers.asNativeBuffer(existing);
-        NativeBuffer newBuffer = NativeBuffers.asNativeBuffer(newfile);
+    static void link(UnixPath existing, UnixPath newfile) throws UnixException {
+        NativeBuffer existingBuffer = copyToNativeBuffer(existing);
+        NativeBuffer newBuffer = copyToNativeBuffer(newfile);
         try {
             link0(existingBuffer.address(), newBuffer.address());
         } finally {
@@ -113,8 +135,8 @@
     /**
      * unlink(const char* path)
      */
-    static void unlink(byte[] path) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static void unlink(UnixPath path) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             unlink0(buffer.address());
         } finally {
@@ -140,8 +162,8 @@
     /**
      * mknod(const char* path, mode_t mode, dev_t dev)
      */
-    static void mknod(byte[] path, int mode, long dev) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static void mknod(UnixPath path, int mode, long dev) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             mknod0(buffer.address(), mode, dev);
         } finally {
@@ -154,9 +176,9 @@
     /**
      *  rename(const char* old, const char* new)
      */
-    static void rename(byte[] from, byte[] to) throws UnixException {
-        NativeBuffer fromBuffer = NativeBuffers.asNativeBuffer(from);
-        NativeBuffer toBuffer = NativeBuffers.asNativeBuffer(to);
+    static void rename(UnixPath from, UnixPath to) throws UnixException {
+        NativeBuffer fromBuffer = copyToNativeBuffer(from);
+        NativeBuffer toBuffer = copyToNativeBuffer(to);
         try {
             rename0(fromBuffer.address(), toBuffer.address());
         } finally {
@@ -186,8 +208,8 @@
     /**
      * mkdir(const char* path, mode_t mode)
      */
-    static void mkdir(byte[] path, int mode) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static void mkdir(UnixPath path, int mode) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             mkdir0(buffer.address(), mode);
         } finally {
@@ -199,8 +221,8 @@
     /**
      * rmdir(const char* path)
      */
-    static void rmdir(byte[] path) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static void rmdir(UnixPath path) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             rmdir0(buffer.address());
         } finally {
@@ -214,8 +236,8 @@
      *
      * @return  link target
      */
-    static byte[] readlink(byte[] path) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static byte[] readlink(UnixPath path) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             return readlink0(buffer.address());
         } finally {
@@ -229,8 +251,8 @@
      *
      * @return  resolved path
      */
-    static byte[] realpath(byte[] path) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static byte[] realpath(UnixPath path) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             return realpath0(buffer.address());
         } finally {
@@ -242,9 +264,9 @@
     /**
      * symlink(const char* name1, const char* name2)
      */
-    static void symlink(byte[] name1, byte[] name2) throws UnixException {
+    static void symlink(byte[] name1, UnixPath name2) throws UnixException {
         NativeBuffer targetBuffer = NativeBuffers.asNativeBuffer(name1);
-        NativeBuffer linkBuffer = NativeBuffers.asNativeBuffer(name2);
+        NativeBuffer linkBuffer = copyToNativeBuffer(name2);
         try {
             symlink0(targetBuffer.address(), linkBuffer.address());
         } finally {
@@ -258,8 +280,8 @@
     /**
      * stat(const char* path, struct stat* buf)
      */
-    static void stat(byte[] path, UnixFileAttributes attrs) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static void stat(UnixPath path, UnixFileAttributes attrs) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             stat0(buffer.address(), attrs);
         } finally {
@@ -272,8 +294,8 @@
     /**
      * lstat(const char* path, struct stat* buf)
      */
-    static void lstat(byte[] path, UnixFileAttributes attrs) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static void lstat(UnixPath path, UnixFileAttributes attrs) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             lstat0(buffer.address(), attrs);
         } finally {
@@ -307,8 +329,8 @@
     /**
      * chown(const char* path, uid_t owner, gid_t group)
      */
-    static void chown(byte[] path, int uid, int gid) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static void chown(UnixPath path, int uid, int gid) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             chown0(buffer.address(), uid, gid);
         } finally {
@@ -321,8 +343,8 @@
     /**
      * lchown(const char* path, uid_t owner, gid_t group)
      */
-    static void lchown(byte[] path, int uid, int gid) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static void lchown(UnixPath path, int uid, int gid) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             lchown0(buffer.address(), uid, gid);
         } finally {
@@ -340,8 +362,8 @@
     /**
      * chmod(const char* path, mode_t mode)
      */
-    static void chmod(byte[] path, int mode) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static void chmod(UnixPath path, int mode) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             chmod0(buffer.address(), mode);
         } finally {
@@ -359,10 +381,10 @@
     /**
      * utimes(conar char* path, const struct timeval times[2])
      */
-    static void utimes(byte[] path, long times0, long times1)
+    static void utimes(UnixPath path, long times0, long times1)
         throws UnixException
     {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             utimes0(buffer.address(), times0, times1);
         } finally {
@@ -380,8 +402,8 @@
     /**
      * DIR *opendir(const char* dirname)
      */
-    static long opendir(byte[] path) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static long opendir(UnixPath path) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             return opendir0(buffer.address());
         } finally {
@@ -421,8 +443,8 @@
     /**
      * access(const char* path, int amode);
      */
-    static void access(byte[] path, int amode) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static void access(UnixPath path, int amode) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             access0(buffer.address(), amode);
         } finally {
@@ -450,8 +472,8 @@
      *
      * @return  passwd->pw_uid
      */
-    static int getpwnam(byte[] name) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(name);
+    static int getpwnam(String name) throws UnixException {
+        NativeBuffer buffer = NativeBuffers.asNativeBuffer(name.getBytes());
         try {
             return getpwnam0(buffer.address());
         } finally {
@@ -465,8 +487,8 @@
      *
      * @return  group->gr_name
      */
-    static int getgrnam(byte[] name) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(name);
+    static int getgrnam(String name) throws UnixException {
+        NativeBuffer buffer = NativeBuffers.asNativeBuffer(name.getBytes());
         try {
             return getgrnam0(buffer.address());
         } finally {
@@ -483,10 +505,10 @@
     /**
      * statvfs(const char* path, struct statvfs *buf)
      */
-    static void statvfs(byte[] path, UnixFileStoreAttributes attrs)
+    static void statvfs(UnixPath path, UnixFileStoreAttributes attrs)
         throws UnixException
     {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             statvfs0(buffer.address(), attrs);
         } finally {
@@ -499,8 +521,8 @@
     /**
      * long int pathconf(const char *path, int name);
      */
-    static long pathconf(byte[] path, int name) throws UnixException {
-        NativeBuffer buffer = NativeBuffers.asNativeBuffer(path);
+    static long pathconf(UnixPath path, int name) throws UnixException {
+        NativeBuffer buffer = copyToNativeBuffer(path);
         try {
             return pathconf0(buffer.address(), name);
         } finally {
--- a/src/solaris/classes/sun/nio/fs/UnixPath.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixPath.java	Mon Oct 20 19:20:24 2008 +0100
@@ -49,52 +49,30 @@
     private final UnixFileSystem fs;
 
     // internal representation
-    // TBD: Test performance against storing the path as an array of byte[]
-    // where the components can be shared between Path instances.
     private final byte[] path;
 
-    // path used in system calls. If process-wide chidr allowed or MVM then
-    // all access to file system is via absolute paths (relative paths are
-    // always resolved against file system's default directory)
-    private final byte[] pathForSysCalls;
-
     // String representation (created lazily)
     private volatile String stringValue;
 
-    // cached hashcode (created lazily)
+    // 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;
 
-    // cached file permissions (created lazily)
+    // file permissions (created lazily)
     private volatile FilePermission[] perms;
 
-
-    UnixPath(UnixFileSystem fs, String input) {
-        this.fs = fs;
-        // removes redundant slashes and checks for invalid characters
-        this.path = normalizeAndCheck(input).getBytes();
-
-        // resolve against default directory if chdir allowed
-        if (getFileSystem().chdirAllowed()) {
-            this.pathForSysCalls = resolve(getFileSystem().defaultDirectory(), path);
-        } else {
-            this.pathForSysCalls = path;
-        }
-    }
-
     UnixPath(UnixFileSystem fs, byte[] path) {
         this.fs = fs;
         this.path = path;
+    }
 
-        // resolve against default directory if chdir allowed
-        if (getFileSystem().chdirAllowed()) {
-            this.pathForSysCalls = resolve(getFileSystem().defaultDirectory(), path);
-        } else {
-            this.pathForSysCalls = path;
-        }
+    UnixPath(UnixFileSystem fs, String input) {
+        // removes redundant slashes and checks for invalid characters
+        this(fs, normalizeAndCheck(input).getBytes());
     }
+
     // package-private
     // removes redundant slashes and check input for invalid characters
     static String normalizeAndCheck(String input) {
@@ -141,6 +119,31 @@
         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)
@@ -690,29 +693,13 @@
 
     // -- file operations --
 
-    // use this message when throwing exceptions
-    String getPathForExecptionMessage() {
-        return toString();
-    }
-
-    // use this path for permission checks
-    String getPathForPermissionCheck() {
-        // FIXME - this should be cached
-        return new String(pathForSysCalls);
-    }
-
-    // use this path when making system/library calls
-    byte[] getPathForSysCalls() {
-        return pathForSysCalls;
-    }
-
     // package-private
     int openForAttributeAccess(boolean followLinks) throws IOException {
         int flags = O_RDONLY;
         if (!followLinks)
             flags |= O_NOFOLLOW;
         try {
-            return open(getPathForSysCalls(), flags, 0);
+            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)
@@ -727,40 +714,43 @@
         }
     }
 
-    private void createPermissions() {
-        synchronized (this) {
-            if (perms == null) {
-                FilePermission[] p = new FilePermission[2];
-                p[0] = new FilePermission(getPathForPermissionCheck(),
-                    SecurityConstants.FILE_READ_ACTION);
-                p[1] = new FilePermission(getPathForPermissionCheck(),
-                    SecurityConstants.FILE_WRITE_ACTION);
-                perms = p;
+    // 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() {
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            if (perms == null)
-                createPermissions();
-            sm.checkPermission(perms[0]);
-        }
+        checkReadOrWrite(true);
     }
 
     void checkWrite() {
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            if (perms == null)
-                createPermissions();
-            sm.checkPermission(perms[1]);
-        }
+        checkReadOrWrite(false);
     }
 
     void checkDelete() {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
+            // permission not cached
             sm.checkDelete(getPathForPermissionCheck());
         }
     }
@@ -774,37 +764,29 @@
     }
 
     @Override
-    public void checkAccess(Access first, Access... rest) throws IOException {
+    public void checkAccess(AccessMode... modes) throws IOException {
         boolean e = false;
         boolean r = false;
         boolean w = false;
         boolean x = false;
 
-        if (first == Access.EXISTS) e = true;
-        else if (first == Access.READ) r = true;
-        else if (first == Access.WRITE) w = true;
-        else if (first == Access.EXECUTE) x = true;
-        else {
-            if (first == null)
-                throw new NullPointerException();
-            throw new AssertionError("Should not get here");
-        }
-        for (Access access: rest) {
-            if (first == Access.EXISTS) e = true;
-            else if (access == Access.READ) r = true;
-            else if (access == Access.WRITE) w = true;
-            else if (access == Access.EXECUTE) x = true;
-            else {
-                if (access == null)
-                    throw new NullPointerException();
-                throw new AssertionError("Should not get here");
+        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 |= (e) ? F_OK : R_OK;
+            mode |= (r) ? R_OK : F_OK;
         }
         if (w) {
             checkWrite();
@@ -812,12 +794,14 @@
         }
         if (x) {
             SecurityManager sm = System.getSecurityManager();
-            if (sm != null)
+            if (sm != null) {
+                // not cached
                 sm.checkExec(getPathForPermissionCheck());
+            }
             mode |= X_OK;
         }
         try {
-            access(getPathForSysCalls(), mode);
+            access(this, mode);
         } catch (UnixException exc) {
             exc.rethrowAsIOException(this);
         }
@@ -830,11 +814,11 @@
         // need file attributes to know if file is directory
         UnixFileAttributes attrs = null;
         try {
-            attrs = UnixFileAttributes.get(getPathForSysCalls(), false);
+            attrs = UnixFileAttributes.get(this, false);
             if (attrs.isDirectory()) {
-                rmdir(getPathForSysCalls());
+                rmdir(this);
             } else {
-                unlink(getPathForSysCalls());
+                unlink(this);
             }
         } catch (UnixException x) {
             // no-op if file does not exist
@@ -854,14 +838,14 @@
     public DirectoryStream<Path> newDirectoryStream(DirectoryStream.Filter<? super Path> filter)
         throws IOException
     {
-        checkRead();
         if (filter == null)
             throw new NullPointerException();
+        checkRead();
 
         // can't return SecureDirectoryStream on older kernels.
         if (!getFileSystem().supportsSecureDirectoryStreams()) {
             try {
-                long ptr = opendir(getPathForSysCalls());
+                long ptr = opendir(this);
                 return new UnixDirectoryStream(this, ptr, filter);
             } catch (UnixException x) {
                 if (x.errno() == UnixConstants.ENOTDIR)
@@ -876,7 +860,7 @@
         int dfd2 = -1;
         long dp = 0L;
         try {
-            dfd1 = open(getPathForSysCalls(), O_RDONLY, 0);
+            dfd1 = open(this, O_RDONLY, 0);
             dfd2 = dup(dfd1);
             dp = fdopendir(dfd1);
         } catch (UnixException x) {
@@ -935,7 +919,7 @@
         int mode = UnixFileModeAttribute
             .toUnixMode(UnixFileModeAttribute.ALL_PERMISSIONS, attrs);
         try {
-            mkdir(getPathForSysCalls(), mode);
+            mkdir(this, mode);
         } catch (UnixException x) {
             x.rethrowAsIOException(this);
         }
@@ -946,11 +930,7 @@
     public InputStream newInputStream()throws IOException {
         try {
             Set<OpenOption> options = Collections.emptySet();
-            FileChannel fc = UnixChannelFactory
-                .newFileChannel(getPathForSysCalls(),
-                                getPathForPermissionCheck(),
-                                options,
-                                0);
+            FileChannel fc = UnixChannelFactory.newFileChannel(this, options, 0);
             return Channels.newInputStream(fc);
         } catch (UnixException x) {
             x.rethrowAsIOException(this);
@@ -966,11 +946,7 @@
         int mode = UnixFileModeAttribute
             .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
         try {
-            return UnixChannelFactory
-                .newFileChannel(getPathForSysCalls(),
-                                getPathForPermissionCheck(),
-                                options,
-                                mode);
+            return UnixChannelFactory.newFileChannel(this, options, mode);
         } catch (UnixException x) {
             x.rethrowAsIOException(this);
             return null;  // keep compiler happy
@@ -991,11 +967,7 @@
         int mode = UnixFileModeAttribute
             .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
         try {
-            FileChannel fc = UnixChannelFactory
-                .newFileChannel(getPathForSysCalls(),
-                                getPathForPermissionCheck(),
-                                opts,
-                                mode);
+            FileChannel fc = UnixChannelFactory.newFileChannel(this, opts, mode);
             return Channels.newOutputStream(fc);
         } catch (UnixException x) {
             x.rethrowAsIOException(this);
@@ -1018,13 +990,13 @@
         UnixFileAttributes thisAttrs;
         UnixFileAttributes otherAttrs;
         try {
-             thisAttrs = UnixFileAttributes.get(getPathForSysCalls(), true);
+             thisAttrs = UnixFileAttributes.get(this, true);
         } catch (UnixException x) {
             x.rethrowAsIOException(this);
             return false;    // keep compiler happy
         }
         try {
-            otherAttrs = UnixFileAttributes.get(other.getPathForSysCalls(), true);
+            otherAttrs = UnixFileAttributes.get(other, true);
         } catch (UnixException x) {
             x.rethrowAsIOException(other);
             return false;    // keep compiler happy
@@ -1049,12 +1021,12 @@
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             sm.checkPermission(new LinkPermission("symbolic"));
-            this.checkWrite();
+            checkWrite();
         }
 
         // create link
         try {
-            symlink(target.asByteArray(), this.getPathForSysCalls());
+            symlink(target.asByteArray(), this);
         } catch (UnixException x) {
             x.rethrowAsIOException(this);
         }
@@ -1074,7 +1046,7 @@
             existing.checkWrite();
         }
         try {
-            link(existing.getPathForSysCalls(), this.getPathForSysCalls());
+            link(existing, this);
         } catch (UnixException x) {
             x.rethrowAsIOException(this, existing);
         }
@@ -1091,7 +1063,7 @@
             AccessController.checkPermission(perm);
         }
         try {
-            byte[] target = readlink(getPathForSysCalls());
+            byte[] target = readlink(this);
             return new UnixPath(getFileSystem(), target);
         } catch (UnixException x) {
            if (x.errno() == UnixConstants.EINVAL)
@@ -1112,13 +1084,8 @@
         if (sm != null) {
             sm.checkPropertyAccess("user.dir");
         }
-
-        if (getFileSystem().chdirAllowed()) {
-            // already resolved against default directory
-            return new UnixPath(getFileSystem(), pathForSysCalls);
-        } else {
-            return new UnixPath(getFileSystem(), resolve(getFileSystem().defaultDirectory(), path));
-        }
+        return new UnixPath(getFileSystem(),
+            resolve(getFileSystem().defaultDirectory(), path));
     }
 
     @Override
@@ -1130,7 +1097,7 @@
         // if resolveLinks is true then use realpath
         if (resolveLinks) {
             try {
-                byte[] rp = realpath(absolute.asByteArray());
+                byte[] rp = realpath(absolute);
                 return new UnixPath(getFileSystem(), rp);
             } catch (UnixException x) {
                 x.rethrowAsIOException(this);
@@ -1154,8 +1121,7 @@
             {
                 UnixFileAttributes attrs = null;
                 try {
-                    attrs = UnixFileAttributes.get(result.getPathForSysCalls(),
-                                                   false);
+                    attrs = UnixFileAttributes.get(result, false);
                 } catch (UnixException x) {
                     x.rethrowAsIOException(result);
                 }
@@ -1172,7 +1138,7 @@
 
         // finally check that file exists
         try {
-            UnixFileAttributes.get(result.getPathForSysCalls(), true);
+            UnixFileAttributes.get(result, true);
         } catch (UnixException x) {
             x.rethrowAsIOException(result);
         }
--- a/src/solaris/classes/sun/nio/fs/UnixSecureDirectoryStream.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixSecureDirectoryStream.java	Mon Oct 20 19:20:24 2008 +0100
@@ -152,12 +152,7 @@
             if (!ds.isOpen())
                 throw new ClosedDirectoryStreamException();
             try {
-                return UnixChannelFactory
-                    .newFileChannel(dfd,
-                                    file.asByteArray(),
-                                    pathToCheck,
-                                    options,
-                                    mode);
+                return UnixChannelFactory.newFileChannel(dfd, file, pathToCheck, options, mode);
             } catch (UnixException x) {
                 x.rethrowAsIOException(file);
                 return null; // keep compiler happy
@@ -179,7 +174,7 @@
         // permission check using name resolved against original path of directory
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            sm.checkDelete(ds.directory().resolve(file).getPathForPermissionCheck());
+            ds.directory().resolve(file).checkDelete();
         }
 
         ds.readLock().lock();
@@ -194,7 +189,7 @@
                 // file type and unlink it.
                 UnixFileAttributes attrs = null;
                 try {
-                    attrs = UnixFileAttributes.get(dfd, file.asByteArray(), false);
+                    attrs = UnixFileAttributes.get(dfd, file, false);
                 } catch (UnixException x) {
                     x.rethrowAsIOException(file);
                 }
@@ -370,7 +365,7 @@
                 try {
                      UnixFileAttributes attrs = (file == null) ?
                          UnixFileAttributes.get(dfd) :
-                         UnixFileAttributes.get(dfd, file.asByteArray(), followLinks);
+                         UnixFileAttributes.get(dfd, file, followLinks);
 
                      // SECURITY: must return as BasicFileAttribute
                      return attrs.asBasicFileAttributes();
@@ -510,7 +505,7 @@
                 return;
             }
             if (attribute.equals(GROUP_NAME)) {
-                setGroup((UserPrincipal)value);
+                setGroup((GroupPrincipal)value);
                 return;
             }
             super.setAttribute(attribute, value);
@@ -557,7 +552,7 @@
                 try {
                      UnixFileAttributes attrs = (file == null) ?
                          UnixFileAttributes.get(dfd) :
-                         UnixFileAttributes.get(dfd, file.asByteArray(), followLinks);
+                         UnixFileAttributes.get(dfd, file, followLinks);
                      return attrs;
                 } catch (UnixException x) {
                     x.rethrowAsIOException(file);
@@ -618,26 +613,29 @@
         }
 
         @Override
+        public UserPrincipal getOwner() throws IOException {
+            return readAttributes().owner();
+        }
+
+        @Override
         public void setOwner(UserPrincipal owner)
             throws IOException
         {
-            if (owner.isGroup())
-                throw new IllegalArgumentException("Owner parameter can't be group");
-            if (!(owner instanceof UnixUserPrincipal))
+            if (!(owner instanceof UnixUserPrincipals.User))
                 throw new ProviderMismatchException();
-            int uid = ((UnixUserPrincipal)owner).uid();
+            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(UserPrincipal group)
+        public void setGroup(GroupPrincipal group)
             throws IOException
         {
-            if (!group.isGroup())
-                throw new IllegalArgumentException("Group parameter must be a group");
-            if (!(group instanceof UnixUserPrincipal))
+            if (!(group instanceof UnixUserPrincipals.Group))
                 throw new ProviderMismatchException();
-            int gid = ((UnixUserPrincipal)group).gid();
+            int gid = ((UnixUserPrincipals.Group)group).gid();
             setOwners(-1, gid);
         }
     }
--- a/src/solaris/classes/sun/nio/fs/UnixUriUtils.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/classes/sun/nio/fs/UnixUriUtils.java	Mon Oct 20 19:20:24 2008 +0100
@@ -93,7 +93,7 @@
         // trailing slash if directory
         if (sb.charAt(sb.length()-1) != '/') {
             try {
-                 if (UnixFileAttributes.get(up.getPathForSysCalls(), true).isDirectory())
+                 if (UnixFileAttributes.get(up, true).isDirectory())
                      sb.append('/');
             } catch (UnixException x) {
                 // ignore
--- a/src/solaris/classes/sun/nio/fs/UnixUserPrincipal.java	Mon Oct 20 11:19:56 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,165 +0,0 @@
-/*
- * Copyright 2007-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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 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.UserPrincipal;
-import java.nio.file.attribute.UserPrincipalNotFoundException;
-import java.io.IOException;
-import static sun.nio.fs.UnixNativeDispatcher.*;
-
-/**
- * Unix implementation of java.nio.file.attribute.UserPrincipal
- */
-
-class UnixUserPrincipal
-    implements UserPrincipal
-{
-    private static UnixUserPrincipal createSpecial(String name) {
-        return new UnixUserPrincipal(-1, false, name);
-    }
-
-    static final UnixUserPrincipal SPECIAL_OWNER = createSpecial("OWNER@");
-    static final UnixUserPrincipal SPECIAL_GROUP = createSpecial("GROUP@");
-    static final UnixUserPrincipal SPECIAL_EVERYONE = createSpecial("EVERYONE@");
-
-    private final int id;             // uid or gid
-    private final boolean isGroup;
-    private final String name;
-
-    private UnixUserPrincipal(int id, boolean isGroup, String name) {
-        this.id = id;
-        this.isGroup = isGroup;
-        this.name = name;
-    }
-
-    // return UserPrincipal representing given uid
-    static UnixUserPrincipal fromUid(int uid) {
-        String name = null;
-        try {
-            name = new String(getpwuid(uid));
-        } catch (UnixException x) {
-            name = Integer.toString(uid);
-        }
-        return new UnixUserPrincipal(uid, false, name);
-    }
-
-    // return (group) UserPrincipal representing given gid
-    static UnixUserPrincipal fromGid(int gid) {
-        String name = null;
-        try {
-            name = new String(getgrgid(gid));
-        } catch (UnixException x) {
-            name = Integer.toString(gid);
-        }
-        return new UnixUserPrincipal(gid, true, name);
-    }
-
-    // lookup user or group name
-    private static int lookupPrincipalByName(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.getBytes()) : getpwnam(name.getBytes());
-        } catch (UnixException x) {
-            throw new IOException(name + ": " + x.errorString());
-        }
-        if (id == -1)
-            throw new UserPrincipalNotFoundException(name);
-        return id;
-
-    }
-
-    // lookup user name
-    static UserPrincipal lookupPrincipalByName(String name) throws IOException {
-        int uid = lookupPrincipalByName(name, false);
-        return new UnixUserPrincipal(uid, false, name);
-    }
-
-    // lookup group name
-    static UserPrincipal lookupPrincipalByGroupName(String group) throws IOException {
-        int gid = lookupPrincipalByName(group, true);
-        return new UnixUserPrincipal(gid, true, group);
-    }
-
-    int uid() {
-        if (isGroup())
-            throw new IllegalStateException();
-        return id;
-    }
-
-    int gid() {
-        if (!isGroup())
-            throw new IllegalStateException();
-        return id;
-    }
-
-    boolean isSpecial() {
-        return id == -1;
-    }
-
-    @Override
-    public boolean isGroup() {
-        return isGroup;
-    }
-
-    @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 UnixUserPrincipal))
-            return false;
-        UnixUserPrincipal other = (UnixUserPrincipal)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();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/solaris/classes/sun/nio/fs/UnixUserPrincipals.java	Mon Oct 20 19:20:24 2008 +0100
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2007-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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import static sun.nio.fs.UnixNativeDispatcher.*;
+
+/**
+ * Unix implementation of java.nio.file.attribute.UserPrincipal
+ */
+
+class UnixUserPrincipals {
+    private static User createSpecial(String name) { return new User(-1, name); }
+
+    static final User SPECIAL_OWNER = createSpecial("OWNER@");
+    static final User SPECIAL_GROUP = createSpecial("GROUP@");
+    static final User SPECIAL_EVERYONE = createSpecial("EVERYONE@");
+
+    static class User implements UserPrincipal {
+        private final int id;             // uid or gid
+        private final boolean isGroup;
+        private final String name;
+
+        private User(int id, boolean isGroup, String name) {
+            this.id = id;
+            this.isGroup = isGroup;
+            this.name = name;
+        }
+
+        User(int id, String name) {
+            this(id, false, name);
+        }
+
+        int uid() {
+            if (isGroup)
+                throw new AssertionError();
+            return id;
+        }
+
+        int gid() {
+            if (isGroup)
+                return id;
+            throw new AssertionError();
+        }
+
+        boolean isSpecial() {
+            return id == -1;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this)
+                return true;
+            if (!(obj instanceof User))
+                return false;
+            User other = (User)obj;
+            if ((this.id != other.id) ||
+                (this.isGroup != other.isGroup)) {
+                return false;
+            }
+            // specials
+            if (this.id == -1 && other.id == -1)
+                return this.name.equals(other.name);
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            return (id != -1) ? id : name.hashCode();
+        }
+    }
+
+    static class Group extends User implements GroupPrincipal {
+        Group(int id, String name) {
+            super(id, true, name);
+        }
+    }
+
+    // return UserPrincipal representing given uid
+    static User fromUid(int uid) {
+        String name = null;
+        try {
+            name = new String(getpwuid(uid));
+        } catch (UnixException x) {
+            name = Integer.toString(uid);
+        }
+        return new User(uid, name);
+    }
+
+    // return GroupPrincipal representing given gid
+    static Group fromGid(int gid) {
+        String name = null;
+        try {
+            name = new String(getgrgid(gid));
+        } catch (UnixException x) {
+            name = Integer.toString(gid);
+        }
+        return new Group(gid, name);
+    }
+
+    // lookup user or group name
+    private static int lookupName(String name, boolean isGroup)
+        throws IOException
+    {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("lookupUserInformation"));
+        }
+        int id = -1;
+        try {
+            id = (isGroup) ? getgrnam(name) : getpwnam(name);
+        } catch (UnixException x) {
+            throw new IOException(name + ": " + x.errorString());
+        }
+        if (id == -1)
+            throw new UserPrincipalNotFoundException(name);
+        return id;
+
+    }
+
+    // lookup user name
+    static UserPrincipal lookupUser(String name) throws IOException {
+        if (name.equals(SPECIAL_OWNER.getName()))
+            return SPECIAL_OWNER;
+        if (name.equals(SPECIAL_GROUP.getName()))
+            return SPECIAL_GROUP;
+        if (name.equals(SPECIAL_EVERYONE.getName()))
+            return SPECIAL_EVERYONE;
+        int uid = lookupName(name, false);
+        return new User(uid, name);
+    }
+
+    // lookup group name
+    static GroupPrincipal lookupGroup(String group)
+        throws IOException
+    {
+        int gid = lookupName(group, true);
+        return new Group(gid, group);
+    }
+}
--- a/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c	Mon Oct 20 19:20:24 2008 +0100
@@ -204,6 +204,25 @@
 #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)
 {
--- a/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java	Mon Oct 20 19:20:24 2008 +0100
@@ -125,7 +125,7 @@
             long sidAddress = GetSecurityDescriptorOwner(buffer.address());
             if (sidAddress == 0L)
                 throw new IOException("no owner");
-            return new WindowsUserPrincipal(sidAddress);
+            return WindowsUserPrincipals.fromSid(sidAddress);
         } catch (WindowsException x) {
             x.rethrowAsIOException(file);
             return null;
@@ -166,9 +166,9 @@
         String path = followLinks ? WindowsLinkSupport.getFinalPath(file) :
                                     file.getPathForWin32Calls();
 
-        if (!(obj instanceof WindowsUserPrincipal))
+        if (!(obj instanceof WindowsUserPrincipals.User))
             throw new ProviderMismatchException();
-        WindowsUserPrincipal owner = (WindowsUserPrincipal)obj;
+        WindowsUserPrincipals.User owner = (WindowsUserPrincipals.User)obj;
 
         // ConvertStringSidToSid allocates memory for SID so must invoke
         // LocalFree to free it when we are done
--- a/src/windows/classes/sun/nio/fs/WindowsConstants.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsConstants.java	Mon Oct 20 19:20:24 2008 +0100
@@ -79,6 +79,7 @@
     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;
 
@@ -150,6 +151,7 @@
     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;
--- a/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java	Mon Oct 20 19:20:24 2008 +0100
@@ -72,12 +72,12 @@
         }
 
         try {
-            WindowsNativeDispatcher.FirstFile first = FindFirstFile(search);
+            FirstFile first = FindFirstFile(search);
             this.handle = first.handle();
             this.firstName = first.name();
         } catch (WindowsException x) {
             if (x.lastError() == ERROR_DIRECTORY) {
-                throw new NotDirectoryException(dir.getPathForExecptionMessage());
+                throw new NotDirectoryException(dir.getPathForExceptionMessage());
             }
             x.rethrowAsIOException(dir);
 
--- a/src/windows/classes/sun/nio/fs/WindowsException.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsException.java	Mon Oct 20 19:20:24 2008 +0100
@@ -92,8 +92,8 @@
     }
 
     void rethrowAsIOException(WindowsPath file, WindowsPath other) throws IOException {
-        String a = (file == null) ? null : file.getPathForExecptionMessage();
-        String b = (other == null) ? null : other.getPathForExecptionMessage();
+        String a = (file == null) ? null : file.getPathForExceptionMessage();
+        String b = (other == null) ? null : other.getPathForExceptionMessage();
         IOException x = translateToIOException(a, b);
         throw x;
     }
@@ -103,7 +103,7 @@
     }
 
     IOException asIOException(WindowsPath file) {
-        return translateToIOException(file.getPathForExecptionMessage(), null);
+        return translateToIOException(file.getPathForExceptionMessage(), null);
     }
 
 }
--- a/src/windows/classes/sun/nio/fs/WindowsFileCopy.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsFileCopy.java	Mon Oct 20 19:20:24 2008 +0100
@@ -117,7 +117,7 @@
                     // can't replace file
                     if (!replaceExisting) {
                         throw new FileAlreadyExistsException(
-                            target.getPathForExecptionMessage());
+                            target.getPathForExceptionMessage());
                     }
 
                 } finally {
@@ -155,7 +155,7 @@
                         x.lastError() == ERROR_ALREADY_EXISTS)
                     {
                         throw new FileAlreadyExistsException(
-                            target.getPathForExecptionMessage());
+                            target.getPathForExceptionMessage());
                     }
                 }
                 x.rethrowAsIOException(target);
@@ -257,8 +257,8 @@
             } catch (WindowsException x) {
                 if (x.lastError() == ERROR_NOT_SAME_DEVICE) {
                     throw new AtomicMoveNotSupportedException(
-                        source.getPathForExecptionMessage(),
-                        target.getPathForExecptionMessage(),
+                        source.getPathForExceptionMessage(),
+                        target.getPathForExceptionMessage(),
                         x.errorString());
                 }
                 x.rethrowAsIOException(source, target);
@@ -307,7 +307,7 @@
                     // can't replace file
                     if (!replaceExisting) {
                         throw new FileAlreadyExistsException(
-                            target.getPathForExecptionMessage());
+                            target.getPathForExceptionMessage());
                     }
 
                 } finally {
@@ -337,7 +337,7 @@
                         x.lastError() == ERROR_ALREADY_EXISTS)
                     {
                         throw new FileAlreadyExistsException(
-                            target.getPathForExecptionMessage());
+                            target.getPathForExceptionMessage());
                     }
                 }
                 x.rethrowAsIOException(target);
@@ -421,7 +421,7 @@
                 x.lastError() == ERROR_ALREADY_EXISTS)
             {
                 throw new DirectoryNotEmptyException(
-                    target.getPathForExecptionMessage());
+                    target.getPathForExceptionMessage());
             }
             x.rethrowAsIOException(source);
         }
--- a/src/windows/classes/sun/nio/fs/WindowsFileStore.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsFileStore.java	Mon Oct 20 19:20:24 2008 +0100
@@ -27,7 +27,6 @@
 
 import java.nio.file.*;
 import java.nio.file.attribute.*;
-import java.nio.channels.*;
 import java.util.*;
 import java.io.IOException;
 
@@ -99,6 +98,18 @@
         }
     }
 
+    VolumeInformation volumeInformation() {
+        return info;
+    }
+
+    void checkAttributeAccess() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkRead(pathForPermissionCheck);
+            sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));
+        }
+    }
+
     @Override
     public String name() {
         return info.volumeName();   // "SYSTEM", "DVD-RW", ...
@@ -126,6 +137,8 @@
     public FileStoreAttributeView getFileStoreAttributeView(String name) {
         if (name.equals("space"))
             return new WindowsFileStoreAttributeView(this);
+        if (name.equals("volume"))
+            return new VolumeFileStoreAttributeView(this);
         return null;
     }
 
@@ -194,12 +207,7 @@
         public FileStoreSpaceAttributes readAttributes()
             throws IOException
         {
-            // permission check
-            SecurityManager sm = System.getSecurityManager();
-            if (sm != null) {
-                sm.checkRead(fs.pathForPermissionCheck);
-                sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));
-            }
+            fs.checkAttributeAccess();
 
             // read the free space info
             DiskFreeSpace info = null;
@@ -226,4 +234,91 @@
             };
         }
     }
+
+    /**
+     * 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 final WindowsFileStore fs;
+
+        VolumeFileStoreAttributeView(WindowsFileStore fs) {
+            this.fs = fs;
+        }
+
+        @Override
+        public String name() {
+            return "volume";
+        }
+
+        private int vsn() {
+            fs.checkAttributeAccess();
+            return fs.volumeInformation().volumeSerialNumber();
+        }
+
+        private boolean isCompressed() {
+            fs.checkAttributeAccess();
+            return (fs.volumeInformation().flags() &
+                    FILE_VOLUME_IS_COMPRESSED) > 0;
+        }
+
+        @Override
+        public Object getAttribute(String attribute) throws IOException {
+            if (attribute.equals(VSN_NAME))
+                return vsn();
+            if (attribute.equals(COMPRESSED_NAME))
+                return isCompressed();
+            return null;
+        }
+
+        @Override
+        public void setAttribute(String attribute, Object value)
+            throws IOException
+        {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Map<String,?> readAttributes(String first, String... rest)
+            throws IOException
+        {
+            boolean vsn = false;
+            boolean compressed = false;
+
+            if (first.equals(VSN_NAME)) vsn = true;
+            else if (first.equals(COMPRESSED_NAME)) compressed = true;
+            else if (first.equals("*")) {
+                vsn = true;
+                compressed = true;
+            }
+            if (!vsn || !compressed) {
+                for (String attribute: rest) {
+                    if (attribute.equals("*")) {
+                        vsn = true;
+                        compressed = true;
+                        break;
+                    }
+                    if (attribute.equals(VSN_NAME)) {
+                        vsn = true;
+                        continue;
+                    }
+                    if (attribute.equals(COMPRESSED_NAME)) {
+                        compressed = true;
+                        continue;
+                    }
+                }
+            }
+
+            Map<String,Object> result = new HashMap<String,Object>();
+            if (vsn)
+                result.put(VSN_NAME, vsn());
+            if (compressed)
+                result.put(COMPRESSED_NAME, isCompressed());
+            return result;
+        }
+    }
 }
--- a/src/windows/classes/sun/nio/fs/WindowsFileSystem.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsFileSystem.java	Mon Oct 20 19:20:24 2008 +0100
@@ -39,7 +39,7 @@
 import static sun.nio.fs.WindowsConstants.*;
 
 class WindowsFileSystem
-    extends FileSystem implements UserPrincipalLookupService
+    extends FileSystem
 {
     private final WindowsFileSystemProvider provider;
 
@@ -121,8 +121,6 @@
 
     // return new iterator over root directories
     private Iterator<Path> rootDirectoryIterator() {
-        // FIXME - we should replace this with calls to FindFirstVolume and
-        // FindNextVolume
         int drives = 0;
         try {
             drives = WindowsNativeDispatcher.GetLogicalDrives();
@@ -246,61 +244,31 @@
         return new WindowsPath(this, result.type(), result.root(), result.path());
     }
 
-    // lookup of user or group
-    private UserPrincipal lookupPrincipalByNameImpl(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 new WindowsUserPrincipal(sidBuffer.address());
-        } catch (WindowsException x) {
-            throw new IOException(name + ": " + x.errorString());
-        } finally {
-            sidBuffer.release();
-        }
-    }
-
-    @Override
-    public UserPrincipal lookupPrincipalByName(String name)
-        throws IOException
-    {
-        return lookupPrincipalByNameImpl(name);
-    }
-
-    @Override
-    public UserPrincipal lookupPrincipalByGroupName(String group)
-        throws IOException
-    {
-        return lookupPrincipalByNameImpl(group);
-    }
 
     @Override
     public UserPrincipalLookupService getUserPrincipalLookupService() {
-        return this;
+        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 getNameMatcher(String syntax, String input) {
         String expr;
--- a/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java	Mon Oct 20 19:20:24 2008 +0100
@@ -142,7 +142,7 @@
             }
         } while (++linkCount < 32);
 
-        throw new FileSystemException(input.getPathForExecptionMessage(), null,
+        throw new FileSystemException(input.getPathForExceptionMessage(), null,
             "Too many links");
     }
 
@@ -219,7 +219,7 @@
             // 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.getPathForExecptionMessage(),
+                throw new FileSystemException(input.getPathForExceptionMessage(),
                     null, "UNC has invalid share");
             }
             pos = path.indexOf('\\', pos+1);
--- a/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java	Mon Oct 20 19:20:24 2008 +0100
@@ -1088,19 +1088,26 @@
 
     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
         int stringOffsetInBytes = getOffsetField(s) << 1;
         char[] stringValue = getValueField(s);
-
-        // allocate buffer with space for zero termination
-        int sizeInBytes = stringLengthInBytes + 2;
-        NativeBuffer buffer = NativeBuffers.getNativeBuffer(sizeInBytes);
-
-        // copy into buffer and zero terminate
         long offset = Unsafe.ARRAY_CHAR_BASE_OFFSET + stringOffsetInBytes;
         unsafe.copyMemory(stringValue, offset, null, buffer.address(),
             (long)stringLengthInBytes);
         unsafe.putChar(buffer.address() + stringLengthInBytes, (char)0);
-
+        buffer.setOwner(s);
         return buffer;
     }
 
--- a/src/windows/classes/sun/nio/fs/WindowsPath.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsPath.java	Mon Oct 20 19:20:24 2008 +0100
@@ -33,7 +33,6 @@
 import java.net.URI;
 import java.security.AccessController;
 import java.util.*;
-import java.lang.reflect.*;
 
 import com.sun.nio.file.ExtendedWatchEventModifier;
 
@@ -58,9 +57,6 @@
     // root component (may be empty)
     private final String root;
     // normalized path
-    // TDB: Need to compare performance with implementation that stores path
-    // as array of components where the component can be shared betweeen Path
-    // instances.
     private final String path;
 
     // offsets into name components (computed lazily)
@@ -71,9 +67,9 @@
 
     // the path to use in calls to Windows (same as resolved path when less
     // than 248 characters but differs for long paths)
-    private final String pathforWin32Calls;
+    private final String pathForWin32Calls;
 
-    // computed hash code
+    // computed hash code (computed lazily, no need to be volatile)
     private volatile int hash;
 
 
@@ -138,7 +134,7 @@
             ps = addPrefixIfNeeded(ps);
         }
 
-        this.pathforWin32Calls = ps;
+        this.pathForWin32Calls = ps;
     }
 
     /**
@@ -163,7 +159,7 @@
     }
 
     // use this message when throwing exceptions
-    String getPathForExecptionMessage() {
+    String getPathForExceptionMessage() {
         return path;
     }
 
@@ -174,7 +170,7 @@
 
     // use this for calls into Windows (may have \\?\ or \\?\UNC prefix)
     String getPathForWin32Calls() {
-        return pathforWin32Calls;
+        return pathForWin32Calls;
     }
 
     // Add long path prefix to path if required
@@ -532,6 +528,7 @@
             while (--otherCount >= 0) {
                 String thisElement = this.elementAsString(otherCount);
                 String otherElement = other.elementAsString(otherCount);
+                // FIXME: should compare in uppercase
                 if (!thisElement.equalsIgnoreCase(otherElement))
                     return false;
             }
@@ -561,6 +558,7 @@
         if (other.root.length() > 0) {
             if (otherCount < thisCount)
                 return false;
+            // FIXME: should compare in uppercase
             if (!this.root.equalsIgnoreCase(other.root))
                 return false;
         }
@@ -570,6 +568,7 @@
         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;
         }
@@ -761,35 +760,9 @@
     }
 
     @Override
-    public void checkAccess(Access first, Access... rest) throws IOException {
-        boolean e = false;
-        boolean r = false;
-        boolean w = false;
-        boolean x = false;
-
-        if (first == Access.EXISTS) e = true;
-        else if (first == Access.READ) r = true;
-        else if (first == Access.WRITE) w = true;
-        else if (first == Access.EXECUTE) x = true;
-        else {
-            if (first == null)
-                throw new NullPointerException();
-            throw new AssertionError("Should not get here");
-        }
-        for (Access access: rest) {
-            if (access == Access.EXISTS) e = true;
-            else if (access == Access.READ) r = true;
-            else if (access == Access.WRITE) w = true;
-            else if (access == Access.EXECUTE) x = true;
-            else {
-                if (access == null)
-                    throw new NullPointerException();
-                throw new AssertionError("Should not get here");
-            }
-        }
-
-        // check file exists only so no need to get effective access to file
-        if (e && !r && !w && !x) {
+    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);
@@ -799,10 +772,22 @@
             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 (e || r) {
+        if (r) {
             checkRead();
-            if (r) mask |= FILE_READ_DATA;
+            mask |= FILE_READ_DATA;
         }
         if (w) {
             checkWrite();
@@ -817,7 +802,7 @@
 
         if ((getEffectiveAccess() & mask) == 0)
             throw new AccessDeniedException(
-                this.getPathForExecptionMessage(), null,
+                this.getPathForExceptionMessage(), null,
                 "Effective permissions does not allow requested access");
 
         // for write access we neeed to check if the DOS readonly attribute
@@ -827,7 +812,7 @@
                 WindowsFileAttributes attrs = WindowsFileAttributes.get(this, true);
                 if (!attrs.isDirectory() && attrs.isReadOnly())
                     throw new AccessDeniedException(
-                        this.getPathForExecptionMessage(), null,
+                        this.getPathForExceptionMessage(), null,
                         "DOS readonly attribute is set");
             } catch (WindowsException exc) {
                 exc.rethrowAsIOException(this);
@@ -835,7 +820,7 @@
 
             if (WindowsFileStore.create(this).isReadOnly()) {
                 throw new AccessDeniedException(
-                    this.getPathForExecptionMessage(), null, "Read-only file system");
+                    this.getPathForExceptionMessage(), null, "Read-only file system");
             }
             return;
         }
@@ -868,7 +853,7 @@
                     x.lastError() == ERROR_ALREADY_EXISTS)
                 {
                     throw new DirectoryNotEmptyException(
-                        getPathForExecptionMessage());
+                        getPathForExceptionMessage());
                 }
             }
             x.rethrowAsIOException(this);
@@ -970,7 +955,7 @@
 
     @Override
     public SeekableByteChannel newByteChannel(Set<? extends OpenOption> options,
-                                                      FileAttribute<?>... attrs)
+                                              FileAttribute<?>... attrs)
          throws IOException
     {
         WindowsSecurityDescriptor sd =
--- a/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java	Mon Oct 20 19:20:24 2008 +0100
@@ -124,9 +124,9 @@
             // get the SID for each entry
             for (AclEntry entry: acl) {
                 UserPrincipal user = entry.principal();
-                if (!(user instanceof WindowsUserPrincipal))
+                if (!(user instanceof WindowsUserPrincipals.User))
                     throw new ProviderMismatchException();
-                String sidString = ((WindowsUserPrincipal)user).sidString();
+                String sidString = ((WindowsUserPrincipals.User)user).sidString();
                 try {
                     long pSid = ConvertStringSidToSid(sidString);
                     sidList.add(pSid);
@@ -258,7 +258,7 @@
 
         // lookup SID to create UserPrincipal
         long sidAddress = aceAddress + OFFSETOF_SID;
-        UserPrincipal user = new WindowsUserPrincipal(sidAddress);
+        UserPrincipal user = WindowsUserPrincipals.fromSid(sidAddress);
 
         return AclEntry.newBuilder()
             .setType(type)
--- a/src/windows/classes/sun/nio/fs/WindowsUserPrincipal.java	Mon Oct 20 11:19:56 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-/*
- * Copyright 2007-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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 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.UserPrincipal;
-import java.io.IOException;
-
-import static sun.nio.fs.WindowsConstants.*;
-import static sun.nio.fs.WindowsNativeDispatcher.*;
-
-class WindowsUserPrincipal
-    implements UserPrincipal
-{
-    private final boolean isGroup;
-
-    // String representation of SID
-    private final String sid;
-
-    // Account name (if available) or SID
-    private final String accountName;
-
-
-    WindowsUserPrincipal(long sidAddress) throws IOException {
-        String sidString;
-        try {
-            sidString = ConvertSidToStringSid(sidAddress);
-            if (sidString == null) {
-                // need fallback for 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;
-        }
-        // map SID type
-        this.isGroup = (account != null &&
-            ((account.use() == SidTypeGroup) ||
-             (account.use() == SidTypeWellKnownGroup)));
-        this.sid = sidString;
-        this.accountName = name;
-    }
-
-    // package-private
-    String sidString() {
-        return sid;
-    }
-
-    @Override
-    public boolean isGroup() {
-        return isGroup;
-    }
-
-    @Override
-    public String getName() {
-        return accountName;
-    }
-
-    @Override
-    public String toString() {
-        return accountName;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == this)
-            return true;
-        if (!(obj instanceof WindowsUserPrincipal))
-            return false;
-        WindowsUserPrincipal other = (WindowsUserPrincipal)obj;
-        return this.sid.equals(other.sid);
-    }
-
-    @Override
-    public int hashCode() {
-        return sid.hashCode();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windows/classes/sun/nio/fs/WindowsUserPrincipals.java	Mon Oct 20 19:20:24 2008 +0100
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2007-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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 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();
+        }
+    }
+}
--- a/src/windows/classes/sun/nio/fs/WindowsWatchService.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/src/windows/classes/sun/nio/fs/WindowsWatchService.java	Mon Oct 20 19:20:24 2008 +0100
@@ -349,7 +349,7 @@
                     return x.asIOException(dir);
                 }
                 if (!attrs.isDirectory()) {
-                    return new NotDirectoryException(dir.getPathForExecptionMessage());
+                    return new NotDirectoryException(dir.getPathForExceptionMessage());
                 }
 
                 // check if this directory is already registered
--- a/test/demo/nio/ZipFileSystem/Sanity.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/test/demo/nio/ZipFileSystem/Sanity.java	Mon Oct 20 19:20:24 2008 +0100
@@ -114,7 +114,7 @@
         if (fs.isOpen())
             throw new RuntimeException("FileSystem should be closed");
         try {
-            fs.getPath("/missing").checkAccess(Access.READ);
+            fs.getPath("/missing").checkAccess(AccessMode.READ);
         } catch (ClosedFileSystemException x) { }
     }
 
--- a/test/java/nio/file/DirectoryStream/Basic.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/test/java/nio/file/DirectoryStream/Basic.java	Mon Oct 20 19:20:24 2008 +0100
@@ -30,12 +30,11 @@
 import java.nio.file.*;
 import java.util.*;
 import java.io.IOException;
-import java.io.OutputStream;
 
 public class Basic {
     static boolean found;
 
-    static void doTest(Path dir) throws IOException {
+    static void doTest(final Path dir) throws IOException {
         // test that directory is empty
         Files.withDirectory(dir, new FileAction<FileRef>() {
             public void invoke(FileRef entry) {
@@ -64,16 +63,29 @@
         if (!found)
             throw new RuntimeException("entry not found");
 
-        // check filtering f* should match; F* should not
-        DirectoryStream.Filter<Path> filter;
-        filter = DirectoryStreamFilters.newCaseSensitiveGlobFilter("f*");
+        // check filtering: f* should match foo
+        DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
+            private PathMatcher matcher =
+                dir.getFileSystem().getNameMatcher("glob", "f*");
+            public boolean accept(Path file) {
+                return matcher.matches(file);
+            }
+        };
         Files.withDirectory(dir, filter, new FileAction<Path>() {
             public void invoke(Path entry) {
                 if (!entry.getName().equals(foo))
                     throw new RuntimeException("entry not expected");
             }
         });
-        filter = DirectoryStreamFilters.newCaseSensitiveGlobFilter("F*");
+
+        // check filtering: z* should not match any files
+        filter = new DirectoryStream.Filter<Path>() {
+            private PathMatcher matcher =
+                dir.getFileSystem().getNameMatcher("glob", "z*");
+            public boolean accept(Path file) {
+                return matcher.matches(file);
+            }
+        };
         Files.withDirectory(dir, filter, new FileAction<FileRef>() {
             public void invoke(FileRef entry) {
                 throw new RuntimeException("no matching entries expected");
--- a/test/java/nio/file/DirectoryStream/Filters.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/test/java/nio/file/DirectoryStream/Filters.java	Mon Oct 20 19:20:24 2008 +0100
@@ -21,12 +21,6 @@
  * have any questions.
  */
 
-/* @test
- * @bug 4313887
- * @summary Unit test for java.nio.file.DirectoryStreamFilters
- * @library ..
- */
-
 import java.nio.file.*;
 import java.io.*;
 import java.util.Random;
--- a/test/java/nio/file/Path/Misc.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/test/java/nio/file/Path/Misc.java	Mon Oct 20 19:20:24 2008 +0100
@@ -97,31 +97,32 @@
         /**
          * Test: This directory should readable and writable
          */
-        dir.checkAccess(Access.EXISTS);
-        dir.checkAccess(Access.READ);
-        dir.checkAccess(Access.WRITE);
+        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(Access.EXISTS);
+            doesNotExist.checkAccess();
             throw new RuntimeException("NoSuchFileException expected");
         } catch (NoSuchFileException x) {
         }
         try {
-            doesNotExist.checkAccess(Access.READ);
+            doesNotExist.checkAccess(AccessMode.READ);
             throw new RuntimeException("NoSuchFileException expected");
         } catch (NoSuchFileException x) {
         }
         try {
-            doesNotExist.checkAccess(Access.WRITE);
+            doesNotExist.checkAccess(AccessMode.WRITE);
             throw new RuntimeException("NoSuchFileException expected");
         } catch (NoSuchFileException x) {
         }
         try {
-            doesNotExist.checkAccess(Access.EXECUTE);
+            doesNotExist.checkAccess(AccessMode.EXECUTE);
             throw new RuntimeException("NoSuchFileException expected");
         } catch (NoSuchFileException x) {
         }
@@ -148,13 +149,13 @@
             view.setAcl(acl);
 
             try {
-                file.checkAccess(Access.WRITE);
+                file.checkAccess(AccessMode.WRITE);
                 throw new RuntimeException("AccessDeniedException expected");
             } catch (AccessDeniedException x) {
             }
 
             try {
-                file.checkAccess(Access.EXECUTE);
+                file.checkAccess(AccessMode.EXECUTE);
                 throw new RuntimeException("AccessDeniedException expected");
             } catch (AccessDeniedException x) {
             }
@@ -173,7 +174,7 @@
                 file.getFileAttributeView(DosFileAttributeView.class, true);
             dview.setReadOnly(true);
             try {
-                file.checkAccess(Access.WRITE);
+                file.checkAccess(AccessMode.WRITE);
                 throw new RuntimeException("AccessDeniedException expected");
             } catch (AccessDeniedException x) {
             }
@@ -183,7 +184,7 @@
             dview = dir.getFileAttributeView(DosFileAttributeView.class, true);
             boolean save = dview.readAttributes().isReadOnly();
             dview.setReadOnly(true);
-            dir.checkAccess(Access.WRITE);
+            dir.checkAccess(AccessMode.WRITE);
             dview.setReadOnly(save);
         }
 
@@ -191,7 +192,7 @@
          * Test: null
          */
         try {
-            file.checkAccess(null);
+            file.checkAccess((AccessMode)null);
             throw new RuntimeException("NullPointerException expected");
         } catch (NullPointerException ignore) { }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/file/attribute/FileStoreAttributeView/Basic.java	Mon Oct 20 19:20:24 2008 +0100
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2007-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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4313887
+ * @summary Unit test for java.nio.file.attribute.FileStoreAttributeView
+ * @library ../..
+ */
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Simple unit test for FileStoreAttributeView that checks that the disk space
+ * attribtues are "close" to the equivalent values reported by java.io.File.
+ */
+
+public class Basic {
+
+    static final long K = 1024L;
+    static final long G = 1024L * 1024L * 1024L;
+
+    /**
+     * Print out the disk space information for the given file system
+     */
+    static void printFileStore(FileStore fs) throws IOException {
+        FileStoreSpaceAttributeView view =
+            fs.getFileStoreAttributeView(FileStoreSpaceAttributeView.class);
+        FileStoreSpaceAttributes attrs = view.readAttributes();
+
+        long total = attrs.totalSpace() / K;
+        long used = (attrs.totalSpace() - attrs.unallocatedSpace()) / K;
+        long avail = attrs.usableSpace() / K;
+
+        String s = fs.toString();
+        if (s.length() > 20) {
+            System.out.println(s);
+            s = "";
+        }
+        System.out.format("%-20s %12d %12d %12d\n", s, total, used, avail);
+    }
+
+    /**
+     * Check that two values are within 1GB of each other
+     */
+    static void checkWithin1GB(long value1, long value2) {
+        long diff = Math.abs(value1 - value2);
+        if (diff > G)
+            throw new RuntimeException("values differ by more than 1GB");
+    }
+
+    /**
+     * Check disk space on the file system of the given file
+     */
+    static void checkSpace(Path file) throws IOException {
+        System.out.println(" -- check space -- ");
+        System.out.println(file);
+
+        FileStore fs = file.getFileStore();
+        System.out.format("Filesystem: %s\n", fs);
+
+        // get values reported by java.io.File
+        File f = new File(file.toString());
+        long total = f.getTotalSpace();
+        long free = f.getFreeSpace();
+        long usable = f.getUsableSpace();
+        System.out.println("java.io.File");
+        System.out.format("    Total: %d\n", total);
+        System.out.format("     Free: %d\n", free);
+        System.out.format("   Usable: %d\n", usable);
+
+        // get values reported by the FileStoreSpaceAttributeView
+        FileStoreSpaceAttributes attrs = fs
+            .getFileStoreAttributeView(FileStoreSpaceAttributeView.class)
+            .readAttributes();
+        System.out.println("java.nio.file.FileStoreSpaceAttributeView:");
+        System.out.format("    Total: %d\n", attrs.totalSpace());
+        System.out.format("     Free: %d\n", attrs.unallocatedSpace());
+        System.out.format("   Usable: %d\n", attrs.usableSpace());
+
+        // check values are "close"
+        checkWithin1GB(total, attrs.totalSpace());
+        checkWithin1GB(free, attrs.unallocatedSpace());
+        checkWithin1GB(usable, attrs.usableSpace());
+
+        // get values by name (and in bulk)
+        FileStoreAttributeView view = fs.getFileStoreAttributeView("space");
+        checkWithin1GB(total, (Long)view.getAttribute("totalSpace"));
+        checkWithin1GB(free, (Long)view.getAttribute("unallocatedSpace"));
+        checkWithin1GB(usable, (Long)view.getAttribute("usableSpace"));
+        Map<String,?> map = view.readAttributes("*");
+        checkWithin1GB(total, (Long)map.get("totalSpace"));
+        checkWithin1GB(free, (Long)map.get("unallocatedSpace"));
+        checkWithin1GB(usable, (Long)map.get("usableSpace"));
+        map = view.readAttributes("totalSpace", "unallocatedSpace", "usableSpace");
+        checkWithin1GB(total, (Long)map.get("totalSpace"));
+        checkWithin1GB(free, (Long)map.get("unallocatedSpace"));
+        checkWithin1GB(usable, (Long)map.get("usableSpace"));
+    }
+
+    /**
+     * Check (Windows-specific) volume attributes
+     */
+    static void checkVolumeAttributes() throws IOException {
+        System.out.println(" -- volumes -- ");
+        for (FileStore store: FileSystems.getDefault().getFileStores()) {
+            FileStoreAttributeView view = store.getFileStoreAttributeView("volume");
+            if (view == null)
+                continue;
+            Map<String,?> attrs = view.readAttributes("*");
+            int vsn = (Integer)attrs.get("vsn");
+            boolean compressed = (Boolean)attrs.get("compressed");
+            System.out.format("%s vsn:%x compressed:%b%n", store.name(),
+                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");
+            file.newOutputStream().close();
+            try {
+                checkSpace(file);
+            } finally {
+                file.delete(false);
+            }
+
+            // volume attributes (Windows specific)
+            checkVolumeAttributes();
+
+        } finally {
+            TestUtil.removeAll(dir);
+        }
+    }
+}
--- a/test/java/nio/file/attribute/FileStoreSpaceAttributeView/Basic.java	Mon Oct 20 11:19:56 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +0,0 @@
-/*
- * Copyright 2007-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
- * 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.FileStoreSpaceAttributeView
- * @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 FileStoreSpaceAttributeView that checks that the disk space
- * attribtues are "close" to the equivalent values reported by java.io.File.
- */
-
-public class Basic {
-
-    static final long K = 1024L;
-    static final long G = 1024L * 1024L * 1024L;
-
-    /**
-     * Print out the disk space information for the given file system
-     */
-    static void printFileStore(FileStore fs) throws IOException {
-        FileStoreSpaceAttributeView view =
-            fs.getFileStoreAttributeView(FileStoreSpaceAttributeView.class);
-        FileStoreSpaceAttributes attrs = view.readAttributes();
-
-        long total = attrs.totalSpace() / K;
-        long used = (attrs.totalSpace() - attrs.unallocatedSpace()) / K;
-        long avail = attrs.usableSpace() / K;
-
-        String s = fs.toString();
-        if (s.length() > 20) {
-            System.out.println(s);
-            s = "";
-        }
-        System.out.format("%-20s %12d %12d %12d\n", s, total, used, avail);
-    }
-
-    /**
-     * Check that two values are within 1GB of each other
-     */
-    static void checkWithin1GB(long value1, long value2) {
-        long diff = Math.abs(value1 - value2);
-        if (diff > G)
-            throw new RuntimeException("values differ by more than 1GB");
-    }
-
-    /**
-     * Check disk space on the file system of the given file
-     */
-    static void checkSpace(Path file) throws IOException {
-        System.out.println(" -- check space -- ");
-        System.out.println(file);
-
-        FileStore fs = file.getFileStore();
-        System.out.format("Filesystem: %s\n", fs);
-
-        // get values reported by java.io.File
-        File f = new File(file.toString());
-        long total = f.getTotalSpace();
-        long free = f.getFreeSpace();
-        long usable = f.getUsableSpace();
-        System.out.println("java.io.File");
-        System.out.format("    Total: %d\n", total);
-        System.out.format("     Free: %d\n", free);
-        System.out.format("   Usable: %d\n", usable);
-
-        // get values reported by the FileStoreSpaceAttributeView
-        FileStoreSpaceAttributes attrs = fs
-            .getFileStoreAttributeView(FileStoreSpaceAttributeView.class)
-            .readAttributes();
-        System.out.println("java.nio.file.FileStoreSpaceAttributeView:");
-        System.out.format("    Total: %d\n", attrs.totalSpace());
-        System.out.format("     Free: %d\n", attrs.unallocatedSpace());
-        System.out.format("   Usable: %d\n", attrs.usableSpace());
-
-        // check values are "close"
-        checkWithin1GB(total, attrs.totalSpace());
-        checkWithin1GB(free, attrs.unallocatedSpace());
-        checkWithin1GB(usable, attrs.usableSpace());
-
-        // get values by name (and in bulk)
-        FileStoreAttributeView view = fs.getFileStoreAttributeView("space");
-        checkWithin1GB(total, (Long)view.getAttribute("totalSpace"));
-        checkWithin1GB(free, (Long)view.getAttribute("unallocatedSpace"));
-        checkWithin1GB(usable, (Long)view.getAttribute("usableSpace"));
-        Map<String,?> map = view.readAttributes("*");
-        checkWithin1GB(total, (Long)map.get("totalSpace"));
-        checkWithin1GB(free, (Long)map.get("unallocatedSpace"));
-        checkWithin1GB(usable, (Long)map.get("usableSpace"));
-        map = view.readAttributes("totalSpace", "unallocatedSpace", "usableSpace");
-        checkWithin1GB(total, (Long)map.get("totalSpace"));
-        checkWithin1GB(free, (Long)map.get("unallocatedSpace"));
-        checkWithin1GB(usable, (Long)map.get("usableSpace"));
-    }
-
-    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");
-            file.newOutputStream().close();
-            try {
-                checkSpace(file);
-            } finally {
-                file.delete(false);
-            }
-
-        } finally {
-            TestUtil.removeAll(dir);
-        }
-    }
-}
--- a/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java	Mon Oct 20 11:19:56 2008 +0100
+++ b/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java	Mon Oct 20 19:20:24 2008 +0100
@@ -255,18 +255,6 @@
             view.setAttribute("owner", map.get("owner"));
             view.setAttribute("group", map.get("group"));
 
-            // IllegalArgumentException
-            try {
-                view.setOwner(attrs.group());
-                throw new RuntimeException("IllegalArgumentException not thrown");
-            } catch (IllegalArgumentException x) {
-            }
-            try {
-                view.setGroup(attrs.owner());
-                throw new RuntimeException("IllegalArgumentException not thrown");
-            } catch (IllegalArgumentException x) {
-            }
-
         } finally {
             file.delete(false);
         }
@@ -292,7 +280,7 @@
         System.out.format("lookup: %s\n", attrs.owner().getName());
         try {
             UserPrincipal owner = lookupService.lookupPrincipalByName(attrs.owner().getName());
-            if (owner.isGroup())
+            if (owner instanceof GroupPrincipal)
                 throw new RuntimeException("owner is a group?");
             if (!owner.equals(attrs.owner()))
                 throw new RuntimeException("owner different from file owner");
@@ -303,9 +291,7 @@
         // lookup group and check it matches file's group-owner
         System.out.format("lookup group: %s\n", attrs.group().getName());
         try {
-            UserPrincipal group = lookupService.lookupPrincipalByGroupName(attrs.group().getName());
-            if (!group.isGroup())
-                throw new RuntimeException("group is not a group?");
+            GroupPrincipal group = lookupService.lookupPrincipalByGroupName(attrs.group().getName());
             if (!group.equals(attrs.group()))
                 throw new RuntimeException("group different from file group-owner");
         } catch (UserPrincipalNotFoundException x) {