附录

附录

以下示例显示如何创建仅具有读取权限的文件。如我们所见,当我尝试使用 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

笔记:由于旧版许可的原因,大多数 GNU/Linux 发行版都不包含 Bill Joy 编写的原始 vi 程序。相反,vi 命令是通过在 vi 兼容模式下运行 Vim 提供的。以下答案基于在 vi 兼容模式下运行 Vim。

修改只读文件

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

当父目录可由 Vim 用户写入时

!Vim 很有帮助,它让用户知道他们可以通过在该命令后附加一个感叹号来强制执行写入w。如果使用这个强制版本的写入命令,Vim 会删除原始文件(如果使用 Vim 时backup设置了 Vim-only 选项,则原始文件实际上改名与备份文件相同)。然后它会打开(创建)一个新文件一样的名字作为原始文件并将其缓冲区的内容写入此新文件。这可以通过检查索引节点运行 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)、将缓冲区写入文件、关闭文件,然后将权限改回来,从而绕过只读父目录限制。以下是通过 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

如果您使用常规保存命令(例如、或) ,大多数(如果不是全部)vi实现都会阻止您写入文件,例如:ZZ:w:wq:xvim

: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
....

在这种情况下,inode 编号保持不变。

最后,这不是一个错误,因为如果您不被允许更改文件权限,您就无法通过它进行修改vi

相关内容