被覆盖的文件可以恢复吗?

Que*_*low 59 ext4 data-recovery

我不是在谈论恢复 已删除的文件,而是在谈论覆盖的文件。即通过以下方法:

# move
mv new_file old_file

# copy
cp new_file old_file

# edit
vi existing_file
> D
> i new_content
> :x
Run Code Online (Sandbox Code Playgroud)

假设 linux 机器上没有安装特殊程序,如果执行上述三个操作中的任何一个,是否可以检索任何内容?

Mar*_*ick 79

答案是“可能是的,但这取决于文件系统类型和时间。”

这三个示例都不会覆盖 old_file 或 existing_file 的物理数据块,除非偶然。

  • mv new_file old_file. 这将取消链接 old_file。如果有额外的指向 old_file 的硬链接,则这些剩余链接中的块将保持不变。否则,这些块通常(取决于文件系统类型)被放置在空闲列表中。然后,如果mv需要复制(与仅移动目录条目相反),新块将作为mv写入分配。

    这些新分配的块可能与刚刚释放的相同,也可能不同。在像UFS这样的文件系统上,如果可能的话,从与创建文件的目录相同的柱面组中分配块。因此有可能从目录中取消链接文件并在同一目录中创建文件将重新使用(并覆盖)一些刚刚释放的相同块。这就是为什么对于意外删除文件的人的标准建议是,在有人可以尝试恢复文件之前,不要将任何新数据写入其目录树中的文件(最好不要写入整个文件系统)。

  • cp new_file old_file将执行以下操作(您可以使用它strace来查看系统调用):

    打开(“旧文件”,O_WRONLY|O_TRUNC)= 4

    O_TRUNC 标志将导致所有数据块被释放,就像mv上面所做的那样。如上所述,它们通常会被添加到空闲列表中,并且可能会或可能不会被cp命令完成的后续写入重用。

  • vi existing_file. 如果vivim,则该:x命令执行以下操作:

    unlink("existing_file~") = -1 ENOENT(没有那个文件或目录)
    重命名(“existing_file”,“existing_file~”)= 0
    打开(“现有文件”,O_WRONLY|O_CREAT|O_TRUNC,0664)= 3

    所以它甚至不会删除旧数据;数据保存在备份文件中。

    在 FreeBSD 上,vidoesopen("existing_file",O_WRONLY|O_CREAT|O_TRUNC, 0664)cp上面的 ,具有相同的语义。


无需特殊程序即可恢复部分或全部数据;您所需要的只是grepdd,以及对原始设备的访问。

对于小文本文件,@Steven D在您链接的问题grep中的答案中的单个命令是最简单的方法:

grep -i -a -B100 -A100 'text in the deleted file' /dev/sda1
Run Code Online (Sandbox Code Playgroud)

但是对于可能位于多个非连续块中的较大文件,我这样做:

grep -a -b "text in the deleted file" /dev/sda1
13813610612:this is some text in the deleted file
Run Code Online (Sandbox Code Playgroud)

这将为您提供匹配行的字节偏移量。使用一系列dd命令遵循此命令,从

dd if=/dev/sda1 count=1 skip=$(expr 13813610612 / 512)
Run Code Online (Sandbox Code Playgroud)

您还想在该块之前和之后读取一些块。在 UFS 上,文件块通常为 8KB,并且通常分配得相当连续,单个文件的块与来自其他文件或可用空间的 8KB 块交替交错。UFS 上的文件尾部最多有 7 个 1KB 片段,这些片段可能是连续的,也可能不是连续的。

当然,在压缩或加密数据的文件系统上,恢复可能不是那么简单。


实际上,Unix 中很少有实用程序会覆盖现有文件的数据块。一个想到的是dd conv=notrunc。另一个是shred

  • 感谢您解释三种不同操作的内部机制。这真的很有用! (4认同)
  • @EerikSvenPuudist 这可能发生,因为 grep 尝试逐行读取输入,并且在具有随机字节的磁盘分区上,行可能很长。[这个问题](https://unix.stackexchange.com/questions/90036/grep-memory-exhausted) 的答案中有一个解决方法。而不是`grep -i -a -B100 -A100 '已删除文件中的文本' /dev/sda1`,试试`tr -s "\0" "\n" < /dev/sda1 | grep -i -a -B100 -A100 '已删除文件中的文本'` (2认同)

And*_*dyM 7

确保 /var/tmp 或某个大的地方有足够的磁盘空间。

尝试

 grep -i -a -B100 -A100 'a string unique to your file' /dev/sda1 |
 strings > /var/tmp/my-recovered-file
Run Code Online (Sandbox Code Playgroud)

其中 /dev/sda1 将是您系统上的磁盘。

然后在 my-recovered-file 中搜索您的字符串。

可能主要在那里,如果您发现它检查缺少的行空间、方括号、符号等。

使用文件中相当独特的搜索词或字符串,以减少文件中的数据量。如果您搜索诸如“echo”之类的词,您将返回大量字符串,因为系统将有很多文件中包含“echo”一词。


Sai*_*ire 6

我要说不(用一个巨大的星号)。

想想数据是如何放置在磁盘上的。您有包含数据并指向下一个块(如果有)的块。

当您覆盖数据时,您正在更改块内容(如果您要扩展文件的所有结束标记)。所以应该无法恢复任何东西(见下文)。

如果您缩短文件,那么您将丢失旧块,它们很快就会被回收。如果您是一名程序员,请考虑一个链表,在该链表中,您“丢失”了一半的列表,而没有执行释放/删除操作。该数据仍然存在,但祝您找到它时好运。

考虑碎片化可能会很有趣。

当您的磁盘上有不连续数据的“漏洞”时,就会发生碎片。这可能是由于修改文件导致您扩展或缩短它们并且它们不再适合磁盘上的原始位置。

如果文件超过其原始大小(此时需要移动),根据您的文件系统,您可以将整个文件复制到旧数据仍然存在的新位置(但标记为空闲)或者您只是更改旧的结束指针并将其指向新位置(这会导致颠簸)。

长话短说,您的数据可能会丢失(无需经过在显微镜下查看的极端取证过程);然而,它有可能仍然存在。

  • 您的回答假设正在使用基于块的非写时复制文件系统,例如 `ext4` 或 `xfs`。使用诸如`zfs` 和`btrfs` 之类的写文件系统复制,你实际上*从不*“改变块内容”;这些文件系统总是使用全新的块来包含新数据。此外,像`jffs2`这样的基于日志的文件系统也总是将新数据写入新位置(不是“块”,那些文件系统不是基于块的)。话虽如此,这并不意味着可以轻松找到旧数据所在的位置并在回收空间之前进行查找。所以你的答案是否定的,仍然是正确的 (2认同)

小智 5

TL;DR - 如果被覆盖的文件仍然被正在运行的进程保持打开状态,那么这篇博客文章可能会拯救你的培根:

https://www.linux.com/news/bring-back-deleted-files-lsof/

其中,它讨论了已删除的文件,但即使文件被 rsync 覆盖,我也很幸运。我说的是一个 60 GB 的文件被 4 MB 的文件覆盖,我能够恢复原始文件,因为幸运的是我没有停止使其保持打开状态的运行进程。