最近我遇到了一个奇怪的问题,于是到英文论坛上找了下,下面是我的搬运:
提问者:
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文件一样,等于是被重新利用了)。我猜测这就是文件描述符不变的原因。