Как неинвазивно проверить доступ на запись в файл?

20

В сценарии оболочки, как я могу легко и неинвазивно проверить доступ на запись в файл без фактической попытки изменить файл?

Я мог бы проанализировать вывод stat, но это кажется действительно сложным и, возможно, хрупким, хотя я не уверен, насколько статистический вывод отличается в разных реализациях и времени.

Я мог бы добавить в конец файла и посмотреть, если это удастся, но это потенциально опасно, по двум причинам, которые я могу думать:

  1. Теперь мне нужно удалить дополнение, и в случае, если какой-то другой процесс записывает в файл, это сразу становится нетривиальным, так как моя строка больше не является последней.
  2. Любой процесс, читающий файл, может иметь произвольные требования к содержимому этого файла, и я, возможно, просто нарушил это приложение.
user50849
источник

Ответы:

29

Просто используйте - wфлаг использования test:

[ -w /path/to/file ] && echo "writeable" || echo "write permission denied"

Обратите внимание, что если вы собираетесь записать файл позже, все еще возможно, что вы не сможете писать в него. Возможно, файл перемещен, разрешения могут быть изменены и т. Д. Также может случиться так, что -wобнаружатся разрешения на запись, но вмешивается другой фактор, который делает файл недоступным для записи .

хаос
источник
1
Конечно! Я должен был подумать, чтобы проверить справочную страницу теста. Спасибо.
user50849
1
@qweilun это встроенная оболочка, но вы можете отобразить справочную страницу через man testилиman [
chaos
5
@chaos Это и встроенная оболочка, и внешний исполняемый файл - попробуйтеtype -a
Volker Siegel
1
За истокомtest использований , euidaccessкоторый просто проверяет биты разрешения . Нет ли других факторов (например, SELinux), которые могли бы запретить доступ на запись?
Замкнут
2
@BroSlow, &&и ||имеют равный приоритет. Они оцениваются слева направо.
Уайлдкарт
11

Другой подход:

if >> /path/to/file
then
    echo "writeable"
else
    echo "write permission denied"
fi

Это попытается открыть файл для добавления и, если это удастся, не выполнить команду (то есть выполнить нулевую команду ) с выводом в файл. 

Помните, что это создает пустой файл, если он не существует.

-wОператор testкоманды может просто сделать , stat а затем попытаться выяснить , выглядит ли это , как вы должны иметь доступ. Моя альтернатива (выше) более надежна, чем testподход в некоторых особых условиях, потому что она заставляет проверку доступа выполнять ядро, а не оболочка. Например,

  • если файл находится в файловой системе не-Unix - особенно если он удаленно монтируется с файлового сервера не-Unix - потому что statможет вернуть значение режима, которое вводит в заблуждение.
  • если файл находится в файловой системе, которая монтируется только для чтения.
  • если файл имеет ACL, и режим делает его похожим на то, что у вас должен быть доступ, но ACL запрещает его, или наоборот.
  • если какая-то инфраструктура безопасности (AppArmor, SELinux,…) запрещает доступ к файлу.
G-Man говорит: «Восстанови Монику»
источник
3
Я только что проверил это (на Debian). Ни одно время не было изменено, и именно так оно должно работать на любом Unix. Время доступа должно обновляться, только если вы читаете из файла, время изменения должно обновляться, только если вы пишете в файл. Этот код не делает ни того, ни другого. @Schwern: у вас есть ссылка на ваше заявление? Кто-нибудь из вас пробовал это?
G-Man говорит: «Восстановите Монику»
2
PS @muru: Я только что попытался touchнайти файл, который принадлежал мне, но не имел права на запись, и это удалось. Я предполагаю, что chmodэто файл и chmodвернул его. Так что, touchпохоже, абсолютно бесполезен в качестве ответа на вопрос.
G-Man говорит: «Восстановите Монику»
2
@ G-Man, это интересно. IIRC vimимеет такое поведение, что позволяет быстро изменять права доступа при необходимости записи в файлы только для чтения. Я проверил с strace, touchс openошибками EACCES, но последующий вызов к utimensatуспеху, поэтому я думаю, что touchв целом завершается успешно.
Муру
2
@muru: Спасибо за проверку. utimensat(2)говорит: « Требования к разрешениям: 1. Доступ на запись (или) 2. Эффективный идентификатор пользователя вызывающего абонента должен совпадать с владельцем файла…»
G-Man говорит: «Восстановите Монику»
3
Другие проблемы, например, для Champignac: >> fileне переносимо (например, запускает NULLCMD в zsh), используйте true >> fileвместо этого. И если файл является именованным каналом, он имеет неприятные побочные эффекты.
Стефан
3

G-мужчина прав: [ -w ]не всегда говорит правду. Здесь, чтобы справиться с несуществующим файлом и сообщением об отказе в доступе из оболочки:

( [ -e /path/to/file ] && >> /path/to/file ) 2> /dev/null && 
  echo writable || 
  echo not writable

Обновление : выглядит пугающе, не так ли? Ну, это так. Хм ... как это выразить ... НЕ ИСПОЛЬЗУЙТЕ ЭТО, если только вы точно не знаете, что находитесь в условиях, которые он требует для работы, как ожидается. Смотрите комментарий Стефана.

Что делать вывод тогда? Даже если [ -w ]не говорит правду, это единственная команда, которая предназначена для выполнения этой работы. Если этого не произойдет, мы обвиним в этом, напишем отчеты об ошибках, и это сработает в будущем. Лучше проверить условия, при которых он работает и использовать [ -w ]; написать специальный код для особых случаев. Обходные пути имеют свои условия.

[ -w /path/to/file ]

лучший априори .

Champignac
источник
3
Если файл является именованным каналом, он будет зависать, если нет чтения, и даже если читатель будет иметь неприятные побочные эффекты. test -wв большинстве реализаций использования access(2)должно быть достаточно для проверки разрешений.
Стефан