13

I've been searching around trying to find a way to determine if a file is a junction or not, and have not found any satisfactory answers.

First thing I tried was:

Files.isSymbolicLink(aPath)

It detects only symbolic links not the files referred to as junctions in Windows.

Also tried the solution proposed here (using JNA library): Stackoverflow question (3249117) , but it never returned true on any of the files I know to be junctions.

The only way I've found to determine which files are junctions is the following command run in windows command prompt:

DIR /S /A:L

On my computer it returns 66 folders, wheras Files.isSymbolicLink(aPath) returned only 2. So I suppose I could find a way to utilize this, but I don't think it would be very effiecient when traversing a filetree.

Is there any way to do this using the standard java library, or alternativly JNA?

Share a link to this question
CC BY-SA 3.0
| improve this question | |
7

If you can write native code in JNA, you can directly call the Win32 API GetFileAttributes() function and check for the FILE_ATTRIBUTE_REPARSE_POINT flag (junctions are implemented as reparse points).

Update: To differentiate between different types of reparse points, you have to retreive the ReparseTag of the actual reparse point. For a junction point, it will be set to IO_REPARSE_TAG_MOUNT_POINT (0xA0000003).

There are two ways to retreive the ReparseTag:

  1. Use DeviceIoControl() with the FSCTL_GET_REPARSE_POINT control code to obtain an REPARSE_DATA_BUFFER struct, which as a ReparseTag field. You can see an example of an IsDirectoryJunction() implementation using this technique in the following article:

    NTFS Hard Links, Directory Junctions, and Windows Shortcuts

  2. Use FindFirstFile() to obtain a WIN32_FIND_DATA struct. If the path has the FILE_ATTRIBUTE_REPARSE_POINT attribute, the dwReserved0 field will contain the ReparseTag.

Share a link to this answer
CC BY-SA 3.0
| improve this answer | |
  • Thank you, never really used JNA before except for copy&paste code, but if it's the only way I suppose I better learn. – Martin Dec 5 '12 at 22:25
  • What you suggested seems similar to the suggestion in the link I posted, it would be greatly appriciated if you could provide me with an example of how to check for the reparse-flag. – Martin Dec 5 '12 at 22:37
  • FILE_ATTRIBUTE_REPARSE_POINT is defined as 0x400, so that example code you linked to is checking for FILE_ATTRIBUTE_REPARSE_POINT specifically. – Remy Lebeau Dec 5 '12 at 22:42
  • 1
    This won't detect just junctions. It detects all reparse points. Junctions are only one example of a reparse point. – David Heffernan Dec 6 '12 at 9:15
  • 1
    In Windows, junction points are implemented as reparse points. To differentiate between different types of reparse points, you have to use DeviceIoControl(FSCTL_GET_REPARSE_POINT). The returned REPARSE_DATA_BUFFER struct has a ReparseTag field (it is set to IO_REPARSE_TAG_MOUNT_POINT for a junction point). – Remy Lebeau Dec 7 '12 at 0:44
9

There can be a way to do it without JNA, if you have the right java, such as Oracle jdk 8. It's dodgy, it can cease to work, but....

You can get BasicFileAttributes interface related to the link:

BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);

It can happen that this interface implementation is a class sun.nio.fs.WindowsFileAttributes. And this class has a method isReparsePoint, which returns true for both junction points and symbolic links. So you can try to use reflection and call the method:

    boolean isReparsePoint = false;
    if (DosFileAttributes.class.isInstance(attr))
        try {
            Method m = attr.getClass().getDeclaredMethod("isReparsePoint");
            m.setAccessible(true);
            isReparsePoint = (boolean) m.invoke(attr);
        } catch (Exception e) {
            // just gave it a try
        }

Now you only can discover whether it really is symbolic link: Files.isSymbolicLink(path)

If its not, but it is reparse point, then that's junction.

Share a link to this answer
CC BY-SA 3.0
| improve this answer | |
  • You can save the need for the Files.isSylmbolicLink(path) step by reflectively checking the parseTag field of the WindowsFileAttributes A Junction will have a value of -1610612733 (and a symlink -1610612724), Just replace what's in the try block with this: Field field = attr.getClass().getDeclaredField("reparseTag"); field.setAccessible(true); int parseTag = (int) field.get(attr); boolean isJunction = parseTag == -1610612733; – Javaru May 27 '15 at 22:40
6

With J2SE 1.7 use Java NIO

/**
* returns true if the Path is a Windows Junction
*/
private static boolean isJunction(Path p) {
    boolean isJunction = false;
    try {
        isJunction = (p.compareTo(p.toRealPath()) != 0);
    } catch (IOException e) {
        e.printStackTrace(); // TODO: handleMeProperly
    }
    return isJunction;
}
Share a link to this answer
CC BY-SA 3.0
| improve this answer | |
  • it seems that it does not work. toRealPath() is the same as the path itself for a junction. – Osman-pasha Aug 4 '15 at 18:02
  • That is what is expected on a junction. – Peter Kirschner Aug 5 '15 at 3:50
  • So this code does not work, does it? For a junction p.compareTo(p.toRealPath()) is 0 as you agreed and as I saw in test. – Osman-pasha Oct 13 '15 at 19:54
  • 2
    @Peter Why is that expected? Junctions ARE NOT hard links despite popular opinion. NTFS has Hard links, Junctions and Symlinks. The difference between a symlink and junction has to do with traversing UNC targets which Junctions don't do well. – Andrew T Finnell Sep 12 '16 at 22:02
  • 1
    I updated the gist mentioned above to include also a hardlink example (which are only possible on files). So these can be distinguished via Files.isRegularFile(). But the above method is working fine for Junctions. Can you give me an example what you mean by traversing UNC targets. – Peter Kirschner Sep 15 '16 at 13:11
3

While on Windows a junction's attributes have isSymbolicLink() == false, they have isOther() == true. So you could do something like:

boolean isWindows = System.getProperty("os.name").toLowerCase().contains("windows")
BasicFileAttributes attrs = Files.readAttributes(aPath, BasicFileAttributes.class);
boolean isJunction = isWindows && attrs.isDirectory() && attrs.isOther();
Share a link to this answer
CC BY-SA 4.0
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.