12

В следующем примере показано, как создать файл только с разрешениями на чтение. Как мы видим, когда я пытаюсь записать в этот файл с помощью команды echo, полученной мной, Permission denied .

Но почему, если мы используем vi, мы не получим Permission denied? Как можно видеть здесь, мы можем записать в файл, даже если файл доступен только для чтения.

Что здесь происходит? Это ошибка ви?

[admin@madona-machine1 ~]$ touch test-file
[admin@madona-machine1 ~]$ ls -ltr
total 0
-rw-r--r-- 1 admin admin 0 Apr 13 07:32 test-file
[admin@madona-machine1 ~]$ chmod -w  test-file
[admin@madona-machine1 ~]$ ls -ltr
total 0
-r--r--r-- 1 admin admin 0 Apr 13 07:32 test-file
[admin@madona-machine1 ~]$ echo try_to_write > test-file
-bash: test-file: Permission denied
[admin@madona-machine1 ~]$ vi test-file

I am good singer,

 ~
 ~
 ~
 ~
 ~
 ~
 ~                                                
   "test-file" 1L, 4C written

2 ответа2

27

Примечание . Из-за устаревших причин лицензирования большинство дистрибутивов GNU/Linux не содержат оригинальную программу vi, написанную Биллом Джой. Вместо этого команда vi предоставляется при запуске Vim в режиме совместимости с vi. Следующий ответ основан на запуске Vim с его режимом совместимости с vi.

Изменение файла только для чтения

Vim предупреждает пользователя, если он изменяет буфер файла только для чтения, W10: Warning: Changing a readonly file только для чтения. Если пользователь пытается записать в этот файл, он получает следующее сообщение об ошибке, 'readonly' option is set (add ! to override) .

Когда родительский каталог доступен для записи пользователем Vim

Vim, будучи полезным, позволяет пользователю знать, что он может настаивать на написании, добавляя восклицательный знак ! к команде w . Если используется эта принудительная версия команды записи, Vim удаляет исходный файл (при использовании Vim с установленным параметром backup только для Vim исходный файл фактически переименовывается, чтобы совпадать с файлом резервной копии). Затем он открывает (создает) новый файл с тем же именем, что и оригинал, и записывает содержимое своего буфера в этот новый файл. Это можно увидеть, проверив inode файла до и после запуска Vim:

$ ls -l --inode t

131529 -r--r--r-- 1 anthony anthony 0 Apr 13 09:23 t

$ vi t
$ ls -l --inode t

131649 -r--r--r-- 1 anthony anthony 4 Apr 13 09:23 t

Примечание. Это также может изменить разрешение и владельца файла и разорвать (символические) ссылки, например, если исходный файл принадлежит другому пользователю, новый файл будет принадлежать пользователю, работающему под управлением Vim.

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

Когда родительский каталог недоступен для записи пользователем Vim

Однако даже в этом случае Vim по-прежнему старается помочь настойчивому пользователю перезаписать файл. Если пользователь Vim владеет файлом, Vim может обойти ограничение родительского каталога только для чтения, временно изменив разрешение файла (используя системный вызов chmod ), записав буфер в файл, закрыв файл, а затем изменив разрешения назад. Вот выдержка из системных вызовов, выполняемых при запуске vi через strace, strace -o ../vi.trace vi t:

getuid()                                = 501
chmod("t", 0100644)                     = 0
open("t", O_WRONLY|O_CREAT|O_TRUNC, 0644) = 4
write(4, "I am good singer,\n", 18)     = 18
fsync(4)                                = 0
close(4)                                = 0
chmod("t", 0100444)                     = 0

Примечание. Этого не происходит, если пользователь Vim редактирует файл, владельцем которого он не является, поскольку Vim не сможет изменить права доступа к файлу.

добавление

Чтобы быть уверенным, что файл не может быть изменен (в системе GNU/Linux), запустите команду chattr от имени суперпользователя:

sudo chattr +i filename

От man chattr:

Файл с атрибутом «i» не может быть изменен: его нельзя удалить или переименовать, нельзя создать ссылку на этот файл и данные не могут быть записаны в файл. Только суперпользователь или процесс, обладающий возможностью CAP_LINUX_IMMUTABLE, может установить или очистить этот атрибут.

5

Большинство, если не все реализации vi не позволяют вам записать файл, если вы используете обычную команду сохранения, например ZZ :w :wq или :x , например, с vim:

:w
E45: 'readonly' option is set (add ! to override)

С другой стороны, если вы скажете vi написать файл, несмотря на его разрешения, используя что-то вроде :x! или :wq! редактор временно ослабляет права доступа для записи файла:

...
stat("test-file", {st_mode=S_IFREG|0444, st_size=7, ...}) = 0
getuid()                                = 1000
chmod("test-file", 0100644)             = 0
...
open("test-file", O_WRONLY|O_CREAT|O_TRUNC, 0644) = 4
write(4, "I am good singer,\n", 18)               = 18
fsync(4)                                = 0
close(4)                                = 0
chmod("test-file", 0100444)             = 0
....

В этом случае номер индекса остается неизменным.

Наконец, это не ошибка, так как если вам не разрешено изменять права доступа к файлам, вы не можете изменить его с помощью vi .

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .