Files.createDirectories throws AccessDeniedException for an existing directory

ole.sh at gmx.de ole.sh at gmx.de
Tue Nov 26 16:44:45 UTC 2024


Hi,

I came a across a behavior of Files.createDirectories on Linux (RHEL8, JDK 17) that is a litte "unexpected":
The call of Files.createDirectories for an existing (and readable) directory on an NFS mount throws an AccessDeniedException. Technically this exception is correct because our process does not have the filesystem rights to create the directory, the process does have the rights to "read" the directory though. Looking at the JavaDoc of Files.createDirectories my expectation was that no exception would be thrown because the directory exists. I know that Files.createDirectories may throw an IOException and thus an AccessDeniedException but - as I said - it is a little "unexpected". What was even more suprising is that for the same directory the call to Files.createDirectories sometimes works and sometimes throws an AccessDeniedException (using the same process, user, etc. of course).

I took a closer look at it and saw that Files.createDirectories never explicitly checks for the existence of the directory but relies on the createDirectory of the underlying FileSystemProvider to throw an FileAlreadyExistsException. In case of Linux the underlying UnixFileSystemProvider calls the mkdir system call and checks/translates its return code. The problem is that the mkdir system call seems to be allowed (according to Posix?) to return any of the matching return codes in case multiple return codes are "correct". And that happens in our NFS case. We verified that the mkdir call sometimes returns EACCESS and sometimes EEXIST (most likely due to some "caching" in the kernel NFS driver).

Although it is just an "edge case" I wonder if it makes sense to make Files.createDirectories more "predictable" in such cases? A simple solution might be to adapt Files.createAndCheckIsDirectory to check if the "dir" is a  directory not just in case of an FileAlreadyExistsException but also in case of an AccessDeniedException:

    private static void createAndCheckIsDirectory(Path dir,
                                                  FileAttribute<!--?-->... attrs)
        throws IOException
    {
        try {
            createDirectory(dir, attrs);
        } catch (FileAlreadyExistsException x) {
            if (!isDirectory(dir))
                throw x;
+       } catch (AccessDeniedException x) {
+           if (!isDirectory(dir))
+              throw x;
        }
    }

Some additional notes:
* A similar problem was reported and fixed in JDK-8032220 for MacOS and Windows
* Though I have this problem using JDK 17 it (most likely) also could occur with the latest JDK because the implementation of Files.createDirectories seems not to have changed much.

Best regards
Ole


More information about the nio-dev mailing list