views:

200

answers:

3

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?

A: 

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.

bmargulies
A junction point in windows is a file system entity that redirects you to another location (possibly on another volume) and is transparent to all the file system API's for opening and reading files. How is that not exactly like a (POSIX) symbolic link? Other than that on windows its called a junction if its for a directory and a symlink if its for a file?
Jherico
The point of my question is that unlink the JVM on linux, the JVM on windows will NOT return different canonical and absolute values for the junction (or a directory symlink or any of the contents therein).
Jherico
In a Linux file system, there is a backpointer in the inode to the real parent, not to any symlink. Similiarly in NTFS. What a junction point is like is a *mount point*.
bmargulies
A: 

You can try this dirty hack for windows

    if (f.isDirectory() || f.isFile()) {
        System.out.println("File or Directory");
    } else {
        System.out.println("Link");
    }
This does nothing useful. isDirectory() will return true for a normal directory, a directory symbolic link (made with mklink /d) or a junction (made with mklink /j). Any other kind of link or shortcut will return true for isFile(). Your confusion may arise from the fact that if you create a shortcut to a directory or file it shows up as 'Foo' but on disk its represented as 'Foo.lnk', therefore isDirectory() and isFile() will return false for 'Foo' (but then so will exists()). Shortcuts are at any rate, a windows explorer artifact only and have nothing to do with what I was asking.
Jherico
+2  A: 

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 {
  return (f.exists() && (0x400 & getWin32FileAttributes(f)) != 0);
}
Jherico