如果文件已删除但仍处于打开状态,则意味着该文件仍存在于文件系统中(它具有一个inode),但是硬链接数为0。由于没有指向该文件的链接,因此无法按名称打开它。也没有设施可以通过inode打开文件。
无法通过文件系统发现文件,尤其是无法在最后一个文件的目录中查找文件。目录条目不见了。剩下的就是文件本身。您可以使用文件系统调试器访问该文件,但这需要root权限,并且难以使用且容易出错。
Linux通过/proc
。下的特殊符号链接公开打开的文件。这些链接被称为/proc/12345/fd/42
,其中12345是进程的PID,而42是该进程中文件描述符的编号。以与该进程相同的用户身份运行的程序可以访问该文件(读/写/执行权限与删除该文件时的权限相同)。
在符号链接的目标中仍可以看到打开文件所用的名称:如果文件是/var/log/apache/foo.log
,则链接的目标为/var/log/apache/foo.log (deleted)
。(如果文件在打开后被重命名,则符号链接的目标可能反映了重命名。)
因此,给定已打开的已删除文件的进程的PID和打开该文件的描述符,就可以恢复该文件的内容:
recover_open_deleted_file () {
old_name=$(readlink "$1")
case "$old_name" in
*' (deleted)')
old_name=${old_name%' (deleted)'}
if [ -e "$old_name" ]; then
new_name=$(TMPDIR=${old_name%/*} mktemp)
echo "$oldname has been replaced, recovering content to $new_name"
else
new_name="$old_name"
fi
cat <"$1" >"$new_name";;
*) echo "File is not deleted, doing nothing";;
esac
}
recover_open_deleted_file "/proc/$pid/fd/$fd"
如果您只知道进程ID但不知道描述符,则可以使用以下命令恢复所有文件
for x in /proc/$pid/fd/*; do
recover_open_deleted_file "$x"
done
如果您也不知道进程ID,则可以在所有进程中搜索:
for x in /proc/[1-9]*/fd/*; do
case $(readlink "$x") in
/var/log/apache/*) recover_open_deleted_file "$x";;
esac
done
您还可以通过解析的输出来获取此列表lsof
,但这并不简单,也不可靠,也不易移植(无论如何,这是特定于Linux的)。
lsof / | awk '(/deleted/||/abc.txt/) {print "FD :-",$4,"| File Name:-",$9}'