1

So, I recently posted an error that I received on recursively searching for files, and it was because I needed superuser privileges to view the files. I'm not really interested in that, and so I looked around the web and my best bet was just using a try/catch statement, but the problem with that is that the method I'm using (seen below) will stop completely if it got an error, and then if I started it again, it'd restart fully.

So here's the code:

Files.walk(Paths.get("C:\\"))
     .filter(Files::isRegularFile)
     .forEach(System.out::println);

How can I skip over files that I don't have enough permission to view?

Radiodef
  • 37,180
  • 14
  • 90
  • 125
  • Filter on `Files::isWritable` as well. Edit: I'm confused what you mean by "view". Depending on whether you want read or write or some other permission, there should be a method `Files::is_____`. – Mario Ishac Jun 30 '18 at 19:12
  • Check its [`FileAttributeView`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#getFileAttributeView-java.nio.file.Path-java.lang.Class-java.nio.file.LinkOption...-) of type [`AclFileAttributeView`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/attribute/AclFileAttributeView.html) to see if the owner is the superuser? (or another type depending on your platform). – M. le Rutte Jun 30 '18 at 19:19
  • @MarDev [Here](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html) I found all of the things that you were mentioning. I tried out `Files.getOwner()`, on the folder I knew it was rejecting, and it said `NT AUTHORITY\SYSTEM (Well-known group)`. Then when I tried it like on my downloads folder, it said like "User Joe" and the desktop name. How can I check that it's not `NT AUTHORITY\SYSTEM (Well-known group)` during the file walk? – user10012895 Jun 30 '18 at 19:33
  • @user10012895 Try to get the [`GroupPrincipal`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/attribute/GroupPrincipal.html) via the `AclFileAttributeView`. – M. le Rutte Jun 30 '18 at 19:36

2 Answers2

1

Use a visitor instead of walk. This allows you to proceed even in case of failure. I tried this on a linux file which was giving similar error. You may try the same in windows.

private static final class ExSafeVisitor extends SimpleFileVisitor<Path>
{
    @Override
    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException
    {
        if (Files.isReadable(dir))
        {
            return FileVisitResult.CONTINUE;
        }
        else
        {
            return FileVisitResult.SKIP_SUBTREE;
        }
    }

    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException
    {
        if (Files.isReadable(file))
        {
            System.out.println("file = " + file);
        }
        return FileVisitResult.CONTINUE;
    }

    @Override
    //print exception but proceed
    public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException
    {
        exc.printStackTrace();
        return FileVisitResult.CONTINUE;
    }
}

//Files.walk for this path in linux throws exception
Files.walkFileTree(Paths.get("/sys/kernel"), new ExSafeVisitor());
gagan singh
  • 1,591
  • 1
  • 7
  • 12
  • This almost worked for me! I believe it took a good deal longer for it to come across a file that didn't allow me to view the title via my program, but it did eventually, with the same error I listed [here](https://stackoverflow.com/questions/51109815/getting-java-nio-file-accessdeniedexception-when-recursively-collecting-file-nam) – user10012895 Jun 30 '18 at 19:24
  • Using `isReadable()` results in a race condition. [The documentation even states](https://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#isReadable(java.nio.file.Path)): "Note that the result of this method is immediately outdated, **there is no guarantee that a subsequent attempt to open the file for reading will succeed**" – Andrew Henle Jul 01 '18 at 14:54
0

How can I skip over files that I don't have enough permission to view?

You can't.

You have to actually try to read the file to find out if you can actually read the file. See How to check if a file is readable?

In general, "Use X to see if I can do Y" is a fundamentally incorrect approach. X is not Y, so doing X successfully doesn't mean Y will work, nor does X failing indicate that Y will fail. As the linked question shows, no version of Java's isReadable() will give you definitive results as to whether or not you can actually read the file.

Second, even if you do somehow come up with a check that is in fact perfect (you won't, because for example you can't even see any SELinux rules that may be in place...), you still have a TOCTOU bug - things change.

The isReadable() documentation even states:

Note that the result of this method is immediately outdated, there is no guarantee that a subsequent attempt to open the file for reading will succeed

Just because your check said you can read the file doesn't mean you can actually read the file when you try.

The only definitive way to determine that you can actually read a file is to actually read that file. Any checks you do prior to actually trying to open the file for reading just add useless overhead.

You still have to properly handle exceptions at any location of your code.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56