3

I thought I had read that if the absolute and canonical paths of a given file did not match, that that meant the file was a symbolic link.

I'm on Windows 10, and it has things it calls "Junctions"; the above test finds identical strings for those two items. I also have found no other way to distinguish these files, having tried the calls below:

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;

public class WindowsFilePlay2
{
  public static void main(String[] args)
  {
    WindowsFilePlay2 play2 = new WindowsFilePlay2();
    play2.go();
  }
  
  private void go()
  {
    File[] fileList = { new File("c:\\Users\\Ralph\\AppData\\Local\\")
                       ,new File("c:\\Users\\Ralph\\AppData\\")
                       ,new File("c:\\users\\ralph\\")
                      };
    try
    { 
      for (File file : fileList)
      {
        Path    filePath    = file.toPath();
        String  absolute    = file.getAbsolutePath();
        String  canonical   = file.getCanonicalPath();
        String  realPath    = filePath.toRealPath().toString();
        boolean answer      = Files.isSymbolicLink(filePath);
        boolean isFile      = file.isFile();
        boolean isAbsolute  = file.isAbsolute();
        boolean isDirectory = file.isDirectory();
        boolean isHidden    = file.isHidden();
        boolean isReadable  = Files.isReadable(filePath);
        
        BasicFileAttributes attributes = Files.readAttributes(filePath, BasicFileAttributes.class);
        boolean isLink      = attributes.isSymbolicLink();
        boolean isOther     = attributes.isOther();
        
        absolute = absolute.toLowerCase();
        canonical = canonical.toLowerCase();
        
        System.out.printf("filePath    %s%n"
                        + "absolute    %s%n"
                        + "canonical   %s%n"
                        + "realPath    %s%n"
                        + "answer      %b%n"
                        + "isFile      %b%n"
                        + "isAbsolute  %b%n"
                        + "isDirectory %b%n"
                        + "isHidden    %b%n"
                        + "isLink      %b%n"
                        + "isOther     %b%n"
                        + "isReadable  %b%n"
                        + "%n"
                        , filePath.toString(), absolute, canonical, realPath, answer, isFile, isAbsolute, isDirectory, isHidden, isLink, isOther, isReadable
                         );
      }
    }
    catch (IOException ioe)
    {
      ioe.printStackTrace();
    }
  }
}

The output from this:

filePath    c:\Users\Ralph\AppData\Local
absolute    c:\users\ralph\appdata\local
canonical   c:\users\ralph\appdata\local
realPath    C:\Users\ralph\AppData\Local
answer      false
isFile      false
isAbsolute  true
isDirectory true
isHidden    false
isLink      false
isOther     false
isReadable  true

filePath    c:\Users\Ralph\AppData
absolute    c:\users\ralph\appdata
canonical   c:\users\ralph\appdata
realPath    C:\Users\ralph\AppData
answer      false
isFile      false
isAbsolute  true
isDirectory true
isHidden    true
isLink      false
isOther     false
isReadable  true

filePath    c:\users\ralph
absolute    c:\users\ralph
canonical   c:\users\ralph
realPath    C:\Users\ralph
answer      false
isFile      false
isAbsolute  true
isDirectory true
isHidden    false
isLink      false
isOther     false
isReadable  true

But AppData and AppData\Local are not real files; they're junctions or links or whatever to other files. I don't know what they would be called in the Java API. My program wants to avoid them, since it is going through the actual directories on the disk and does not want to visit any directory subtrees twice. So how can I determine that I have one of these, whatever they're called?

arcy
  • 12,845
  • 12
  • 58
  • 103
  • 1
    ["*All NTFS links are **designed to be transparent to applications**. This means that the application accessing a link will be seamlessly redirected by the file system driver, and no special handling is needed. To users, they appear as normal directories or files.*" (Wikipedia)](https://en.wikipedia.org/wiki/NTFS_links) – Turing85 May 16 '21 at 22:06
  • APIs such as `Files#walk(...)` and `Files#walkFileTree(...)` avoid following links unless explicitly told to with `FileVisitOption.FOLLOW_LINKS`. Other NIO2 methods will follow links but can be told not to with `LinkOption.NOFOLLOW_LINKS`. Perhaps this information will be helpful? – Slaw May 16 '21 at 22:23
  • This might also help: https://stackoverflow.com/a/48291462/6395627 – Slaw May 16 '21 at 22:59
  • It is helpful; I still want to know how to determine this from a program. I had a version of the program I'm working on that used the pre-nio method of `File.listFiles()` recursively to walk the directory tree myself; I'm now converting that to an NIO version, so perhaps it is not an issue for that program. Having happened on the distinction, I'd still like to know how Java can tell the difference. For instance, I don't want my user to choose a link/symlink/junction/whatever with which to start the walk, and so I'd like to be able to test what he chose and tell him if that's what he's done. – arcy May 16 '21 at 23:01
  • The Java API does not appear to have any way to detect junction points. You may need to resort to reading the output of a Powershell command or the `dir` command. – VGR May 17 '21 at 00:54
  • Does this answer your question? [Determine whether a file is a junction (in Windows) or not?](https://stackoverflow.com/questions/13733275/determine-whether-a-file-is-a-junction-in-windows-or-not) – Daniel Widdis May 18 '21 at 13:53
  • @DanielWiddis I read that, but the methods without JNA don't work, and the method in my answer to this question does seem to work. – arcy May 18 '21 at 14:17

1 Answers1

2

User error -- OP here, I was using the translation of the Junctions instead of the junctions themselves, e.g., c:\users\ralph\Application Data\ is what I should be testing -- that's the junction -- and it translates to c:\users\ralph\AppData\Roaming. But I was testing the latter, expecting to find some way of finding out it was a link or something, but it is not. When I test with the actual Windows Junction, the realPath value from the output above is different than the filePath value.

Thanks to those who responded.

arcy
  • 12,845
  • 12
  • 58
  • 103