Jherico
Jherico

Reputation: 29240

Cross platform way to detect a symbolic link / junction point?

In java, a symbolic link in a Unix environment can be detected by comparing the file's canonical and absolute path. However, this trick does not work on windows. If I execute

mkdir c:\foo
mklink /j c:\bar

from the command line and then execute the following lines in java

File f = new File("C:/bar");
System.out.println(f.getAbsolutePath());
System.out.println(f.getCanonicalPath());

the output is

C:\bar
C:\bar

Is there any pre-Java 7 way of detecting a junction in windows?

Upvotes: 9

Views: 3583

Answers (4)

Thomas S.
Thomas S.

Reputation: 6335

With nio it is possible to detect a junction/reparse point or symlink even without reflection or use of JNA:

public void isReparsePointOrSymlink(Path path) {
    final var attribute = Files.getAttribute(path, "dos:attributes", LinkOption.NOFOLLOW_LINKS);
    if (attribute instanceof Integer value) {
        final boolean isJunctionOrSymlink = (value & 0x400) != 0;
        return isJunctionOrSymlink;
    }
    return Files.isSymbolicLink(path);
}

Note, that Files.isSymbolicLink(path) only returns true for the symbolic link, not for the reparse point. If you need to distinguish between both and isReparsePointOrSymlink returns true, check also Files.isSymbolicLink.

Upvotes: 0

Jherico
Jherico

Reputation: 29240

There doesn't appear to be any cross platform mechanism for this in Java 6 or earlier, though its a fairly simple task using JNA

interface Kernel32 extends Library {
  public int GetFileAttributesW(WString fileName);
}

static Kernel32 lib = null;
public static int getWin32FileAttributes(File f) throws IOException { 
  if (lib == null) {
    synchronized (Kernel32.class) {
      lib = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
    }
  }
  return lib.GetFileAttributesW(new WString(f.getCanonicalPath()));
}

public static boolean isJunctionOrSymlink(File f) throws IOException {
  if (!f.exists()) { return false; }
  int attributes = getWin32FileAttributes(f);
  if (-1 == attributes) { return false; }
  return ((0x400 & attributes) != 0);
}

EDIT: updated per comment about possible error return by getWin32FileAttributes()

Upvotes: 8

Manish Singh
Manish Singh

Reputation: 3499

You can try this dirty hack for windows

    if (f.isDirectory() || f.isFile()) {
        System.out.println("File or Directory");
    } else {
        System.out.println("Link");
    }

Upvotes: -1

bmargulies
bmargulies

Reputation: 100013

The answer is 'no'. Junction points and symbolic links are not the same sort of thing. The JRE doesn't check for them, and so the functions you cite don't differentiate them.

Having said this, you might accomplish something with the following:

If the junctioned directory has contents, then the result of getting the canonical pathname of something down below it might be 'surprising' and reveal the situation, since it is likely to be a pathname under the target of the junction. This only works if the directory pointed to by the junction is, of course, non-empty.

Upvotes: 1

Related Questions