如果已删除的文件仍被某个进程打开,该如何恢复?

如果已删除的文件仍被某个进程打开,该如何恢复?
$ cat important_file > /dev/null &
[1] 9711
$ rm important_file 
$ killall -STOP cat

[1]+  Stopped                 cat important_file > /tmp/p
$ ls -l /proc/`pidof cat`/fd/
total 0
lrwx------ 1 vi vi 64 May 13 20:32 0 -> /dev/pts/29
l-wx------ 1 vi vi 64 May 13 20:32 1 -> /tmp/p
lrwx------ 1 vi vi 64 May 13 20:32 2 -> /dev/pts/29
lr-x------ 1 vi vi 64 May 13 20:32 3 -> /home/vi/important_file (deleted)

如何恢复important_file

我尝试过类似

injcode -m dup2 -ofd=3 -ofilename=/tmp/recovered_file -oflags=O_CREAT $PID_OF_CAT

但它什么也不做。

答案1

如果 /home 是 NFS,则 /home/vi 中将有一个 .nfsNNNNNNNNNN 文件,您可以访问/复制该文件。如果 home 是本地文件系统,则应该能够通过 /proc/PID/fd/3 链接执行相同的操作:

cp /proc/PID/fd/3 /tmp/recovered_file

如果你想真正取消删除该文件,这里有一个博客文章就此主题而言。

答案2

... 比在给定时间进行复制(并且仅收集该文件内容在该时间的快照)更好的方法是将该tail -f文件“”复制到一个新文件中:

tail -c +0 -f /proc/PIDofProgram>/fd/# > /new/path/to/file

(感谢 tail 的细心程序员,它甚至可以处理二进制输出。)

在运行时, 本身tail -f会保持文件打开,从而安全地防止原始程序结束时文件被从磁盘清除。因此,不要tail -f在原始程序结束后立即停止 —— 首先检查 tail'ed/new/path/to/file是否你想要的。如果不是(或者由于其他原因不令人满意),你可以再次复制原始文件,但这次对它的所有写入均已由“程序”完成,并且来自仍在运行的tail -f/proc/PIDoftail/fd/ 目录。

答案3

使用 lsof 查找 inode 编号,然后使用 debugfs 重新创建指向它的硬链接。例如:

# lsof -p 12345 | grep /var/log/messages
syslogd 12345 root    3w   REG                8,3    3000    987654 /var/log/messages (deleted)
# mount | grep var
/dev/sda2 on /var type ext3 (rw)
# debugfs -w /dev/sda2
debugfs: cd log
debugfs: ln <987654> tmp
debugfs: mi tmp
                      Mode    [0100600] 
                   User ID    [0] 
                  Group ID    [0] 
                      Size    [3181271] 
             Creation time    [1375916400] 
         Modification time    [1375916322] 
               Access time    [1375939901]
             Deletion time    [9601027] 0
                Link count    [0] 1
               Block count    [6232] 
                File flags    [0x0] 
...snip...
debugfs:  q
# mv /var/log/tmp /var/log/messages
# ls -al /var/log/messages
-rw------- 0 root root 3301 Aug  8 10:10 /var/log/messages

在您抱怨之前,我伪造了上述记录,因为我现在手头没有已删除的文件;-)

我使用mi将删除时间和链接计数重置为合理值(分别为 0 和 1),但它无法正常工作 - 您可以看到链接计数保持在零ls。我认为内核可能正在缓存 inode 数据。为了安全起见,您应该在使用 debugfs 后尽早进行 fsck。

根据我的经验,您应该使用临时文件名创建链接,然后重命名为正确的名称。直接将其链接到原始文件名似乎会导致目录损坏。YMMV!

答案4

如果您的文件仍在被写入(因此您不能使用cp),而您没有使用ext(因此您不能使用debugfs),那么这里有一种不可知的方法来实现它。

但是,一旦您使用ps aux | grep或找到该过程,并且您已经通过仔细检查了已删除的文件名,lsof -p $pid -a -d $fd您可以使用以下方法生成一个新过程,其唯一的工作是恢复它:

(tail -f -n +1 --pid $pid /proc/$pid/fd/$fd) >$file </dev/null 2>&1 &

奇怪的包装只是为了防范HUP,所以请随意不使用它或将其换成nohup

相关内容