cp覆盖vs rm然后cp


18

当我试图覆盖当前推出的二进制文件,cp无法覆盖,但它可能rm然后它cp。例如:

user@poste:~$ cp binaryFile /tmp
user@poste:~$ sudo cp /tmp/binaryFile binaryFile 
[sudo] password for user:
cp: cannot create regular file `binaryFile`: Text file busy
user@poste:~$ sudo rm binaryFile 
user@poste:~$ sudo cp /tmp/binaryFile  binaryFile 
user@poste:~$ file binaryFile 
binaryFile : ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x7ce005d9eb50e2574246b6a881e625802f7e49f2, not stripped

知道为什么吗?


2
有趣的小线程,但应该在Unix / Linux.SE IMO上。
underscore_d

Answers:


41

在第一种情况下,您试图覆盖当前正在作为程序运行的文件的内容。Linux不允许这样做-如果这样做,您将在操作系统执行代码时立即覆盖代码;第一个区别是程序会崩溃或使其出现故障。

但是在第二种情况下,您实际上并没有更改旧文件的内容,而是在原位置创建了一个文件,而旧文件只是丢失了文件名,但保持其内容不变。

(请记住,rm技术上讲不会删除文件,它只会删除目录链接-类似于ln将更多链接添加到同一文件的方式。只有当文件没有链接没有打开的文件引用时,它才会被自动删除。)

系统通过它们的inode引用正在使用的文件,因此它们具有相同的文件名并不重要-它仍然是由系统保持打开状态的文件,即使它不再具有链接,也只会被删除。一旦所有程序将其关闭。


7
经常使用相同逻辑的另一个技巧:在软件中打开一个(临时)文件并立即将其删除,而无需先关闭该文件。您的程序仍然可以按其希望的方式使用它,并且当程序关闭(受控)程序或忘记关闭程序(例如,程序崩溃而没有清理)时,它将被操作系统自动删除。(程序结束,无论如何发生,都会释放对程序的所有引用到文件。)
Tonny

2
这就是为什么当您删除正在运行的进程的某些日志文件时,df命令在停止进程之前不会返回更正的大小
M4rty

外部程序(具有root特权)是否可以找到任何方法并为此悬空的inode创建新句柄?我想象有一些程序将其用作“安全功能”,因此了解整个故事很有趣。

3
@BenPen:是的,在Linux上–用于/proc/*/fd访问它,并可选地使用linkat()向文件系统添加新链接。
grawity

3
@BenPen和grawity:实际上,出于安全原因即使linkat()索引节点具有零个链接(即使有零个链接),也无法将其链接回目录结构。(例外规则:除非你用创建open(O_TMPFILE)因此它开始以零个链接。)如果你想,linkat()返回ENOENT,甚至是root。请参阅我对这个问题的回答,以使Perl脚本真正运行linkat并证明它不起作用,即使是root用户也是如此:/
Peter Cordes
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.