Какие методы java.nio.file.Files следуют по символическим ссылкам, а какие нет? - PullRequest
1 голос
/ 29 апреля 2019

У вспомогательного класса 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... следуют по символическим ссылкам и почему?

1 Ответ

2 голосов
/ 29 апреля 2019

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 это реализовано с помощью следующих символических ссылок , см. Строку 465 (параметр true в вызове WindowsFileAttributes.get(file, 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 этот метод реализован без следующих символических ссылок (он только проверяет, что файл начинается с "."):

@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);

}

Этот класс создает UnixFileStore, получая атрибуты со следующей ссылкой (параметр true в вызове UnixFileAttributes.get()):

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) использует символическую ссылку, следующую в большинстве реализаций файловой системы.

...