changeset 1366:9923df826001

Ensure NIO2 is in sync with the latest build drop, b98. 2009-02-05 Andrew John Hughes <ahughes@redhat.com> Ensure the NIO2 code is in sync with the latest build drop, b98. * overlays/nio2/openjdk/jdk/src/share/classes/org/classpath/icedtea/java/nio/file/attribute/NamedAttributeView.java, * overlays/nio2/openjdk/jdk/src/share/classes/sun/nio/fs/AbstractNamedAttributeView.java, * overlays/nio2/openjdk/jdk/src/share/classes/sun/nio/fs/Cancellable.java, * overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java, * overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java, * overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java, * overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java, * overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileCopy.java, * overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java, * overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java, * overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java, * overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsNamedAttributeView.java, * overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java, * overlays/nio2/openjdk/jdk/test/org/classpath/icedtea/java/nio/file/Path/InterruptCopy.java, * overlays/nio2/openjdk/jdk/test/org/classpath/icedtea/java/nio/file/attribute/NamedAttributeView/Basic.java,
author Andrew John Hughes <ahughes@redhat.com>
date Thu, 05 Feb 2009 19:03:06 +0000
parents b0be146027ad
children d31f7236fd89
files ChangeLog overlays/nio2/openjdk/jdk/src/share/classes/org/classpath/icedtea/java/nio/file/attribute/NamedAttributeView.java overlays/nio2/openjdk/jdk/src/share/classes/sun/nio/fs/AbstractNamedAttributeView.java overlays/nio2/openjdk/jdk/src/share/classes/sun/nio/fs/Cancellable.java overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileCopy.java overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsNamedAttributeView.java overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java overlays/nio2/openjdk/jdk/test/org/classpath/icedtea/java/nio/file/Path/InterruptCopy.java overlays/nio2/openjdk/jdk/test/org/classpath/icedtea/java/nio/file/attribute/NamedAttributeView/Basic.java
diffstat 16 files changed, 460 insertions(+), 321 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Feb 04 12:48:30 2009 +0000
+++ b/ChangeLog	Thu Feb 05 19:03:06 2009 +0000
@@ -1,3 +1,23 @@
+2009-02-05  Andrew John Hughes  <ahughes@redhat.com>
+
+	Ensure the NIO2 code is in sync with the latest
+	build drop, b98.
+	* overlays/nio2/openjdk/jdk/src/share/classes/org/classpath/icedtea/java/nio/file/attribute/NamedAttributeView.java,
+	* overlays/nio2/openjdk/jdk/src/share/classes/sun/nio/fs/AbstractNamedAttributeView.java,
+	* overlays/nio2/openjdk/jdk/src/share/classes/sun/nio/fs/Cancellable.java,
+	* overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java,
+	* overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java,
+	* overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java,
+	* overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java,
+	* overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileCopy.java,
+	* overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java,
+	* overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java,
+	* overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java,
+	* overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsNamedAttributeView.java,
+	* overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java,
+	* overlays/nio2/openjdk/jdk/test/org/classpath/icedtea/java/nio/file/Path/InterruptCopy.java,
+	* overlays/nio2/openjdk/jdk/test/org/classpath/icedtea/java/nio/file/attribute/NamedAttributeView/Basic.java,
+
 2009-02-04  Andrew John Hughes  <ahughes@redhat.com>
 
 	* acinclude.m4:
--- a/overlays/nio2/openjdk/jdk/src/share/classes/org/classpath/icedtea/java/nio/file/attribute/NamedAttributeView.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/src/share/classes/org/classpath/icedtea/java/nio/file/attribute/NamedAttributeView.java	Thu Feb 05 19:03:06 2009 +0000
@@ -48,9 +48,6 @@
  * intended for use where the size of an attribute value is larger than {@link
  * Integer#MAX_VALUE}.
  *
- * <p> {@note There has been feedback that the read/write methods should use byte
- * arrays instead of ByteBuffers.}
- *
  * <p> Named attributes may be used in some implementations to store security
  * related attributes so consequently, in the case of the default provider at
  * least, all methods that access named attributes require the
@@ -64,13 +61,10 @@
  * <p> Where dynamic access to file attributes is required, the {@link
  * #getAttribute getAttribute} or {@link #readAttributes(String,String[])
  * readAttributes(String,String[])} methods may be used to read the attribute
- * value as if by invoking the {@link #read read} method. Upon return, the
- * buffer's {@link ByteBuffer#position position} is the index of the first
- * byte of the attribute value, and its {@link ByteBuffer#limit limit} is
- * the index of the first byte that should not be read. The {@link
+ * value. The attribute value is returned as a byte array (byte[]). The {@link
  * #setAttribute setAttribute} method may be used to write the value of a
- * user-defined/named attribute from a buffer as if by invoking the {@link
- * #write write} method.
+ * user-defined/named attribute from a buffer (as if by invoking the {@link
+ * #write write} method), or byte array (byte[]).
  *
  * @since 1.7
  */
--- a/overlays/nio2/openjdk/jdk/src/share/classes/sun/nio/fs/AbstractNamedAttributeView.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/src/share/classes/sun/nio/fs/AbstractNamedAttributeView.java	Thu Feb 05 19:03:06 2009 +0000
@@ -62,18 +62,31 @@
 
 
     public final Object getAttribute(String attribute) throws IOException {
-        int size = size(attribute);
-        ByteBuffer buf = ByteBuffer.allocate(size);
-        read(attribute, buf);
-        buf.flip();
-        return buf;
+         int size;
+         try {
+             size = size(attribute);
+         } catch (IOException e) {
+             // not found or some other I/O error
+             if (list().contains(attribute))
+                 throw e;
+             return null;
+         }
+         byte[] buf = new byte[size];
+         int n = read(attribute, ByteBuffer.wrap(buf));
+         return (n == size) ? buf : Arrays.copyOf(buf, n);
     }
 
 
     public final void setAttribute(String attribute, Object value)
         throws IOException
     {
-        write(attribute, (ByteBuffer)value);
+         ByteBuffer bb;
+         if (value instanceof byte[]) {
+             bb = ByteBuffer.wrap((byte[])value);
+         } else {
+             bb = (ByteBuffer)value;
+         }
+         write(attribute, bb);
     }
 
 
@@ -88,29 +101,23 @@
             readAll = true;
         } else {
             names.add(first);
-            for (String name: rest) {
-                if (name.equals("*")) {
-                    readAll = true;
-                    break;
-                }
+        }
+        for (String name: rest) {
+            if (name.equals("*")) {
+                readAll = true;
+            } else {
                 names.add(name);
             }
         }
-        if (readAll) {
-            names.clear();
-            for (String name: list()) {
-                names.add(name);
-            }
-        }
+        if (readAll)
+            names = list();
 
-        // allocate buffer for each value and return as map
-        Map<String,ByteBuffer> result = new HashMap<String,ByteBuffer>();
+        // read each value and return in map
+        Map<String,Object> result = new HashMap<String,Object>();
         for (String name: names) {
-            int size = size(name);
-            ByteBuffer buf = ByteBuffer.allocate(size);
-            read(name, buf);
-            result.put(name, buf);
-            buf.flip();
+            Object value = getAttribute(name);
+            if (value != null)
+                result.put(name, value);
         }
 
         return result;
--- a/overlays/nio2/openjdk/jdk/src/share/classes/sun/nio/fs/Cancellable.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/src/share/classes/sun/nio/fs/Cancellable.java	Thu Feb 05 19:03:06 2009 +0000
@@ -112,21 +112,24 @@
     abstract void implRun() throws Throwable;
 
     /**
-     * Invokes the task in its own thread. If this (meaning the current) thread
-     * is interrupted then an attempt is make to cancel the background task by
-     * writting bits into the memory location that it is polling. On return,
-     * the interrupt status for this thread has been cleared.
+     * Invokes the given task in its own thread. If this (meaning the current)
+     * thread is interrupted then an attempt is make to cancel the background
+     * thread by writing into the memory location that it polls cooperatively.
      */
     static void runInterruptibly(Cancellable task) throws ExecutionException {
         Thread t = new Thread(task);
         t.start();
+        boolean cancelledByInterrupt = false;
         while (t.isAlive()) {
             try {
                 t.join();
             } catch (InterruptedException e) {
+                cancelledByInterrupt = true;
                 task.cancel();
             }
         }
+        if (cancelledByInterrupt)
+            Thread.currentThread().interrupt();
         Throwable exc = task.exception();
         if (exc != null)
             throw new ExecutionException(exc);
--- a/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java	Thu Feb 05 19:03:06 2009 +0000
@@ -117,8 +117,7 @@
 
         // GetFileSecurity does not follow links so when following links we
         // need the final target
-        String path = followLinks ? WindowsLinkSupport.getFinalPath(file) :
-                                    file.getPathForWin32Calls();
+        String path = WindowsLinkSupport.getFinalPath(file, followLinks);
         NativeBuffer buffer = getFileSecurity(path, OWNER_SECURITY_INFORMATION);
         try {
             // get the address of the SID
@@ -142,8 +141,7 @@
 
         // GetFileSecurity does not follow links so when following links we
         // need the final target
-        String path = followLinks ? WindowsLinkSupport.getFinalPath(file) :
-                                    file.getPathForWin32Calls();
+        String path = WindowsLinkSupport.getFinalPath(file, followLinks);
 
         // ALLOW and DENY entries in DACL;
         // AUDIT entries in SACL (ignore for now as it requires privileges)
@@ -170,8 +168,7 @@
 
         // SetFileSecurity does not follow links so when following links we
         // need the final target
-        String path = followLinks ? WindowsLinkSupport.getFinalPath(file) :
-                                    file.getPathForWin32Calls();
+        String path = WindowsLinkSupport.getFinalPath(file, followLinks);
 
         // ConvertStringSidToSid allocates memory for SID so must invoke
         // LocalFree to free it when we are done
@@ -216,9 +213,7 @@
 
         // SetFileSecurity does not follow links so when following links we
         // need the final target
-        String path = followLinks ? WindowsLinkSupport.getFinalPath(file) :
-                                    file.getPathForWin32Calls();
-
+        String path = WindowsLinkSupport.getFinalPath(file, followLinks);
         WindowsSecurityDescriptor sd = WindowsSecurityDescriptor.create(acl);
         try {
             SetFileSecurity(path, DACL_SECURITY_INFORMATION, sd.address());
--- a/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsChannelFactory.java	Thu Feb 05 19:03:06 2009 +0000
@@ -56,7 +56,76 @@
      * Do not follow reparse points when opening an existing file. Do not fail
      * if the file is a reparse point.
      */
-    static final OpenOption NOFOLLOW_REPARSEPOINT = new OpenOption() { };
+    static final OpenOption OPEN_REPARSE_POINT = new OpenOption() { };
+
+    /**
+     * Represents the flags from a user-supplied set of open options.
+     */
+    private static class Flags {
+        boolean read;
+        boolean write;
+        boolean append;
+        boolean truncateExisting;
+        boolean create;
+        boolean createNew;
+        boolean deleteOnClose;
+        boolean sparse;
+        boolean overlapped;
+        boolean sync;
+        boolean dsync;
+
+        // non-standard
+        boolean shareRead = true;
+        boolean shareWrite = true;
+        boolean shareDelete = true;
+        boolean noFollowLinks;
+        boolean openReparsePoint;
+
+        static Flags toFlags(Set<? extends OpenOption> options) {
+            Flags flags = new Flags();
+            for (OpenOption option: options) {
+                if (!(option instanceof StandardOpenOption)) {
+                    if (option == ExtendedOpenOption.NOSHARE_READ) {
+                        flags.shareRead = false;
+                        continue;
+                    }
+                    if (option == ExtendedOpenOption.NOSHARE_WRITE) {
+                        flags.shareWrite = false;
+                        continue;
+                    }
+                    if (option == ExtendedOpenOption.NOSHARE_DELETE) {
+                        flags.shareDelete = false;
+                        continue;
+                    }
+                    if (option == LinkOption.NOFOLLOW_LINKS) {
+                        flags.noFollowLinks = true;
+                        continue;
+                    }
+                    if (option == OPEN_REPARSE_POINT) {
+                        flags.openReparsePoint = true;
+                        continue;
+                    }
+                    if (option == null)
+                        throw new NullPointerException();
+                    throw new UnsupportedOperationException("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 TRUNCATE_EXISTING : flags.truncateExisting = true; break;
+                    case CREATE : flags.create = true; break;
+                    case CREATE_NEW : flags.createNew = true; break;
+                    case DELETE_ON_CLOSE : flags.deleteOnClose = true; break;
+                    case SPARSE : flags.sparse = true; break;
+                    case SYNC : flags.sync = true; break;
+                    case DSYNC : flags.dsync = true; break;
+                    default: throw new AssertionError("Should not get here");
+                }
+            }
+            return flags;
+        }
+    }
 
     /**
      * Open/creates file, returning FileChannel to access the file
@@ -72,50 +141,25 @@
                                       long pSecurityDescriptor)
         throws WindowsException
     {
-        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;
-            }
-            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) &&
-                !(flag instanceof ExtendedOpenOption))
-            {
-                throw new UnsupportedOperationException("Unsupported open option");
+        // default is reading; append => writing
+        if (!flags.read && !flags.write) {
+            if (flags.append) {
+                flags.write = true;
+            } else {
+                flags.read = true;
             }
         }
 
-        // 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(pathForWindows, pathToCheck, reading, writing,
-            append, false, options, pSecurityDescriptor);
-        return FileChannelImpl.open(fdObj, reading, writing, null);
+        FileDescriptor fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor);
+        return FileChannelImpl.open(fdObj, flags.read, flags.write, null);
     }
 
     /**
@@ -135,38 +179,24 @@
                                                               ThreadPool pool)
         throws IOException
     {
-        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) &&
-                !(flag instanceof ExtendedOpenOption))
-            {
-                throw new UnsupportedOperationException("Unsupported open option");
-            }
-            if (flag == StandardOpenOption.APPEND)
-                throw new UnsupportedOperationException("'APPEND' not supported");
+        // Overlapped I/O required
+        flags.overlapped = true;
+
+        // default is reading
+        if (!flags.read && !flags.write) {
+            flags.read = true;
         }
 
-        // default is reading
-        if (!reading && !writing) {
-            reading = true;
-        }
+        // validation
+        if (flags.append)
+            throw new UnsupportedOperationException("APPEND not allowed");
 
         // open file for overlapped I/O
         FileDescriptor fdObj;
         try {
-            fdObj = open(pathForWindows, pathToCheck, reading, writing, false,
-                         true, options, pSecurityDescriptor);
+            fdObj = open(pathForWindows, pathToCheck, flags, pSecurityDescriptor);
         } catch (WindowsException x) {
             x.rethrowAsIOException(pathForWindows);
             return null;
@@ -174,7 +204,7 @@
 
         // create the AsynchronousFileChannel
         try {
-            return WindowsAsynchronousFileChannelImpl.open(fdObj, reading, writing, pool);
+            return WindowsAsynchronousFileChannelImpl.open(fdObj, flags.read, flags.write, pool);
         } catch (IOException x) {
             // IOException is thrown if the file handle cannot be associated
             // with the completion port. All we can do is close the file.
@@ -190,11 +220,7 @@
      */
     private static FileDescriptor open(String pathForWindows,
                                        String pathToCheck,
-                                       boolean reading,
-                                       boolean writing,
-                                       boolean append,
-                                       boolean overlapped,
-                                       Set<? extends OpenOption> options,
+                                       Flags flags,
                                        long pSecurityDescriptor)
         throws WindowsException
     {
@@ -203,30 +229,30 @@
 
         // map options
         int dwDesiredAccess = 0;
-        if (reading)
+        if (flags.read)
             dwDesiredAccess |= GENERIC_READ;
-        if (writing)
-            dwDesiredAccess |= (append) ? FILE_APPEND_DATA : GENERIC_WRITE;
+        if (flags.write)
+            dwDesiredAccess |= (flags.append) ? FILE_APPEND_DATA : GENERIC_WRITE;
 
         int dwShareMode = 0;
-        if (!options.contains(ExtendedOpenOption.NOSHARE_READ))
+        if (flags.shareRead)
             dwShareMode |= FILE_SHARE_READ;
-        if (!options.contains(ExtendedOpenOption.NOSHARE_WRITE))
+        if (flags.shareWrite)
             dwShareMode |= FILE_SHARE_WRITE;
-        if (!options.contains(ExtendedOpenOption.NOSHARE_DELETE))
+        if (flags.shareDelete)
             dwShareMode |= FILE_SHARE_DELETE;
 
         int dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
         int dwCreationDisposition = OPEN_EXISTING;
-        if (writing) {
-            if (options.contains(StandardOpenOption.CREATE_NEW)) {
+        if (flags.write) {
+            if (flags.createNew) {
                 dwCreationDisposition = CREATE_NEW;
                 // force create to fail if file is orphaned reparse point
                 dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
             } else {
-                if (options.contains(StandardOpenOption.CREATE))
+                if (flags.create)
                     dwCreationDisposition = OPEN_ALWAYS;
-                if (options.contains(StandardOpenOption.TRUNCATE_EXISTING)) {
+                if (flags.truncateExisting) {
                     // Windows doesn't have a creation disposition that exactly
                     // corresponds to CREATE + TRUNCATE_EXISTING so we use
                     // the OPEN_ALWAYS mode and then truncate the file.
@@ -239,23 +265,21 @@
             }
         }
 
-        if (options.contains(StandardOpenOption.DSYNC) || options.contains(StandardOpenOption.SYNC))
+        if (flags.dsync || flags.sync)
             dwFlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
-        if (overlapped)
+        if (flags.overlapped)
             dwFlagsAndAttributes |= FILE_FLAG_OVERLAPPED;
-
-        boolean deleteOnClose = options.contains(StandardOpenOption.DELETE_ON_CLOSE);
-        if (deleteOnClose)
+        if (flags.deleteOnClose)
             dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
 
         // NOFOLLOW_LINKS and NOFOLLOW_REPARSEPOINT mean open reparse point
         boolean okayToFollowLinks = true;
         if (dwCreationDisposition != CREATE_NEW &&
-            (options.contains(LinkOption.NOFOLLOW_LINKS) ||
-             options.contains(NOFOLLOW_REPARSEPOINT) ||
-             deleteOnClose))
+            (flags.noFollowLinks ||
+             flags.openReparsePoint ||
+             flags.deleteOnClose))
         {
-            if (options.contains(LinkOption.NOFOLLOW_LINKS))
+            if (flags.noFollowLinks)
                 okayToFollowLinks = false;
             dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
         }
@@ -264,11 +288,11 @@
         if (pathToCheck != null) {
             SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
-                if (reading)
+                if (flags.read)
                     sm.checkRead(pathToCheck);
-                if (writing)
+                if (flags.write)
                     sm.checkWrite(pathToCheck);
-                if (deleteOnClose)
+                if (flags.deleteOnClose)
                     sm.checkDelete(pathToCheck);
             }
         }
@@ -308,9 +332,7 @@
         }
 
         // make the file sparse if needed
-        if (dwCreationDisposition == CREATE_NEW &&
-            options.contains(StandardOpenOption.SPARSE))
-        {
+        if (dwCreationDisposition == CREATE_NEW && flags.sparse) {
             try {
                 DeviceIoControlSetSparse(handle);
             } catch (WindowsException x) {
--- a/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java	Thu Feb 05 19:03:06 2009 +0000
@@ -62,16 +62,16 @@
         this.dir = dir;
         this.filter = filter;
 
-        // Need to append * or \* to match entries in directory.
-        String search = dir.getPathForWin32Calls();
-        char last = search.charAt(search.length() -1);
-        if (last == ':' || last == '\\') {
-            search += "*";
-        } else {
-            search += "\\*";
-        }
+        try {
+            // Need to append * or \* to match entries in directory.
+            String search = dir.getPathForWin32Calls();
+            char last = search.charAt(search.length() -1);
+            if (last == ':' || last == '\\') {
+                search += "*";
+            } else {
+                search += "\\*";
+            }
 
-        try {
             FirstFile first = FindFirstFile(search);
             this.handle = first.handle();
             this.firstName = first.name();
--- a/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java	Thu Feb 05 19:03:06 2009 +0000
@@ -226,9 +226,7 @@
 
             // GetFileAttribtues & SetFileAttributes do not follow links so when
             // following links we need the final target
-            String path = followLinks ? WindowsLinkSupport.getFinalPath(file) :
-                                        file.getPathForWin32Calls();
-
+            String path = WindowsLinkSupport.getFinalPath(file, followLinks);
             try {
                 int oldValue = GetFileAttributes(path);
                 int newValue = oldValue;
--- a/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileCopy.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileCopy.java	Thu Feb 05 19:03:06 2009 +0000
@@ -144,8 +144,8 @@
             sm.checkPermission(new LinkPermission("symbolic"));
         }
 
-        final String sourcePath = source.getPathForWin32Calls();
-        final String targetPath = target.getPathForWin32Calls();
+        final String sourcePath = asWin32Path(source);
+        final String targetPath = asWin32Path(target);
 
         // if target exists then delete it.
         if (targetAttrs != null) {
@@ -288,8 +288,8 @@
             target.checkWrite();
         }
 
-        String sourcePath = source.getPathForWin32Calls();
-        String targetPath = target.getPathForWin32Calls();
+        final String sourcePath = asWin32Path(source);
+        final String targetPath = asWin32Path(target);
 
         // atomic case
         if (atomicMove) {
@@ -468,6 +468,16 @@
         }
     }
 
+
+    private static String asWin32Path(WindowsPath path) throws IOException {
+        try {
+            return path.getPathForWin32Calls();
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(path);
+            return null;
+        }
+    }
+
     /**
      * Copy DACL/owner/group from source to target
      */
@@ -476,8 +486,7 @@
                                                boolean followLinks)
         throws IOException
     {
-        String path = followLinks ?
-            WindowsLinkSupport.getFinalPath(source) : source.getPathForWin32Calls();
+        String path = WindowsLinkSupport.getFinalPath(source, followLinks);
 
         // may need SeRestorePrivilege to set file owner
         WindowsSecurity.Privilege priv =
--- a/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java	Thu Feb 05 19:03:06 2009 +0000
@@ -84,11 +84,11 @@
             // final target
             String target;
             if (file.getFileSystem().supportsLinks()) {
-                target = WindowsLinkSupport.getFinalPath(file);
+                target = WindowsLinkSupport.getFinalPath(file, true);
             } else {
                 // file must exist
                 WindowsFileAttributes.get(file, true);
-                target = file.toString();
+                target = file.getPathForWin32Calls();
             }
             String root = GetVolumePathName(target);
             return new WindowsFileStore(root, file.getPathForPermissionCheck());
--- a/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java	Thu Feb 05 19:03:06 2009 +0000
@@ -137,6 +137,9 @@
                                             options,
                                             sd.address(),
                                             pool);
+        } catch (WindowsException x) {
+            x.rethrowAsIOException(file);
+            return null;
         } finally {
             if (sd != null)
                 sd.release();
--- a/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java	Thu Feb 05 19:03:06 2009 +0000
@@ -66,13 +66,17 @@
      * Returns the final path of a given path as a String. This should be used
      * prior to calling Win32 system calls that do not follow links.
      */
-    static String getFinalPath(WindowsPath input) throws IOException {
+    static String getFinalPath(WindowsPath input, boolean followLinks)
+        throws IOException
+    {
         WindowsFileSystem fs = input.getFileSystem();
-        if (!fs.supportsLinks())
-            return input.getPathForWin32Calls();
 
-        // if the file is not a sym link then return the path to access the file
         try {
+            // if not following links then don't need final path
+            if (!followLinks || !fs.supportsLinks())
+                return input.getPathForWin32Calls();
+
+            // if file is a sym link then don't need final path
             if (!WindowsFileAttributes.get(input, false).isSymbolicLink()) {
                 return input.getPathForWin32Calls();
             }
--- a/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsNamedAttributeView.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsNamedAttributeView.java	Thu Feb 05 19:03:06 2009 +0000
@@ -51,7 +51,7 @@
             throw new NullPointerException("'name' is null");
         return file + ":" + name;
     }
-    private String join(WindowsPath file, String name) {
+    private String join(WindowsPath file, String name) throws WindowsException {
         return join(file.getPathForWin32Calls(), name);
     }
 
@@ -219,11 +219,11 @@
             Set<OpenOption> opts = new HashSet<OpenOption>();
             opts.add(READ);
             if (!followLinks)
-                opts.add(WindowsChannelFactory.NOFOLLOW_REPARSEPOINT);
+                opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);
             fc = WindowsChannelFactory
                 .newFileChannel(join(file, name), null, opts, 0L);
         } catch (WindowsException x) {
-            x.rethrowAsIOException(join(file, name));
+            x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));
         }
         try {
             long size = fc.size();
@@ -246,11 +246,11 @@
             Set<OpenOption> opts = new HashSet<OpenOption>();
             opts.add(READ);
             if (!followLinks)
-                opts.add(WindowsChannelFactory.NOFOLLOW_REPARSEPOINT);
+                opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);
             fc = WindowsChannelFactory
                 .newFileChannel(join(file, name), null, opts, 0L);
         } catch (WindowsException x) {
-            x.rethrowAsIOException(join(file, name));
+            x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));
         }
 
         // read to EOF (nothing we can do if I/O error occurs)
@@ -300,7 +300,7 @@
         try {
             Set<OpenOption> opts = new HashSet<OpenOption>();
             if (!followLinks)
-                opts.add(WindowsChannelFactory.NOFOLLOW_REPARSEPOINT);
+                opts.add(WindowsChannelFactory.OPEN_REPARSE_POINT);
             opts.add(CREATE);
             opts.add(WRITE);
             opts.add(StandardOpenOption.TRUNCATE_EXISTING);
@@ -309,7 +309,7 @@
                 named = WindowsChannelFactory
                     .newFileChannel(join(file, name), null, opts, 0L);
             } catch (WindowsException x) {
-                x.rethrowAsIOException(join(file, name));
+                x.rethrowAsIOException(join(file.getPathForPermissionCheck(), name));
             }
             // write value (nothing we can do if I/O error occurs)
             try {
@@ -331,8 +331,8 @@
         if (System.getSecurityManager() != null)
             checkAccess(file.getPathForPermissionCheck(), false, true);
 
-        String toDelete = followLinks ?
-            join(WindowsLinkSupport.getFinalPath(file), name) : join(file, name);
+        String path = WindowsLinkSupport.getFinalPath(file, followLinks);
+        String toDelete = join(path, name);
         try {
             DeleteFile(toDelete);
         } catch (WindowsException x) {
--- a/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java	Thu Feb 05 19:03:06 2009 +0000
@@ -33,6 +33,7 @@
 import java.net.URI;
 import java.security.AccessController;
 import java.util.*;
+import java.lang.ref.WeakReference;
 
 import com.sun.nio.file.ExtendedWatchEventModifier;
 
@@ -49,6 +50,15 @@
 class WindowsPath extends AbstractPath {
     private static final Unsafe unsafe = Unsafe.getUnsafe();
 
+    // The maximum path that does not require long path prefix. On Windows
+    // the maximum path is 260 minus 1 (NUL) but for directories it is 260
+    // minus 12 minus 1 (to allow for the creation of a 8.3 file in the
+    // directory).
+    private static final int MAX_PATH = 247;
+
+    // Maximum extended-length path
+    private static final int MAX_LONG_PATH = 32000;
+
     // FIXME - eliminate this reference to reduce space
     private final WindowsFileSystem fs;
 
@@ -59,18 +69,15 @@
     // normalized path
     private final String path;
 
+    // the path to use in Win32 calls. This differs from path for relative
+    // paths and has a long path prefix for all paths longer than MAX_PATH.
+    private volatile WeakReference<String> pathForWin32Calls;
+
     // offsets into name components (computed lazily)
     private volatile Integer[] offsets;
 
-    // resolved against file system's default directory
-    private final String resolved;
-
-    // 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;
-
     // computed hash code (computed lazily, no need to be volatile)
-    private volatile int hash;
+    private int hash;
 
 
     /**
@@ -85,56 +92,6 @@
         this.type = type;
         this.root = root;
         this.path = path;
-
-        // resolve path against file system's default directory
-        switch (type) {
-            case ABSOLUTE :
-            case UNC :
-                this.resolved = path;
-                break;
-            case RELATIVE :
-                String defaultDirectory = getFileSystem().defaultDirectory();
-                if (defaultDirectory.endsWith("\\")) {
-                    this.resolved = defaultDirectory + path;
-                } else {
-                    this.resolved = defaultDirectory + "\\" + path;
-                }
-                break;
-            case DIRECTORY_RELATIVE:
-                String defaultRoot = getFileSystem().defaultRoot();
-                this.resolved = defaultRoot + path.substring(1);
-                break;
-            case DRIVE_RELATIVE:
-                // Need to postpone resolving these types of paths as they can
-                // change for the case of removable media devices when media
-                // is inserted or removed.
-                this.resolved = path;
-                break;
-            default:
-                throw new AssertionError();
-        }
-
-        // Long paths need to have "." and ".." removed and be prefixed with \\?\
-        // Note that it is okay to remove ".." even when it follows a link -
-        // for example, it is okay for foo/link/../bar to be changed to foo/bar.
-        // The reason is that Win32 APIs to access foo/link/../bar will access
-        // foo/bar anyway (which differs to Unix systems)
-        String ps = resolved;
-        if (ps.length() > 248) {
-            if (ps.length() > 32000) {
-                throw new InvalidPathException(ps,
-                    "Cannot access file with path exceeding 32000 characters");
-            }
-            try {
-                ps = GetFullPathName(ps);
-            } catch (WindowsException x) {
-                throw new AssertionError("GetFullPathName failed for '" + ps +
-                    "' " + x.getMessage());
-            }
-            ps = addPrefixIfNeeded(ps);
-        }
-
-        this.pathForWin32Calls = ps;
     }
 
     /**
@@ -165,12 +122,107 @@
 
     // use this path for permission checks
     String getPathForPermissionCheck() {
+        return path;
+    }
+
+    // use this path for Win32 calls
+    // This method will prefix long paths with \\?\ or \\?\UNC as required.
+    String getPathForWin32Calls() throws WindowsException {
+        // short absolute paths can be used directly
+        if (isAbsolute() && path.length() <= MAX_PATH)
+            return path;
+
+        // return cached values if available
+        WeakReference<String> ref = pathForWin32Calls;
+        String resolved = (ref != null) ? ref.get() : null;
+        if (resolved != null) {
+            // Win32 path already available
+            return resolved;
+        }
+
+        // resolve against default directory
+        resolved = getAbsolutePath();
+
+        // Long paths need to have "." and ".." removed and be prefixed with
+        // "\\?\". Note that it is okay to remove ".." even when it follows
+        // a link - for example, it is okay for foo/link/../bar to be changed
+        // to foo/bar. The reason is that Win32 APIs to access foo/link/../bar
+        // will access foo/bar anyway (which differs to Unix systems)
+        if (resolved.length() > MAX_PATH) {
+            if (resolved.length() > MAX_LONG_PATH) {
+                throw new WindowsException("Cannot access file with path exceeding "
+                    + MAX_LONG_PATH + " characters");
+            }
+            resolved = addPrefixIfNeeded(GetFullPathName(resolved));
+        }
+
+        // cache the resolved path (except drive relative paths as the working
+        // directory on removal media devices can change during the lifetime
+        // of the VM)
+        if (type != WindowsPathType.DRIVE_RELATIVE) {
+            synchronized (path) {
+                pathForWin32Calls = new WeakReference<String>(resolved);
+            }
+        }
         return resolved;
     }
 
-    // use this for calls into Windows (may have \\?\ or \\?\UNC prefix)
-    String getPathForWin32Calls() {
-        return pathForWin32Calls;
+    // return this path resolved against the file system's default directory
+    private String getAbsolutePath() throws WindowsException {
+        if (isAbsolute())
+            return path;
+
+        // Relative path ("foo" for example)
+        if (type == WindowsPathType.RELATIVE) {
+            String defaultDirectory = getFileSystem().defaultDirectory();
+            if (defaultDirectory.endsWith("\\")) {
+                return defaultDirectory + path;
+            } else {
+                StringBuilder sb =
+                    new StringBuilder(defaultDirectory.length() + path.length() + 1);
+                return sb.append(defaultDirectory).append('\\').append(path).toString();
+            }
+        }
+
+        // Directory relative path ("\foo" for example)
+        if (type == WindowsPathType.DIRECTORY_RELATIVE) {
+            String defaultRoot = getFileSystem().defaultRoot();
+            return defaultRoot + path.substring(1);
+        }
+
+        // Drive relative path ("C:foo" for example).
+        if (isSameDrive(root, getFileSystem().defaultRoot())) {
+            // relative to default directory
+            String remaining = path.substring(root.length());
+            String defaultDirectory = getFileSystem().defaultDirectory();
+            String result;
+            if (defaultDirectory.endsWith("\\")) {
+                result = defaultDirectory + remaining;
+            } else {
+                result = defaultDirectory + "\\" + remaining;
+            }
+            return result;
+        } else {
+            // relative to some other drive
+            String wd;
+            try {
+                int dt = GetDriveType(root + "\\");
+                if (dt == DRIVE_UNKNOWN || dt == DRIVE_NO_ROOT_DIR)
+                    throw new WindowsException("");
+                wd = GetFullPathName(root + ".");
+            } catch (WindowsException x) {
+                throw new WindowsException("Unable to get working directory of drive '" +
+                    Character.toUpperCase(root.charAt(0)) + "'");
+            }
+            String result = wd;
+            if (wd.endsWith("\\")) {
+                result += path.substring(root.length());
+            } else {
+                if (path.length() > root.length())
+                    result += "\\" + path.substring(root.length());
+            }
+            return result;
+        }
     }
 
     // Add long path prefix to path if required
@@ -727,9 +779,9 @@
      */
     private int getEffectiveAccess() throws IOException {
         // read security descriptor continaing ACL (symlinks are followed)
-        String fp = WindowsLinkSupport.getFinalPath(this);
+        String target = WindowsLinkSupport.getFinalPath(this, true);
         NativeBuffer aclBuffer = WindowsAclFileAttributeView
-            .getFileSecurity(fp, DACL_SECURITY_INFORMATION);
+            .getFileSecurity(target, DACL_SECURITY_INFORMATION);
 
         // retrieves DACL from security descriptor
         long pAcl = GetSecurityDescriptorDacl(aclBuffer.address());
@@ -1189,44 +1241,10 @@
             sm.checkPropertyAccess("user.dir");
         }
 
-        // result is the resolved path if the path is not drive-relative
-        if (type != WindowsPathType.DRIVE_RELATIVE)
-            return WindowsPath.createFromNormalizedPath(getFileSystem(), resolved);
-
-        // if the path is drive-relative and is relative to a drive other
-        // than the drive of the default directory then resolve against the
-        // working directory of that drive.
-        if (!isSameDrive(root, getFileSystem().defaultRoot())) {
-            try {
-                int dt = GetDriveType(root + "\\");
-                if (dt == DRIVE_UNKNOWN || dt == DRIVE_NO_ROOT_DIR)
-                    throw new WindowsException("");
-                String wd = GetFullPathName(root + ".");
-                String result = wd;
-                if (wd.endsWith("\\")) {
-                    result += path.substring(root.length());
-                } else {
-                    if (path.length() > root.length())
-                        result += "\\" + path.substring(root.length());
-                }
-                return WindowsPath.createFromNormalizedPath(getFileSystem(), result);
-            } catch (WindowsException x) {
-                IOException ioe = new IOException("Unable to get working " +
-                    "directory of drive '" +
-                    Character.toUpperCase(root.charAt(0)) + "'");
-                throw new java.io.IOError(ioe);
-            }
-        } else {
-            // relative to default directory
-            String remaining = path.substring(root.length());
-            String defaultDirectory = getFileSystem().defaultDirectory();
-            String result;
-            if (defaultDirectory.endsWith("\\")) {
-                result = defaultDirectory + remaining;
-            } else {
-                result = defaultDirectory + "\\" + remaining;
-            }
-            return createFromNormalizedPath(getFileSystem(), result);
+        try {
+            return createFromNormalizedPath(getFileSystem(), getAbsolutePath());
+        } catch (WindowsException x) {
+            throw new IOError(new IOException(x.getMessage()));
         }
     }
 
--- a/overlays/nio2/openjdk/jdk/test/org/classpath/icedtea/java/nio/file/Path/InterruptCopy.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/test/org/classpath/icedtea/java/nio/file/Path/InterruptCopy.java	Thu Feb 05 19:03:06 2009 +0000
@@ -90,8 +90,10 @@
                 source.copyTo(target, ExtendedCopyOption.INTERRUPTIBLE);
                 throw new RuntimeException("Copy completed (this is not expected)");
             } catch (IOException e) {
+                boolean interrupted = Thread.interrupted();
+                if (!interrupted)
+                    throw new RuntimeException("Interrupt status was not set");
                 System.out.println("Copy failed (this is expected)");
-                e.printStackTrace();
             }
 
             // copy source to target via task in thread pool, interrupting it after
--- a/overlays/nio2/openjdk/jdk/test/org/classpath/icedtea/java/nio/file/attribute/NamedAttributeView/Basic.java	Wed Feb 04 12:48:30 2009 +0000
+++ b/overlays/nio2/openjdk/jdk/test/org/classpath/icedtea/java/nio/file/attribute/NamedAttributeView/Basic.java	Thu Feb 05 19:03:06 2009 +0000
@@ -32,7 +32,8 @@
 import java.nio.file.*;
 import static java.nio.file.LinkOption.*;
 import java.nio.file.attribute.*;
-import java.util.Iterator;
+import java.util.Arrays;
+import java.util.Map;
 import java.util.Random;
 import java.io.IOException;
 
@@ -44,6 +45,29 @@
     private static final String ATTR_VALUE = "text/plain";
     private static final String ATTR_VALUE2 = "text/html";
 
+    static interface Task {
+        void run() throws Exception;
+    }
+
+    static void tryCatch(Class<? extends Throwable> ex, Task task) {
+        boolean caught = false;
+        try {
+            task.run();
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass())) {
+                caught = true;
+            } else {
+                throw new RuntimeException(x);
+            }
+        }
+        if (!caught)
+            throw new RuntimeException(ex.getName() + " expected");
+    }
+
+    static void expectNullPointerException(Task task) {
+        tryCatch(NullPointerException.class, task);
+    }
+
     static boolean hasAttribute(NamedAttributeView view, String attr)
         throws IOException
     {
@@ -55,7 +79,7 @@
     }
 
     static void test(Path file, LinkOption... options) throws IOException {
-        NamedAttributeView view = file
+        final NamedAttributeView view = file
             .getFileAttributeView(NamedAttributeView.class, options);
         ByteBuffer buf = rand.nextBoolean() ?
             ByteBuffer.allocate(100) : ByteBuffer.allocateDirect(100);
@@ -82,11 +106,10 @@
             throw new RuntimeException("Unexpected attribute value");
 
         // Test: read with insufficient space
-        try {
-            view.read(ATTR_NAME, ByteBuffer.allocateDirect(size-1));
-            throw new RuntimeException("Read expected to fail");
-        } catch (IOException x) {
-        }
+        tryCatch(IOException.class, new Task() {
+            public void run() throws IOException {
+                view.read(ATTR_NAME, ByteBuffer.allocateDirect(1));
+            }});
 
         // Test: replace value
         buf.clear();
@@ -104,56 +127,97 @@
         view.delete(ATTR_NAME);
         if (hasAttribute(view, ATTR_NAME))
             throw new RuntimeException("Attribute name in list");
+
+        // Test: dynamic access
+        byte[] valueAsBytes = ATTR_VALUE.getBytes();
+        view.setAttribute(ATTR_NAME, valueAsBytes);
+        byte[] actualAsBytes = (byte[])view.getAttribute(ATTR_NAME);
+        if (!Arrays.equals(valueAsBytes, actualAsBytes))
+            throw new RuntimeException("Unexpected attribute value");
+        Map<String,?> map = view.readAttributes(ATTR_NAME);
+        if (!Arrays.equals(valueAsBytes, (byte[])map.get(ATTR_NAME)))
+            throw new RuntimeException("Unexpected attribute value");
+        map = view.readAttributes(ATTR_NAME, "*");
+        if (!Arrays.equals(valueAsBytes, (byte[])map.get(ATTR_NAME)))
+            throw new RuntimeException("Unexpected attribute value");
+        map = view.readAttributes("DoesNotExist");
+        if (!map.isEmpty())
+            throw new RuntimeException("Map expected to be empty");
     }
 
     static void miscTests(Path file) throws IOException {
-        NamedAttributeView view = file
+        final NamedAttributeView view = file
             .getFileAttributeView(NamedAttributeView.class);
         view.write(ATTR_NAME, ByteBuffer.wrap(ATTR_VALUE.getBytes()));
 
         // NullPointerException
-        ByteBuffer buf = ByteBuffer.allocate(100);
-        try {
-            view.read(null, buf);
-            throw new RuntimeException("NPE expected");
-        } catch (NullPointerException x) { }
-        try {
-            view.read(ATTR_NAME, null);
-            throw new RuntimeException("NPE expected");
-        } catch (NullPointerException x) { }
-        try {
-            view.write(null, buf);
-            throw new RuntimeException("NPE expected");
-        } catch (NullPointerException x) { }
-        try {
-            view.write(ATTR_NAME, null);
-            throw new RuntimeException("NPE expected");
-        } catch (NullPointerException x) { }
-        try {
-            view.size(null);
-            throw new RuntimeException("NPE expected");
-        } catch (NullPointerException x) { }
-        try {
-            view.delete(null);
-            throw new RuntimeException("NPE expected");
-        } catch (NullPointerException x) { }
+        final ByteBuffer buf = ByteBuffer.allocate(100);
+
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.read(null, buf);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.read(ATTR_NAME, null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.write(null, buf);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+               view.write(ATTR_NAME, null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.size(null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.delete(null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.getAttribute(null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.setAttribute(ATTR_NAME, null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.setAttribute(null, new byte[0]);
+            }});
+         expectNullPointerException(new Task() {
+            public void run() throws IOException {
+               view.readAttributes(null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.readAttributes("*", (String[])null);
+            }});
+        expectNullPointerException(new Task() {
+            public void run() throws IOException {
+                view.readAttributes("*", ATTR_NAME, null);
+            }});
 
         // Read-only buffer
-        buf = ByteBuffer.wrap(ATTR_VALUE.getBytes()).asReadOnlyBuffer();
-        view.write(ATTR_NAME, buf);
-        buf.flip();
-        try {
-            view.read(ATTR_NAME, buf);
-            throw new RuntimeException("IAE expected");
-        } catch (IllegalArgumentException x) { }
+        tryCatch(IllegalArgumentException.class, new Task() {
+            public void run() throws IOException {
+                ByteBuffer buf = ByteBuffer.wrap(ATTR_VALUE.getBytes()).asReadOnlyBuffer();
+                view.write(ATTR_NAME, buf);
+                buf.flip();
+                view.read(ATTR_NAME, buf);
+            }});
 
         // Zero bytes remaining
-        buf = ByteBuffer.allocateDirect(100);
-        buf.position(buf.capacity());
-        try {
-            view.read(ATTR_NAME, buf);
-            throw new RuntimeException("IOE expected");
-        } catch (IOException x) { }
+        tryCatch(IOException.class, new Task() {
+            public void run() throws IOException {
+                ByteBuffer buf = buf = ByteBuffer.allocateDirect(100);
+                buf.position(buf.capacity());
+                view.read(ATTR_NAME, buf);
+            }});
     }
 
     public static void main(String[] args) throws IOException {