Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Files.isHidden(Path) return false for directories on Windows?

From the documentation of Files.isHidden(Path) (emphasis mine):

Tells whether or not a file is considered hidden. The exact definition of hidden is platform or provider dependent. On UNIX for example a file is considered to be hidden if its name begins with a period character ('.'). On Windows a file is considered hidden if it isn't a directory and the DOS hidden attribute is set.

Depending on the implementation this method may require to access the file system to determine if the file is considered hidden.

From this I can understand what the expected behavior is. However, why is this the expected behavior?

The reason I'm wondering is because of the difference in behavior between Files.isHidden, DosFileAttributes.isHidden, and Windows' File Explorer. For instance, I can go into File Explorer and set a directory to be hidden and it will no longer show up (unless I configure it to show hidden items). If I test if said directory is hidden with Java then Files.isHidden returns false and DosFileAttributes.isHidden returns true. You can test this with the following code:

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.DosFileAttributes;

public class Main {

  public static void main(String[] args) throws Exception {  
    final var directory = Path.of(args[0]).toAbsolutePath().normalize();
    final var store     = Files.getFileStore(directory);
    final var dosAttrs  = Files.readAttributes(directory, DosFileAttributes.class);

    System.out.println("Directory     : " + directory);
    System.out.println("FileStore     : " + store.name() + " [" + store.type() + "]");
    System.out.println("Hidden (Files): " + Files.isHidden(directory));
    System.out.println("Hidden (Dos)  : " + dosAttrs.isHidden());
  }

}

Note: I'm using Windows 10 and OpenJDK 11.0.1. My file system is NTFS.


Running this with:

java Main.java C:\path\to\hidden\directory

I get:

Directory     : C:\path\to\hidden\directory
FileStore     : OS [NTFS]
Hidden (Files): false
Hidden (Dos)  : true

Note: This behavior appears to be part of WindowsFileSystemProvider. The method Files.isHidden(Path) simply forwards the call to the argument's FileSystem's provider. The implementation is basically:

DosFileAttributes attrs = ...; // get attributes
return !attrs.isDirectory() && attrs.isHidden();

I found this (non)-issue (JDK-8170334) where a comment says:

I don't think we have a bug here because the hidden attribute is meaningless on directories.

Yet File Explorer, which is core software on Windows, behaves like the hidden attribute is not meaningless on directories. So again, why does the Java implementation on Windows take into account whether or not the Path points to a directory? Or is Java correct and File Explorer is doing non-standard things?

I'm inclined to think File Explorer is correct because both CMD (via dir) and PowerShell (via Get-ChildItem) won't list hidden directories either; not unless the appropriate options are specified.

like image 620
Slaw Avatar asked Dec 15 '18 11:12

Slaw


Video Answer


1 Answers

I checked documentation for file attributes provided by Microsoft for Windows platform. It says that if attribute FILE_ATTRIBUTE_HIDDEN = 2 (0x2) is set

The file or directory is hidden. It is not included in an ordinary directory listing.

As I can see in the class sun.nio.fs.WindowsConstants there is the same value definition used by DosFileAttributes.isHidden() method - public static final int FILE_ATTRIBUTE_HIDDEN = 0x00000002; which for my understanding should be mapped one to one with the attribute available for Windows, so in general hidden flag for a directory should be working in the same way as for a regular file. In relation to operating system/file system integration, this behaviour seems to be incorrect.

like image 66
Kamil Avatar answered Sep 29 '22 04:09

Kamil