【问题标题】:Which methods of java.nio.file.Files follow symbolic links and which don't?java.nio.file.Files 的哪些方法遵循符号链接,哪些不遵循?
【发布时间】:2019-09-17 13:43:11
【问题描述】:

Java 帮助类java.nio.file.Files 具有访问文件属性的方法。一些类方法遵循符号链接(所有方法都带有LinkOption 参数),而对于其他一些方法,不清楚是否遵循符号链接(没有LinkOption 参数的方法)。

这些是遵循符号链接的一些方法:

  • Files.isDirectory(Path, LinkOption...)
  • Files.isRegular(Path, LinkOption...)
  • Files.getAttribute(Path, String, LinkOption...)
  • Files.getLastModified(Path, LinkOption...)
  • Files.getOwner(Path, LinkOption...)
  • Files.getPosixFilePermission(Path, LinkOption...)

对于其他一些方法,确定它们是否遵循符号链接并不明显(没有LinkOption... 参数并且javadoc中没有提到符号链接):

  • Files.isSymbolicLink(Path)
  • Files.isExecutable(Path)
  • Files.isReadable(Path)
  • Files.isWritable(Path)
  • Files.isHidden(Path)
  • Files.size(Path)
  • Files.getFileStore(Path)

符号链接后面有哪些不带LinkOption...参数的方法,为什么?

【问题讨论】:

  • 一般来说,在 Unix 系统上,除非您明确检查符号链接,否则它会被透明地跟踪。
  • 这个问题也可以询问newDirectoryStream是否跟随链接。我很想知道。

标签: java symlink symlink-traversal


【解决方案1】:

TLDR:在大多数情况下,这似乎是FileSystemProvider 实现选择是否遵循符号链接(这可能会回答“为什么”问题)。符号链接是:

已关注:

  • Files.size(Path)

主要关注:

  • Files.getFileStore(Path) :在 Windows 和 Linux 上关注,在 Jimfs 上没有关注

未关注:

  • Files.isSymbolic(Path)

大部分没有被关注:

  • Files.isExecutable(Path) : 在 Windows 和 Unix 上不遵循,但在 Jimfs 上遵循
  • Files.isReadable(Path) : 在 Windows 和 Unix 上不遵循,但在 Jimfs 上遵循

完全实现特定:

  • Files.isWritable(Path) :在 Windows 上跟随,但在 Unix 上不跟随
  • Files.isHidden(Path) :在 Windows 上跟随,但在 Unix 上不跟随

您可以通过调用Files.readAttributes(Path, Class, LinkOption...) 并使用返回的属性来确定是否遵循符号链接。

Files.isSymbolic(Path) 不遵循符号链接

对于Files.isSymbolic(Path),原因很明显:如果该方法默认遵循符号链接,它总是会返回false

Files.isHidden(Path) 在 Windows 上关注符号链接,但在 Unix 上不关注

从方法签名,我们可能会认为该方法没有遵循符号链接(因为没有LinkOption...参数)。但是,这并不那么明显。

Files.isHidden(Path) 方法委托给java.nio.file.spi.FileSystemProvider.isHidden(Path) 的实现,javadoc 没有指定该方法是否遵循符号链接。

在 Windows 上,它是 implemented by following symbolic links,见第 465 行(WindowsFileAttributes.get(file, true) 调用中的 true 参数告诉要遵循符号链接):

@Override
public boolean isHidden(Path obj) throws IOException { 
    WindowsPath file = WindowsPath.toWindowsPath(obj); 
    file.checkRead(); 
    WindowsFileAttributes attrs = null; 
    try { 
        attrs = WindowsFileAttributes.get(file, true); 
    } catch (WindowsException x) { 
        x.rethrowAsIOException(file); 
    } 
    // DOS hidden attribute not meaningful when set on directories 
    if (attrs.isDirectory()) 
        return false; 
    return attrs.isHidden(); 
} 

在 Unix 上,这个方法是 implemented without following symbolic links(它只检查文件是否以“.”开头):

@Override
public boolean isHidden(Path obj) {
    UnixPath file = UnixPath.toUnixPath(obj);
    file.checkRead();
    UnixPath name = file.getFileName();
    if (name == null)
        return false;
    return (name.asByteArray()[0] == '.');
}

因此,我们可以得出结论,这是特定于实现的。

Files.isExecutable(Path) 在大多数文件系统中不要遵循符号链接

此方法委托给Files.isAccessible(Path, AccessMode.EXECUTE),后者委托给FileSystemProvider.checkAccess(Path, AccessMode...) 方法。

在 Windows 上,WindowsFileSystemProvider.checkAccess(Path, AccessMode...) 方法委托给java.lang.SecurityManager,它决定文件是否可执行。 AFAIK,SecurityManager 不遵循符号链接,因此我们可以假设 Files.isExecutable(Path) 在 Windows 上不遵循符号链接。

在 Unix 上,UnixFileSystemProvider.checkAccess(Path, AccessMode...) 方法也委托给 SecurityManager,我们可以假设 Files.isExecutable(Path) 在 Unix 上也不遵循符号链接。

在 Jimfs(来自 Google 的内存文件系统)上,调用委托给 com.google.common.jimfs.FileSystemView.checkAccess(JimfsPath),它遵循符号链接(即使 Jimfs 不支持访问控制):

public void checkAccess(JimfsPath path) throws IOException {
    // just check that the file exists
    lookUpWithLock(path, Options.FOLLOW_LINKS).requireExists(path);
}

因此,我们可以得出结论,Files.isExecutable(Path) 可能会跟随符号链接,具体取决于文件系统,但在大多数情况下(Unix+Windows)不会。

Files.isReadable(Path) 在大多数文件系统上不遵循符号链接

Files.isReadable(Path) 的实现与isExecutable(Path) 的实现非常相似:不要关注 Unix 和 Windows 上的链接,而是关注 Jimfs 上的链接。

Files.isWritable(Path)

对于Files.isExecutable(Path)isWritable(Path) 方法委托给FileSystemProvider.checkAccess(Path)

在 Windows 上,这需要确定文件是否具有只读属性,这可以通过以下链接完成(参见上面的 WindowsFileSystemProvider 代码)。

在 Unix 上,这显然是在不遵循符号链接的情况下完成的(参见上面的 UnixFileSystemProvider)。

因此,我们可以得出结论,这是特定于实现的。

Files.size(Path) 关注符号链接

实现委托给readAttributes,因此它遵循所有文件系统实现的符号链接:

public static long size(Path path) throws IOException {
    return readAttributes(path, BasicFileAttributes.class).size();
}

Files.getFileStore(Path)

该方法委托给FileSystemProvider.getFileStore(Path) 方法。

在 Windows 上,它使用 WindowsFileStore.create(Path) 遵循符号链接(参见 true 参数):

static WindowsFileStore create(WindowsPath file) throws IOException {
    try {
        // if the file is a link then GetVolumePathName returns the
        // volume that the link is on so we need to call it with the
        // final target
        String target = WindowsLinkSupport.getFinalPath(file, true);
  ...

在 Unix 上,FileSystemProvider.getFileStore(Path) 方法是抽象的,由子类实现,例如[LinuxFileSystem][3]

@Override
LinuxFileStore getFileStore(UnixPath path) throws IOException {
    return new LinuxFileStore(path);

}

此类通过获取带有链接的属性(UnixFileAttributes.get() 调用中的true 参数)来构造UnixFileStore

private static long devFor(UnixPath file) throws IOException {
    try {
        return UnixFileAttributes.get(file, true).dev();
    } catch (UnixException x) {
        x.rethrowAsIOException(file);
        return 0L;  // keep compiler happy
    }
}

在 Jimfs 中,FileStore 似乎在创建时附加到文件中,因此,看起来链接没有被遵循。

因此,我们可以得出结论,Files.getFileStore(Path) 在大多数文件系统实现中使用符号链接跟随。

【讨论】:

  • “我们可以假设 Files.isExecutable(Path) 在 Unix 上也不遵循符号链接”:默认的 Unix 行为是遵循链接,我从未见过 Java 运行时的行为不同。如果您要另外声明,请提供一个示例,而不是假设。
  • @chrylis :在github.com/frohoff/jdk8u-jdk/blob/master/src/solaris/classes/… 中,checkAccess(Path,AccessMode...) 方法显然不使用符号链接(github.com/frohoff/jdk8u-jdk/blob/master/src/solaris/classes/… 中的 access(UnixPath,AccessMode) 方法也没有提及符号链接)。也许我错过了一些东西,但根据我的分析,Files.isExecutable(Path) 没有链接。我很乐意提供一个测试用例。
  • 那是因为你在遍历的时候没有使用符号链接。他们只是发生,除非你明确地stat他们。
  • 另见java.nio.file 包的Javadoc。 “在大多数情况下,符号链接对应用程序是透明的,符号链接上的操作会自动重定向到链接的目标。例外情况是符号链接被删除或重命名/移动,在这种情况下,链接被删除或删除,而不是链接的目标。这个包包括对符号链接的支持,其中实现提供了这些语义。”
猜你喜欢
  • 1970-01-01
  • 2015-11-06
  • 2012-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多