最近我遇到了一个奇怪的问题,于是到英文论坛上找了下,上面是我的搬运:
提问者:
Witness the following:
请看上面的命令:
sh-3.2$ cd testcase
sh-3.2$ sudo touch temp
sh-3.2$ ls -al
total 0
drwxr-xr-x 3 glen staff 102 19 Dec 12:38 .
drwxr-xr-x 12 glen staff 408 19 Dec 12:38 ..
-rw-r--r-- 1 root staff 0 19 Dec 12:38 temp
sh-3.2$ echo nope > temp
sh: temp: Permission denied
sh-3.2$ vim temp
# inside vim
itheivery
# press [ESC]
:wq!
# vim exits
sh-3.2$ ls -al
total 8
drwxr-xr-x 3 glen staff 102 19 Dec 12:38 .
drwxr-xr-x 12 glen staff 408 19 Dec 12:38 ..
-rw-r--r-- 1 glen staff 7 19 Dec 12:38 temp
Somehow vim has taken this root-owned file, and changed it into a user owned file!
This only seems to work if the user owns the directory – but it still feels like it shouldn’t be possible. Can anyone explain how this is done?
vim 是怎么把这个原本属于 root 的文件变成是用户的文件的哇?
而且仿佛之后当用户领有该文件所属目录拥有权时才会产生这种状况,不过我仍然感觉这不可能产生。有人晓得这是怎么回事吗?
最佳答复:
You, glen, are the owner of the directory (see the . file in your listing). A directory is just a list of files and you have the permission to alter this list (e.g. add files, remove files, change ownerships to make it yours again, etc.). You may not be able to alter the contents of the file directly, but you can read and unlink (remove) the file as a whole and add new files subsequently[1].Only witnessing the before and after, this may look like the file has been altered.
Vim uses swap files and moves files around under water, so that explains why it seems to write to the same file as you do in your shell, but it’s not the same thing[2].
Glen 同志,你是这个目录的拥有者. 要晓得,所谓目录仅仅是一些文件的列表,而你又有着扭转这一列表的权限。(比如说增加文件,删除文件,扭转拥有权等)你兴许并不能间接扭转这个文件的内容,你却可能读取或是 unlink(勾销链接 / 删除 rm)这一整个文件,随后还能增加新的文件[1]。通过这一系列过程后,这看起来就像是文件被更改了一样。(同时所有权也变了)
Vim 应用交换文件(swap file)和挪动文件操作(move file)来实现读写操作,就解释了为什么你好似做了更改文件的操作一样,但实际上,你用 vim 所做的和改写原文件并不是同种操作[2]。
So, what Vim does, comes down to this:
因而 vim 在后盾其实做了像这样一些操作:
cat temp > .temp.swp # 把文件内容复制到一个阿 Glen 所属的文件中
echo nope >> .temp.swp # 变更新文件的内容
rm temp && mv .temp.swp temp #把文件再写回原来的文件处
[1] This is an important difference in file permission handling between Windows and Unices. In Windows, one is usually not able to remove files you don’t have write permission for.
这就是类 Unix 零碎与 Windows 零碎在解决文件权限上的一个重要不同:在 windows 里没有写权限,你是不能删除文件的
[2] update: as noted in the comments, Vim does not actually do it this way for changing the ownership, as the inode number on the temp file does not change (comparing ls -li
before and after). Using strace we can see exactly what vim does. The interesting part is here:
更新:像评论中说的那样,vim 实际上并不是这样扭转所有权的,因为 ”temp” 文件中的 inode 号并没有变(用 ls -li
比拟之前和之后). 用 strace
能精确看出 vim 干了什么. 乏味的是这里:
open("temp", O_WRONLY|O_CREAT|O_TRUNC, 0664) = -1 EACCES // 关上文件失败,没有权限
unlink("temp") = 0
open("temp", O_WRONLY|O_CREAT|O_TRUNC, 0664) = 4
write(4, "more text bla\n", 14) = 14
close(4) = 0
chmod("temp", 0664) = 0
This shows that it only unlinks, but does not close the file descriptor to temp. It rather just overwrites its whole contents (more text bla\n
in my case). I guess this explains why the inode number does not change.
这显示了 vim 仅仅 unlink,却不敞开指向 temp 的文件描述符。而仅仅在它的整个内容上笼罩(也就是说把 temp 删掉之后,零碎获得的文件描述符依然和之前的 temp 文件一样,等于是被从新利用了)。我猜想这就是文件描述符不变的起因。