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

42

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

Почему мы можем манипулировать только для чтения файла в 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.

Навид Вафаей
источник
1
@Zanna У вас есть каталог, в котором находится файл?
Роб
Да, в противном случае это была бы ОГРОМНАЯ проблема :)
Роб
11
Изменение файла и замена файла - это две разные вещи с разными требованиями к разрешениям.
Дэвид Шварц
1
Возможно, вы захотите взглянуть на это . Это в основном отвечает на ваш вопрос , и как @DavidSchwartz правильно указал :Modifying a file and replacing a file are two different things
Панайотис Tabakis
@PanagiotisTabakis Очень приятно, что это замечательно .. chmod сделать файл доступным для чтения-записи и обратно, если он у вас есть .. ЛЮБИТЕ ЭТО :)
Роб

Ответы:

58

Как уже упоминалось @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не редактируется файл, к которому у вас нет прав на запись. Это удаление файла из каталога, к которому у вас есть права на запись, а затем создание нового файла, к которому у вас снова есть доступ на запись.

Тердон
источник
2
unix.stackexchange.com/questions/36467/…
Жиль "ТАК, перестань быть злым"
8
@CCJ это операция записи в каталог, но не в файл, нет. Операции записи в файлы - это те, которые изменяют содержимое файла. Точно так же создание / удаление файлов - это операции записи в каталог, так как вы меняете его содержимое.
Тердон
2
Кроме того, это опасный порядок операций. Было бы безопаснее записать замену в новое имя файла, а затем использовать rename(2)для замены старого файла. Тогда нет временного окна, в котором ваши данные не существуют на диске.
Питер Кордес
5
@PeterCordes эм, хорошо. Возможно, вы захотите направить свои жалобы разработчикам vim. Я даже не использую эту вещь, я в лагере Emacs.
Тердон
3
@CCJ Удаление файла - это операция записи в каталог, в котором он находится, а не в сам файл. Совершенно интуитивно понятно, что если вы отвечаете за каталог (то есть имеете право на запись в него), вы должны иметь возможность контролировать его содержимое, а владельцу отдельного файла нельзя разрешать переопределять вас.
fkraiem
16

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

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

Дополнение:

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

обкрадывать
источник
7
Похоже, VIM выбирает из нескольких стратегий, в том числе перезаписать на месте или отменить ссылку + написать новый файл.
Питер Кордес
3
@PeterCordes Да, очевидно, он будет очень стараться делать то, что вы говорите :) очень хитрый. :)
Роб
16

При использовании 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
Ravexina
источник
10

Смотрите :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
Мур
источник
2

Это предупреждение 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 по-прежнему будет видеть исходный файл и может свободно читать или записывать в него. Как только программа закроет файл, файл исчезнет (освободится файловой системой).

ludvik02
источник
2

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

 getpwnam("navid")->pw_uid

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

 :!chmod +w %

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

 :!rm %

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

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

 /home/whoopi/.profile

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

Роман Чиборра
источник
Спасибо @Zanna за редактирование кода, хотя это и стоило мне новичку, но заслуженно.
Роман Чиборра
1

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

Обычно, даже если файл принадлежит пользователю 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.
Падди Ландау
источник