When running Files.walk(Paths.get("/var/")).count() as an unprivileged user, the execution might throw an exception as there are folders inside /var/ that need root permission to be traversed.
I am not looking for a way to execute a bash command as root (e.g. sudo find /var), using Process, etc.
I just want to make sure Files.walk(Paths.get("/var/")).count() does not throw an AccessDeniedException:
Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0
at sun.reflect.NativeMethodAccessorImpl.invoke
at sun.reflect.DelegatingMethodAccessorImpl.invoke
at java.lang.reflect.Method.invoke
at org.springframework.boot.devtools.restart.RestartLauncher.run
Caused by: java.io.UncheckedIOException: java.nio.file.AccessDeniedException: /var/cache/httpd
at java.nio.file.FileTreeIterator.fetchNextIfNeeded
at java.nio.file.FileTreeIterator.hasNext
at java.util.Iterator.forEachRemaining
at java.util.Spliterators$IteratorSpliterator.forEachRemaining
at java.util.stream.AbstractPipeline.copyInto
at java.util.stream.AbstractPipeline.wrapAndCopyInto
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential
at java.util.stream.AbstractPipeline.evaluate
at java.util.stream.LongPipeline.reduce
at java.util.stream.LongPipeline.sum
at java.util.stream.ReferencePipeline.count
at com.example.DemoApplication.main
... 5 more
Caused by: java.nio.file.AccessDeniedException: /var/cache/httpd
at sun.nio.fs.UnixException.translateToIOException
at sun.nio.fs.UnixException.rethrowAsIOException
at sun.nio.fs.UnixException.rethrowAsIOException
at sun.nio.fs.UnixFileSystemProvider.newDirectoryStream
at java.nio.file.Files.newDirectoryStream
at java.nio.file.FileTreeWalker.visit
at java.nio.file.FileTreeWalker.next
at java.nio.file.FileTreeIterator.fetchNextIfNeeded
This is just an example. Using filter(...) it is possible to work around the exception. But this example can be expanded to other use cases too.
So in short Is this possible at all, for CLI, JavaFX, etc. apps to gain root permission after they have been executed from command line via a method such as java -jar app.jar?
解决方案
If what you want is actually skipping the paths where you have no access, you have two approaches:
Streams
In the answer to this question it is explained how to obtain the stream of all files of a subtree you can access.
But this example can be expanded to other use cases too.
FileVisitor
Using a FileVisitor adds a lot of code, but grants you much more flexibility when walking directory trees. To solve the same problem you can replace Files.walk() with:
Files.walkFileTree(Path start, FileVisitor super Path> visitor);
extending SimpleFileVisitor (to count the files) and overriding some methods.
You can:
Override the visitFileFailed method, to handle the case you cannot access a file for some reasons; (Lukasz_Plawny's advice)
(optional) Override the preVisitDirectory method, checking for permissions before accessing the directory: if you can't access it, you can simply skip its subtree (keep in mind that you may be able to access a directory, but not all its files);
e.g. 1
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
// you can log the exception 'exc'
return FileVisitResult.SKIP_SUBTREE;
}
e.g. 2
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
if(!Files.isReadable(dir))
return FileVisitResult.SKIP_SUBTREE;
return FileVisitResult.CONTINUE;
}
Hope it helps.