在Linux文件系统中,文件实际上是指向索引节点的链接,该索引节点包含文件的属性,例如所有权,权限,数据块的地址等。当使用rm命令删除文件时,将删除指向其索引节点的链接,但不指向索引节点的链接。其他进程仍可以将其打开。完成操作后,所有链接都将被删除,一个inode及其指向的数据块可用于写入。
现在,如果某个进程仍打开了文件,那么数据就在某个地方,即使根据列出的目录,该文件似乎已经消失了。Linux进程伪文件系统/ proc目录在这里生效。系统上的每个进程都有一个带有其名称的目录,其中包含许多内容,例如:文件描述符,它是一个子目录,包含指向该进程已打开的所有文件的链接。即使文件已从文件系统中删除,该数据的副本也将在那里:
/ proc /进程id / fd / file_descriptor
现在找到它,您需要获取打开了文件的进程的ID,以及文件描述符。这些是通过lsof获得的,这意味着“列出打开的文件”。
一旦从lsof获得了该信息,就可以从/ proc中复制数据并获得(实际上)丢失的内容。
您可以使用以下示例对此进行测试
首先,创建一个文本文件,您可以将其删除然后再带回:
$ man lsof | col -b > test_file
然后看一下您刚刚创建的文件的内容:
$ less test_file
您应该看到lsof的大型手册页的纯文本版本看着您,礼貌些。
现在按Ctrl-Z暂停less。返回一个shell提示符,确保您的文件仍然存在:
$ ls -l test_file
-rw-r--r--. 1 root root 124467 Oct 14 13:42 test_file
# stat test_file
File: ‘test_file’
Size: 124467 Blocks: 248 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 2149553030 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2019-10-14 13:42:13.633798195 +0800
Modify: 2019-10-14 13:42:08.749021536 +0800
Change: 2019-10-14 13:42:08.749021536 +0800
Birth: -
$ rm test_file
$ stat test_file
stat: cannot stat ‘test_file’: No such file or directory
在这里,我们绝不能允许仍然使用该文件的进程退出,因为一旦发生这种情况,该文件将真正消失并且您的麻烦将会加剧。现在,如果这是您正在播放的视频或声音文件,那么当您意识到已删除文件时,要做的第一件事就是立即暂停应用程序的播放,或者冻结该过程,以便它最终不会停止播放文件并退出。
现在将文件带回来。首先,看看lsof必须说些什么:
$ lsof | grep test_file
less 2615 root 4r REG 253,0 124467 2149553030 /root/test_file (deleted)
第一列为您提供与该进程关联的命令的名称,第二列为该进程的ID,第四列中的数字为文件描述符(“ r”表示它是常规文件)。现在您知道进程2615仍然打开了文件,并且知道了文件描述符4。这就是将其从/ proc中复制出来所需要的一切。
我们可能会认为,将-a标志与cp一起使用是正确的做法,因为我们正在还原文件,但是实际上不要这样做很重要。否则,您将不复制文件中包含的文字数据,而只是将一个现在断开的符号链接复制到该文件,因为该文件曾经在其原始目录中列出:
$ ls -l /proc/2615/fd/4
lr-x------. 1 root root 64 Oct 14 13:45 /proc/2615/fd/4 -> /root/test_file (deleted)
$ cp /proc/2615/fd/4 test_file
最后,确认您做得不错:
$ ls -l test_file
-rw-r--r--. 1 root root 124467 Oct 14 13:48 test_file
$ man lsof | col -b> test_file1
$ cmp test_file test_file1
文件没有差异,这表明还原成功。