Search code examples
javafile-iosymlink

Files.newInputStream with NOFOLLOW_LINKS option


I wonder what is the expected behavior of java.nio.file.Files.newInputStream with java.nio.file.LinkOption.NOFOLLOW_LINKS option when used on symbolic links. I could not find it in documentation.

I created two files. Regular empty file called "file" and a symbolic link called "link":

touch file
ln -s file link

When I try to open input stream for the link file:

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;

public class Main {
    public static void main(String[] args) throws IOException {
        try (
            InputStream stream = Files.newInputStream(Path.of("src", "link"), LinkOption.NOFOLLOW_LINKS)
        ) {}
    }
}

then I get an error:

Exception in thread "main" java.io.IOException: Too many levels of symbolic links (NOFOLLOW_LINKS specified)
    at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:86)
    at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
    at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:116)
    at java.base/sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:219)
    at java.base/java.nio.file.Files.newByteChannel(Files.java:371)
    at java.base/java.nio.file.Files.newByteChannel(Files.java:422)
    at java.base/java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:420)
    at java.base/java.nio.file.Files.newInputStream(Files.java:156)
    at Main.main(Main.java:10)

If I either remove the NOFOLLOW_LINKS option or change path to the regular file, then no error is thrown.

If NOFOLLOW_LINKS option cannot be used on symbolic links, then I would expect either IllegalArgumentException or UnsupportedOperationException to be thrown. Why is IOexception with message "Too many levels of symbolic links" thrown instead?

I use openjdk version "11.0.19" in case that was relevant.


Solution

  • The expected behavior for I/O errors is that an IOException is thrown, which it is, as you have seen.

    IllegalArgumentException is not a good fit here. It is used when there is something wrong with the arguments that can be detected before attempting to do anything. For example, Files.newInputStream throws this exception 'if an invalid combination of options is specified'.

    UnsupportedOperationException is also used for something different, it is used in cases where the entire operation is unsupported. For example, attempting to remove an element from an unmodifiable collection.