Почему я могу изменить файл только для чтения?

Краткий вопрос:

Почему мы можем манипулировать файлом только для чтения в Vim с помощью : + w + q + ! даже не будучи администратором?

Длинный вопрос:

У меня есть текстовый файл (myFile.txt), который доступен только для чтения всем:

navid@navid-ThinkPad-T530:~/ubuntuTest$ ls -l myFile.txt 
-r--r--r-- 1 navid navid 26 Aug 22 21:21 myFile.txt

Я могу открыть его с помощью Vim, не имея прав администратора:

navid@navid-ThinkPad-T530:~/ubuntuTest$ vi myFile.txt 

Я изменяю его и нажимаю: Esc + : + w + q + Enter и вижу это сообщение об ошибке:

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

Пока все имеет смысл. Но когда я нажимаю: Esc + : + w + q + ! + Enter, Vim сохраняет изменения.

Я использую Ubuntu 16.04 и VIM 7.4.

7 ответов

Решение

Как уже упоминалось@Rob, вы можете сделать это, только если у вас есть права на запись в каталог, содержащий файл. Попытка сделать то же самое с файлом, например, /etc не удастся.

Что касается того, как vim делает это, он удаляет файл и воссоздает его. Чтобы проверить это, я создал файл, принадлежащий пользователю root:

echo foo | sudo tee fff

А затем приступил к редактированию файла с vim так, как вы описываете, но прикрепляя процесс к strace чтобы увидеть, что происходит:

strace vim fff 2> strace.out

Я тогда проверил strace.out и нашел:

unlink("fff")                           = 0
open("fff", O_WRONLY|O_CREAT|O_TRUNC, 0644) = 4
write(4, "foasdasdao\n", 11)            = 11

Итак, файл был сначала удален (unlink("fff")), затем был создан новый файл с тем же именем (open("fff", O_WRONLY|O_CREAT|O_TRUNC, 0644)) и сделанные мной изменения были записаны в него (write(4, "foasdasdao\n", 11)). Если вы попробуете это дома, вы увидите, что после редактирования с vim, файл теперь будет принадлежать вам, а не root.

Так что, строго говоря, vim не редактирует файл, к которому у вас нет прав записи. Это удаление файла из каталога, к которому у вас есть права на запись, а затем создание нового файла, к которому у вас снова есть доступ на запись.

Пока у вас есть родительский каталог, вы можете удалить или заменить файл независимо от разрешения, так как вы можете изменять содержимое каталога:).

Попробуйте с другой командой, такой как rm, она подскажет вам, но вы все равно можете это сделать. Сделайте каталог недоступным для записи, и это должно его остановить.

Дополнение:

Только что попробовал, но пока у меня есть файл, я могу изменять его, даже если папка доступна только для чтения. Однако, когда я меняю владельца на root: root, он не может открыть файл для записи. Так решает модифицирующие файлы, принадлежащие root (или кому-то еще)

С помощью w! вы удаляете исходный файл (что вам разрешено делать) и вместо этого пишете свою версию.

Когда у вас есть права на запись в каталог, вы можете: создавать, перемещать или удалять файлы в этом каталоге.

$ mkdir foo
$ echo hi > foo/file
$ chmod 777 foo
$ chmod 700 foo/file
$ ls -l foo/file 
-rwx------ 1 ravexina ravexina 7 Aug 31 03:19 foo/file

Теперь позвольте мне переключить моего пользователя и изменить файл

$ sudo -u user2 -s
$ vi foo/a # save using w! (I wrote into the file bye)
$ ls -l foo/a
-rwx------ 1 user2 user2 7 Aug 31 03:20 foo/file

Теперь посмотрим, что там:

$ cat foo/file
bye

Увидеть :help write-readonly:

                                                        write-readonly
When the 'cpoptions' option contains 'W', Vim will refuse to overwrite a
readonly file.  When 'W' is not present, ":w!" will overwrite a readonly file,
if the system allows it (the directory must be writable).

Поскольку у вас есть права на запись в каталог (то есть вы можете создавать, удалять или переименовывать файлы в нем), система разрешает это.


Значение по умолчанию cpoptions не содержит W:

                                                'cpoptions' 'cpo' cpo
'cpoptions' 'cpo'       string  (Vim default: "aABceFs",
                                 Vi default:  all flags)
                        global

И ваш редактор vim, и ваш файл несут

 getpwnam("navid")->pw_uid

владение, чтобы вы могли также раскошелиться

 :!chmod +w %

и вы можете догадаться, что когда-то еще проще

 :!rm %

(требующий только + w, но без разрешения на связь. и даже не владение) стал слишком частым для того, чтобы кто-то печатал, так что vim был перепрограммирован, чтобы автоматически предлагать и по запросу автоматически выполнять такую ​​операцию.

Попробуйте переписать вашу старшую сестру

 /home/whoopi/.profile

как простой navid и ставки - ваш vim дает вам желаемый отказ.

Это предупреждение VIM, которое может быть относительно важным, учитывая то, как работают разрешения в UNIX. Кажущаяся неочевидность этого заключается в том, что файловые системы UNIX имеют разрешения для файла, хранящегося в i-узле файла. Структура каталогов как-то отделена и связывает только эти i-узлы. Каталоги также имеют свои разрешения, которые говорят, можете ли вы связывать / отсоединять файлы в нем, или читать их, или переходить в подкаталоги. Такая конструкция позволяет одному и тому же файлу появляться в нескольких разных местах в структуре каталогов (через жесткие ссылки). Говоря "добавить! Переопределить", VIM пытается предупредить вас, что исходный файл будет не связан (так что он останется во всех других местах нетронутым), и новый файл будет создан и связан с исходным местом в структуре каталога. В случае, если количество ссылок исходного файла уменьшается до нуля, исходный файл будет освобожден, но если нет, вы фактически клонируете файл. Открытие файла также считается ссылкой, поэтому, если какая-то программа открыла файл, и вы согласились "добавить! Для переопределения", программа не увидит изменения, внесенные вами в файл с помощью VIM. Файл удаляется только из VIM из каталога, и после закрытия файла другой программой файл будет освобожден, если только он не был связан где-то еще.

Обратите внимание, что в Windows разрешения для файлов хранятся в каталоге, поэтому с точки зрения парадигмы разрешений Windows это поведение vim действительно может выглядеть странно. Для записи в файл Windows может также логически проверять некоторые разрешения для каталогов, даже разрешения для супер-каталогов. Как уже говорилось выше, в UNIX права доступа к каталогу не имеют значения для манипулирования файлом, поскольку вы смогли отобразить его и открыть его (т. Е. Для всех суперкаталогов было x). У открытого файла в UNIX может даже не появиться имя файла, если после открытия он был удален из всех каталогов.

Например, у вас есть файл /home/user1/foo, и он является тем же файлом, что и (то есть жестко связан с) /home/user2/foo, и файл никем не доступен для записи и в настоящее время открыт программой P (открыт для чтения-записи программа запущена от рута). Если пользователь1 открывает его с помощью vim и перезаписывает, он делает свою собственную копию и больше не видит исходный файл. Если впоследствии user2 откроет свою ссылку с помощью vim и запишет в нее, она снова будет не связана, и он создаст другую копию. Программа P по-прежнему будет видеть исходный файл и может свободно читать или записывать в него. Как только программа закроет файл, файл исчезнет (освободится файловой системой).

Это не совсем ответ, но если вы действительно хотите установить файл так, чтобы никто не мог изменить или удалить его, вы можете сделать его неизменным.

Обычно, даже если файл принадлежит пользователю root, вы можете удалить его, если у вас есть права на запись в папку. Но когда вы делаете файл неизменным, даже root не может изменить или удалить его.

Чтобы сделать файл неизменным (вам нужно sudo):

sudo chattr +i myFile.txt

Вы можете увидеть это с lsattr (письмо i в результате):

$ lsattr myFile.txt
----i--------e-- myFile.txt

Чтобы снова сделать файл нормальным:

sudo chattr -i myFile.txt

Для пояснения: если файл является неизменным, его нельзя удалить, переименовать, изменить или даже жестко связать.

Это стоит прочитать man chattrпотому что файлы могут иметь ряд полезных атрибутов.

Вы также можете найти "ограниченное удаление" полезным. Если он помещен в папку (не в файл), это означает, что любому, кто создает файл в папке, разрешается изменять или удалять этот файл, но никто другой (кроме корневого) не имеет. Папка /tmp имеет этот флаг установлен. Вы можете увидеть это с t флаг на /tmp:

$ ls -l --directory /tmp
drwxrwxrwt 10 root root 4096 Sep  6 09:00 /tmp

Чтобы установить или удалить флаг ограниченного удаления для папки:

chmod +t myFolder      # Add the restricted deletion flag.
chmod -t myFolder      # Remove the restricted deletion flag.
Другие вопросы по тегам