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


42

简短问题:

为什么即使没有管理员也可以使用:+ w+ q+ 在Vim中操作只读文件!

长问题:

我有一个文本文件(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您是否拥有文件所在的目录?
罗布

是的,否则这将是一个很大的问题:)
Rob

11
修改文件和替换文件是两种具有不同权限要求的不同事情。
戴维·史瓦兹

1
您可能想看看这个。它基本上可以回答您的问题,正如@DavidSchwartz正确指出的那样Modifying a file and replacing a file are two different things
Panagiotis Tabakis

@PanagiotisTabakis非常高兴发现这很棒。.chmod使文件可读写,如果您拥有它,则再次返回..喜欢它:)
Rob

Answers:


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这不是在编辑您没有写权限的文件。它是从您具有写访问权的目录中删除文件,然后创建一个新的文件(您再次拥有写访问权)。



8
@CCJ是对目录的写操作,而不是文件的写操作,不。对文件的写操作是更改文件内容的操作。同样,创建/删除文件是对目录的写操作,因为您正在更改其内容。
terdon

2
而且,这是危险的操作顺序。将替换内容写入新文件名,然后用于rename(2)替换旧文件会更安全。然后,没有时间窗口,磁盘上不存在您的数据。
彼得·科德斯

5
@PeterCordes嗯,好的。不过,您可能希望将投诉直接转给vim开发人员。我什至不使用它,我在emacs营地。
terdon

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

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节点中的文件具有权限。目录结构在某种程度上是分开的,并且仅链接这些索引节点。目录也具有其权限,该权限表明您是否可以将文件链接/取消链接到文件中,读取文件还是遍历子目录。这种设计允许同一文件可以出现在目录结构中的几个不同位置(通过硬链接)。通过说“添加!覆盖”,VIM试图警告您原始文件将被取消链接(因此它将保持在所有其他位置不变),并且将创建新文件并将其链接到目录结构中的原始位置。如果原始文件的链接计数减少到零,则原始文件将被释放,但是如果没有,则实际上是在克隆文件。打开文件也算作链接,因此,如果某个程序打开了文件,并且您同意“添加!要覆盖”,则该程序将不会看到您使用VIM对文件所做的更改。仅通过VIM从目录取消链接该文件,并且在通过另一个程序关闭该文件后,该文件将被释放,除非在其他位置链接了该文件。

请注意,在Windows中,文件的权限存储在目录中,因此从Windows权限范例的角度来看,这种vim行为的确可能看起来很奇怪。为了写入文件,Windows逻辑上可能还会检查某些目录权限,甚至超级目录权限。如上所述,在UNIX中,只要可以列出并打开文件,目录权限与文件操作无关(即,所有超级目录都为x)。如果在UNIX中打开的文件在打开后与所有目录都未链接,则可能甚至没有文件名。

例如,您有文件/ home / user1 / foo,它与/ home / user2 / foo是同一文件(即,硬链接到/ home / user2 / foo),并且任何人都无法写该文件,并且该文件当前由程序P打开(由程序由root启动)。如果user1用vim打开它并覆盖,则他将创建自己的副本,并且不再看到原始文件。如果随后user2用vim打开他的链接并写入该链接,它将再次解除链接,并创建另一个副本。程序P仍将看到原始文件,并且可以自由读取或写入原始文件。程序关闭文件后,文件将消失(由文件系统释放)。


2

vim编辑器过程和文件都携带

 getpwnam("navid")->pw_uid

所有权,以便您也可以掏空

 :!chmod +w %

您可能会猜到,从前

 :!rm %

(仅需要+ w,ut unlink权限,甚至没有所有权)对于某人来说变得太频繁了,以至于vim被重新编程为自动提供并根据请求自动执行这样的操作。

尝试覆盖你大姐姐的

 /home/whoopi/.profile

因为单纯的赌注和赌注是您的vim会给您您所希望的拒绝。


谢谢@Zanna进行代码编辑,尽管这值得我新手花点时间,但理应如此。
Roman Czyborra

1

这并不是完全正确的答案,但是如果您真的想设置一个文件,使任何人都无法更改或删除它,则可以使其不可变。

通常,即使文件是root拥有的,如果您对该文件夹具有写权限,您仍然可以删除该文件。但是,当您使文件不可变时,即使root用户也无法修改或删除它。

要使文件不可变(您需要sudo):

sudo chattr +i myFile.txt

您可以通过lsattri结果中的字母)看到它:

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