RFR: JDK-8232092: (fs) Files::isWritable returns false on a writeable root directory (win)

Nikola Grcevski Nikola.Grcevski at microsoft.com
Mon Jul 6 21:59:56 UTC 2020

Hello core-libs-dev,

I was asked to help look into JDK-8232092 by Christian Stein (the bug reporter), and since I don't have an OpenJDK account yet I'm sharing my findings on the issue here. I looked into two separate issues that might cause FileSystemProvider.checkAccess to return an incorrect result as reported. 

The first issue seems related to substituted directories with volumes, or virtual drives on Windows. The problem happens if the Windows GetVolumePathNameW API is called with a virtual drive letter in the path, causing the API to return ERROR_INVALID_PARAMETER or error code 87. The code in WindowsFileStore::create makes a call to WindowsLinkSupport::getFinalPath, however the getFinalPath method will avoid expanding the virtual drive path, by calling GetFinalPathNameByHandle, because the path isn't a symbolic link. The existing code in WindowsFileStore::create currently checks for the ErrorLevel of ERROR_DIR_NOT_ROOT, and it properly calls the path expansion API, however it doesn't check for ERROR_INVALID_PARAMETER which might happen if a path with virtual drive letter is used.

We can follow the steps below to reproduce the issue:
- Have a writeable directory on Windows, e.g. C:\Temp
- Run "subst T: C:\Temp" on the command line to create the virtual drive T for C:\Temp
- Check with "cacls T:" and "cacls C:\Temp" that you have the exact same access control permissions
- Run "FileSystems.getDefault().provider().checkAccess(Path.of("T:\\"), java.nio.file.AccessMode.WRITE)" in jshell and you'll see an Exception java.nio.file.FileSystemException: T:\: The parameter is incorrect. Running the same command on C:\\Temp will return without an exception.

I've attached at the bottom of this email a simple patch that address the virtual drive issue. There might be a better way to fix this issue so any feedback is appreciated.

The second issue reported is using a virtual drive with the ImDisk utility to create a Virtual RAM Disk on Windows (Z: drive in the bug report). As mentioned in the bug report the failure is slightly different, in this case GetFinalPathNameByHandleW is called and the API returns ERROR_INVALID_FUNCTION. This error is caused by the third-party utility design/implementation. With ImDisk virtual disks, applications that rely on Windows Volume Mount Manager APIs, like GetFinalPathNameByHandleW, will fail because ImDisk does not interact with Windows Volume Mount Manager at all, it effectively bypasses it. Essentially, GetFinalPathNameByHandle and few other APIs will never work properly with ImDisk virtual drives.

Nikola Grcevski

diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsFileStore.java b/src/java.base/windows/classes/sun/nio/fs/WindowsFileStore.java
index acbb2c15f2a..9b4b4117b24 100644
--- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileStore.java
+++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileStore.java
@@ -79,10 +79,12 @@ class WindowsFileStore
             // volume that the link is on so we need to call it with the
             // final target
             String target = WindowsLinkSupport.getFinalPath(file, true);
             try {
                 return createFromPath(target);
             } catch (WindowsException e) {
-                if (e.lastError() != ERROR_DIR_NOT_ROOT)
+                if (e.lastError() != ERROR_DIR_NOT_ROOT && 
+                    e.lastError() != ERROR_INVALID_PARAMETER)
                     throw e;
                 target = WindowsLinkSupport.getFinalPath(file);
                 if (target == null)

More information about the core-libs-dev mailing list