`touch` файл, который использует ACL в Linux, вызывает" Операция не разрешена " - PullRequest
0 голосов
/ 04 октября 2018

В коде Java я хочу «дотронуться» до файла.Я хочу обновить метки времени до текущего времени.Файл использует ACL.И это, похоже, проблема.

Файл:

$ ll file.xml 
-rw-rwxrw-+ 1 root root 8611 Oct  4 17:28 file.xml
$ getfacl file.xml 
# file: file.xml
# owner: root
# group: root
user::rw-
user:tomcat8:rwx
group::r-x
mask::rwx
other::rw-

И мое приложение Java запускается из Tomcat 8 с пользователем tomcat8.А sudo -u tomcat8 touch file.xml работает.Это также работает, если я полностью удаляю ACL и устанавливаю tomcat8 в качестве владельца.Но это невозможно в производственной среде.

Итак, сначала я попробовал Apache common-io:

FileUtils.touch(path);

Это вызывает IOException.Я немного отладил его и обнаружил, что библиотека вызывает FileSystem.setLastModifiedTime, которая вызывает функцию Linux utimes.

Я отладил команду Linux touch и увидел, что она вызывает еще одну более современную функцию: utimensat(0, NULL, NULL, 0).Он также вызывает dup2 и дублирует дескриптор файла.

Поэтому я создал свой собственный сенсорный метод в Java:

long time = System.currentTimeMillis();
FileTime fileTimeNow = FileTime.fromMillis(time);
BasicFileAttributeView fileAttributeView = Files.getFileAttributeView(derivative.toPath(), BasicFileAttributeView.class);
fileAttributeView.setTimes(fileTimeNow, fileTimeNow, fileTimeNow);

Это также вызывает исключение (операция не разрешена).

Внутренне он вызывает utimensat(69, NULL, [{1538666780, 483000000}, {1538666780, 483000000}], 0).

Я не могу установить null на .setTimes(...).Этот вызов игнорируется.И нет Java-способа дублировать файловый дескриптор (dup2).Поэтому я не могу протестировать дальнейшие шаги, чтобы сделать его более похожим на прикосновение Linux.

Как заставить это работать, когда файл использует ACL?Я не хочу запускать внешние программы (коснитесь).

Ответы [ 2 ]

0 голосов
/ 04 октября 2018

Вот man utimensat:

Требования к разрешениям

Чтобы установить временные метки обоих файлов на текущее время (т. Е. Times равно NULL, или в обоих полях tv_nsec укажите UTIME_NOW), либо:

  1. вызывающий должен иметь доступ на запись в файл;

  2. эффективный идентификатор пользователя вызывающего должен совпадать с владельцем файла;или

  3. вызывающий должен иметь соответствующие права доступа.

Чтобы внести какие-либо изменения, кроме установки обеих меток времени на текущее время (т. е., times не NULL , и ни одно из полей tv_nsec не равно UTIME_NOW, а ни одно из полей tv_nsec не равно UTIME_OMIT), должно применяться любое из указанных выше условий 2 или 3.

У вас есть #1, но не № 2 или № 3.Если вы попросите touch явно установить время для текущей отметки времени, оно также не будет выполнено:

$ getfacl test | sed -e "s/$USER/myuser/"
# file: test
# owner: root
# group: root
user::rw-
user:myuser:rwx
group::r--
mask::rwx
other::r--

$ touch -d "@$(date +%s)" test
touch: setting times of ‘test’: Operation not permitted

Хотя у меня нет хороших предложений относительно того, что делать вместо этого.Вы можете либо внести изменения в файл без операции, либо вызвать touch как внешнюю команду:

String path="some path";
// See https://stackoverflow.com/a/52651585 for why we're not doing this via Java
int result = Runtime.getRuntime().exec(new String[] { "touch", "--", path }).waitFor();
if(result != 0) throw new IOException("Can't update timestamp");
0 голосов
/ 04 октября 2018

Если файл не записан одновременно, вы можете открыть его, прочитать его первый байт и снова записать его с нулевым смещением.Это обновит время модификации файла, не требуя прав владения.

(Кстати, ACL выглядит действительно любопытно, особенно часть other:: rw-.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...