恢复 apache 打开的已删除文件?

恢复 apache 打开的已删除文件?

假设 apache 日志文件被删除,但 apache 仍保持打开状态;那么这就是我正在做的事情:

pid=$(lsof | grep text.txt | awk '/deleted/ {print $2}')
fd=$(lsof | grep text.txt | awk '/deleted/ {print $4}' | grep -oE "[[:digit:]]{1,}")

cp /proc/$pid/fd/$fd directorytobecopied/testfile.txt

这就是我正在做的恢复文件并将其放回原来的位置。有没有更简单的方法可以做到这一点,因为上面的代码看起来不太好。此外,我如何知道文件从哪里被删除(待复制目录)这样我就不必手动询问某人文件最初所在的位置并将其放回原处。

答案1

如果一个文件已被删除但仍然打开,则意味着该文件仍然存在于文件系统中(它有一个索引节点)但有一个硬链接计数为 0。由于没有指向该文件的链接,因此您无法按名称打开它。也没有通过索引节点打开文件的工具。

无法通过文件系统发现该文件,尤其是无法在该文件最后所在的目录中查找该文件。目录条目消失了。剩下的就是文件本身。您可以使用文件系统调试器访问该文件,但这需要 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 特定的)。

相关内容