Vi可以写入文件,尽管文件是只读的


12

以下示例显示如何创建仅具有读取权限的文件。如我们所见,当我尝试使用echo命令写入此文件时,得到了Permission denied

但是,为什么在我们使用vi的情况下,我们没有得到Permission denied?从这里可以看出,即使文件是只读的,我们也可以写入文件。

这是怎么回事 这是vi错误吗?

[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

1
仅供参考,有一个Beta SE网站-vi.stackexchange.com
Raystafarian 2015年

Answers:


28

注意:由于遗留许可证的原因,大多数GNU / Linux发行版不包含Bill Joy编写的原始vi程序。而是通过在vi兼容模式下运行Vim来提供vi命令。以下答案是基于以vi兼容模式运行Vim的。

修改只读文件

如果Vim修改了只读文件的缓冲区,它将警告用户W10: Warning: Changing a readonly file。如果用户尝试写入此文件,则会收到以下错误消息'readonly' option is set (add ! to override)

当上级目录可由Vim用户写入时

Vim很有帮助,它使用户知道他们可以通过!w命令后附加一个感叹号来强制坚持写。如果使用了此强制版本的write命令,Vim会删除原始文件(如果将Vim与Vim-only backup选项一起使用,则原始文件实际上会重命名为与备份文件相同)。然后,它将打开(创建)一个与原始文件同名新文件,并将其缓冲区的内容写入该新文件。这可以通过在运行Vim之前和之后检查文件的inode来观察:

$ 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系统调用),将缓冲区写入文件,关闭文件,然后更改文件名,来绕过只读父目录限制。权限退回。以下是通过strace运行vi时进行的系统调用的摘要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功能的进程才能设置或清除此属性。


2
神圣的烟雾,那是彻底的!
卡米尔·古德塞内

4
@CamilleGoudeseune在发布答案的第一个版本之后,我做了一些实验,最终花了大约一个小时通过strace运行Vim,以查看它在不同情况下在幕后所做的事情(权限的不同排列以及文件和文件的所有权和所有权)。父目录)。有时我会迷失方向,但是一旦发布答案,我就想确保自己说的是正确的。
Anthony Geoghegan 2015年

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


哈哈!发布答案后,我做了一些实验,最终花了将近一个小时的时间通过strace运行Vim,以了解在不同情况下(文件和父目录的权限和所有权的不同排列)它在后台的作用。对实验结果进行总结后,我才看到您的答案。这是一次很好的学习经历。
Anthony Geoghegan 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.