最近我遇到了一个奇怪的问题,于是到英文论坛上找了下,上面是我的搬运:

提问者:

Witness the following:
请看上面的命令:

sh-3.2$ cd testcasesh-3.2$ sudo touch tempsh-3.2$ ls -altotal 0drwxr-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 tempsh-3.2$ echo nope > tempsh: temp: Permission deniedsh-3.2$ vim temp# inside vimitheivery# press [ESC]:wq!# vim exitssh-3.2$ ls -altotal 8drwxr-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")                               = 0open("temp", O_WRONLY|O_CREAT|O_TRUNC, 0664) = 4write(4, "more text bla\n", 14)              = 14close(4)                                     = 0chmod("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文件一样,等于是被从新利用了)。我猜想这就是文件描述符不变的起因。