java walkFileTree模仿chmod -R 755不起作用

时间:2017-11-26 13:50:50

标签: java

我想确保目录树中的正确权限(目录为0755,文件为644)。这是我的班级:

package NRF_Utils;

import java.io.IOException;
import java.nio.file.FileVisitResult;
import static java.nio.file.FileVisitResult.*;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Set;
import java.util.logging.Logger;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;

public class DirectoryTreeOperations {
    private static final Logger log = Logger.getLogger("spv." + DirectoryTreeOperations.class.getName());

    public static boolean setPermissions(String root, String directoryPermissions, String filePermissions) {
        boolean result = true;
        //declaring the path to delete
        final Path path = Paths.get(root);
        final Set<PosixFilePermission> dirPermissions = PosixFilePermissions.fromString(directoryPermissions);
        final Set<PosixFilePermission> filPermissions = PosixFilePermissions.fromString(filePermissions);

        try {
            Files.walkFileTree(path, new FileVisitor<Path>() {

                @Override
                public FileVisitResult preVisitDirectory(Path dir,
                        BasicFileAttributes attrs) throws IOException {
                    System.out.println("setting dir permission on " + dir);
                    Files.setPosixFilePermissions(dir, dirPermissions);                 
                    return CONTINUE;
                }

                @Override
                public FileVisitResult visitFile(Path file,
                        BasicFileAttributes attrs) throws IOException {
                    System.out.println("setting file permission on " + file);
                    Files.setPosixFilePermissions(file, filPermissions);
                    return CONTINUE;
                }

                @Override
                public FileVisitResult visitFileFailed(Path file, IOException exc)
                        throws IOException {
                    log.severe("visitFileFailed failed on " + file + " : " + exc);
                    return CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir,
                        IOException exc) throws IOException {
                    return CONTINUE;
                }

            });
        } catch (IOException e) {
            log.severe("setPermissions failed " + e);
            result = false;
        }
        return result;
    }

    // TODO remove and provide a proper unit test
    public static void main(String [] arg) {
        System.out.println ("setPermissions returned: " + setPermissions("/tmp/x", "rwxr-xr-x", "rw-r--r--"));
    }
}

为了进行测试,我做了:

mkdir -p /tmp/x/y/z;touch /tmp/x/y/z/f;chmod 000 /tmp/x/y/z

输出结果为:

setting dir permission on /tmp/x
setting dir permission on /tmp/x/y
setPermissions returned: true
nov. 26, 2017 2:45:00 PM NRF_Utils.DirectoryTreeOperations$1 visitFileFailed
GRAVE: visitFileFailed failed on /tmp/x/y/z : java.nio.file.AccessDeniedException: /tmp/x/y/z

似乎java不想浏览目录树,因为权限错误,但我的目的是探索目录树来修复权限。 API是疯了吗?

3 个答案:

答案 0 :(得分:5)

它看起来似乎很奇怪,所以也许不是一个疯狂的API,但实现当然不能满足使用preVisitDirectory()来使目录可访问的特定情况。

Files.walkFileTree() doc说:

  

如果文件是目录,并且无法打开目录,   然后使用I / O异常调用visitFileFailed方法,   之后,默认情况下,文件树步行继续在下一个步骤   兄弟姐妹的目录。

并查看实现,它确实尝试在调用visitor.preVisitDirectory()之前打开目录,这解释了您遇到的问题。

作为一个解决方案,您可以获取FileTreeWalker.java源代码,并在您自己的本地版本的FileTreeWalker中进行微调 - 直接查找对visitor.preVisitDirectory()的调用并移动打开的目录代码在那之后发生。然后将您的代码更改为:

  new FileTreeWalker(EnumSet.noneOf(FileVisitOption.class), new FileVisitor<Path>() {
     ...
  }, Integer.MAX_VALUE).walk(path);

当你跑步时,你会得到:

setting dir permission on /tmp/x
setting dir permission on /tmp/x/y
setting dir permission on /tmp/x/y/z
setting file permission on /tmp/x/y/z/f
setPermissions returned: true

显示了FileVisitor的实施情况。

希望有所帮助。

答案 1 :(得分:3)

当您从命令行执行chmod 755 /tmp/x/y/z时,它不会检查z本身的权限。只要您有足够的y访问权限,就可以在chmod上执行z

OTOH,如果您查看Files.walkFileTree的{​​{3}},它实际上会尝试使用自己的visit方法访问每个目标文件,收集文件属性等,之前它会调用您的访问者方法。因此拒绝访问错误。

从表面上看,您可能需要滚动自己的文件树助行器,在那里您可以继续更改权限,而无需先尝试访问目标路径。

答案 2 :(得分:1)

DEFINE('DB_USER', 'root'); // default user name DEFINE('DB_PASSWORD', ''); // empty password just open single quote and close 的唯一问题是它不会在没有搜索权限的目录上调用walkFileTree。您可以通过在walkFileTree查找的位置之前修复权限来解决此问题。  即,通过手动扫描递送到preVisitDirectory()的任何目录的直接子项并在那里应用权限(而不是preVisitDirectoy()):

visitFile

然后你可以评论 @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { for(File f : new File(dir.toUri()).listFiles()) { //iterate over the contents of the directory System.out.println("setting dir permission on " + f); Files.setPosixFilePermissions(dir.resolve(f.getName()), dirPermissions); } //System.out.println("setting dir permission on " + dir); //Files.setPosixFilePermissions(dir, dirPermissions); return CONTINUE; } 的身体:

visitFile()

由于我们现在将权限应用于walk所在的下一层,我们需要在try块内部进行额外的调用:

            @Override
            public FileVisitResult visitFile(Path file,
                    BasicFileAttributes attrs) throws IOException {
            //    System.out.println("setting file permission on " + file);
            //    Files.setPosixFilePermissions(file, filPermissions);
                return CONTINUE;
            }

以下是整个事情(好吧,为方便起见,我取消了包裹声明):

        System.out.println("setting dir permission on " + path); //in case the initial path needs fixing
        Files.setPosixFilePermissions(path, dirPermissions);

在示例案例上运行时:

import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import static java.nio.file.FileVisitResult.*;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Set;
import java.util.logging.Logger;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;

public class DirectoryTreeOperations {
    private static final Logger log = Logger.getLogger("spv." + DirectoryTreeOperations.class.getName());

    public static boolean setPermissions(String root, String directoryPermissions, String filePermissions) {
        boolean result = true;
        //declaring the path to delete
        final Path path = Paths.get(root);
        final Set<PosixFilePermission> dirPermissions = PosixFilePermissions.fromString(directoryPermissions);
        final Set<PosixFilePermission> filPermissions = PosixFilePermissions.fromString(filePermissions);

        try {
            System.out.println("setting dir permission on " + path); //in case the initial path needs fixing
            Files.setPosixFilePermissions(path, dirPermissions);

            Files.walkFileTree(path, new FileVisitor<Path>() {
                @Override
                public FileVisitResult preVisitDirectory(Path dir,
                        BasicFileAttributes attrs) throws IOException {
                    for(File f : new File(dir.toUri()).listFiles()) { //iterate over the contents of the directory
                        System.out.println("setting dir permission on " + f);
                        Files.setPosixFilePermissions(dir.resolve(f.getName()), dirPermissions);
                    }

                    //System.out.println("setting dir permission on " + dir);
                    //Files.setPosixFilePermissions(dir, dirPermissions);
                    return CONTINUE;
                }

                @Override
                public FileVisitResult visitFile(Path file,
                        BasicFileAttributes attrs) throws IOException {
                //    System.out.println("setting file permission on " + file);
                //    Files.setPosixFilePermissions(file, filPermissions);
                    return CONTINUE;
                }

                @Override
                public FileVisitResult visitFileFailed(Path file, IOException exc)
                        throws IOException {
                    log.severe("visitFileFailed failed on " + file + " : " + exc);
                    return CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir,
                        IOException exc) throws IOException {
                    return CONTINUE;
                }

            });
        } catch (IOException e) {
            log.severe("setPermissions failed " + e);
            result = false;
        }
        return result;
    }

    // TODO remove and provide a proper unit test
    public static void main(String [] arg) {
        System.out.println ("setPermissions returned: " + setPermissions("/tmp/x", "rwxr-xr-x", "rw-r--r--"));
    }
}