为什么我可以修改只读文件?

Pos*_*vid 42 vim permissions command-line chmod read-only

简短问题:

我们为什么可以操纵使用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
Run Code Online (Sandbox Code Playgroud)

我可以在没有管理员权限的情况下用 Vim 打开它:

navid@navid-ThinkPad-T530:~/ubuntuTest$ vi myFile.txt 
Run Code Online (Sandbox Code Playgroud)

我修改它并按:Esc+ :+ w+ q+Enter我看到这个错误信息:

E45: 'readonly' option is set (add ! to override)
Run Code Online (Sandbox Code Playgroud)

到目前为止,一切都说得通。但是当我按下:Esc+ :+ w+ q+ !+ 时Enter,Vim 会保存更改。

我使用的是 Ubuntu 16.04 和 VIM 7.4。

ter*_*don 58

正如@Rob 已经提到的,只有当您对包含文件的目录具有写访问权限时才能执行此操作。例如,尝试对文件执行相同的操作/etc将失败。

至于如何 vim做到这一点,它会删除文件并重新创建它。为了测试这一点,我创建了一个由 root 拥有的文件:

echo foo | sudo tee fff
Run Code Online (Sandbox Code Playgroud)

然后继续以vim您描述的方式编辑文件,但附上该过程strace以查看发生了什么:

strace vim fff 2> strace.out
Run Code Online (Sandbox Code Playgroud)

然后我检查strace.out并发现:

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

因此,文件首先被删除 ( unlink("fff")),然后创建了一个同名的新文件 ( open("fff", O_WRONLY|O_CREAT|O_TRUNC, 0644)) 并将我所做的修改写入其中 ( write(4, "foasdasdao\n", 11))。如果您在家尝试此操作,您会看到在使用 编辑它之后vim,该文件现在属于您而不是 root。

因此,严格来说,vim不是在编辑您没有写权限的文件。它是从您有写访问权限的目录中删除一个文件,然后创建一个新文件,您也有写访问权限。

  • @CCJ 这是对 *directory* 的写操作,但不是对文件的写操作,不是。对文件的写操作是更改文件内容的操作。出于同样的原因,创建/删除文件是对目录的写操作,因为您正在更改其内容。 (8认同)
  • @PeterCordes 嗯,好的。不过,您可能希望将您的投诉直接发送给 vim 开发人员。我什至不使用这个东西,我在 emacs 阵营。 (5认同)
  • @CCJ 删除文件是对包含它的目录的写操作,而不是对文件本身的写操作。完全直观的是,如果您负责一个目录(即,对其具有写访问权限),您应该能够控制其中的内容,并且不应允许单个文件的所有者覆盖您。 (3认同)
  • http://unix.stackexchange.com/questions/36467/why-inode-value-changes-when-we-edit-in-vi-editor (2认同)
  • 此外,这是一个危险的操作顺序。将替换写入新文件名,然后使用 `rename(2)` 替换旧文件会更安全。然后没有时间窗口在磁盘上不存在您的数据。 (2认同)
  • @PeterCordes Vim 几乎总是在磁盘上有一个 .swp 文件来保护您的数据;看看强制关闭是否会改变操作顺序会很有趣。 (2认同)
  • 这个答案对我来说听起来像是“权限模型已损坏”。你说文件是只读的,只是我可以随意更改内容。 (2认同)
  • @DeadMG 权限模型很好,你只是误解了它是如何工作的。如果您对目录具有写访问权限,则意味着您具有在该目录中创建和删除文件的完全访问权限。这是正常的,在所有权限系统中都是如此。因此,您可以删除并重新创建文件。你不能*修改*文件。如果要将文件设为只读,则不要将其放在可写入的目录中。称该系统损坏就像抱怨有人在您将钥匙交给他们时打开了您的保险箱。 (2认同)

Rob*_*Rob 15

只要您拥有父目录,无论权限如何,您都可以删除或替换文件,因为您可以更改目录的内容:)。

用 rm 之类的其他命令试试,它会提示你,但你仍然可以这样做。使目录不可写,这应该停止它。

添加:

刚刚尝试过,但只要我拥有该文件,我仍然可以修改它,即使文件夹是只读的。但是,当我将所有权更改为 root:root 时,它无法打开文件进行写入。所以解决了root(或其他人)拥有的修改文件

  • 听起来 VIM 从多种策略中进行选择,包括就地重写或取消链接+写入新文件。 (7认同)
  • @PeterCordes 是的,它显然会非常努力地按照您的指示去做:) 非常狡猾。:) (3认同)

Rav*_*ina 15

使用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
Run Code Online (Sandbox Code Playgroud)

现在让我切换用户并更改文件

$ 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
Run Code Online (Sandbox Code Playgroud)

现在看看里面有什么:

$ cat foo/file
bye
Run Code Online (Sandbox Code Playgroud)


mur*_*uru 9

: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).
Run Code Online (Sandbox Code Playgroud)

由于您对该目录具有写权限(意味着您可以在其中创建、删除或重命名文件),因此系统确实允许它。


的默认值cpoptions不包含W

                                                'cpoptions' 'cpo' cpo
'cpoptions' 'cpo'       string  (Vim default: "aABceFs",
                                 Vi default:  all flags)
                        global
Run Code Online (Sandbox Code Playgroud)