1.背景
如果使用rm -rf 误删除数据,我们怎么恢复误删除的数据呢?
2.场景分析
删除数据主要有两种场景:
- 场景一 在执行rm -rf 删除文件时,该文件正在被进程使用。
- 场景二 这个文件没有被进程占用,从而被误删除
在场景一,对于进程正在使用的场景,数据可以恢复是因为Linux里每个文件都有2个link计数器:i_count和i_nlink
i_count: 当一个文件被一个进程引用时,它的数值会加1,也就是说它记录的是文件被进程引用的次数。
i_nlink: 记录文件产生硬链接的个数。
Linux系统只有在两个数值都清零的时候,文件才被系统认为是删除的,假设此时删除文件有进程在使用,那么i_conunt数值不为0。
在场景二,此时i_count和i_nlink都为0,inode连接信息已经被删除了,我们就需要通过存放文件的block单元,做数据块的数据找回。
找回数据需要依赖两个关键的参数:
inode: 用于存放文件的相关元数据,它的元数据里会有一个类似于索引的值,能够索引到后面具体存放数据的block单元
block: 是一个数据块,用来实际存放数据
所以理论上可以通过block块找回数据,因为上面保存着真实的数据。
风险:如果有进程在在不断地往磁盘写数据时,需要申请新的block块,如果操作系统分配已删除的block块时,新写入的数据就会覆盖原来的数据,此时就会造成数据真正丢失。
在这种情况下,应该第一时间umount目录所在的磁盘,或者不对磁盘进行任何写入,以保证理论数据还存在磁盘上,那么还可以通过相关分析找回数据。
3.场景一演示
场景一搭建:
首先准备测试的文件aaa.txt,内容为运维贼船公众号的域名,在终端一中执行:
# 创建测试文件夹
mkdir /tmp/test
# 创建测试文件
echo "aaa.al" > /tmp/test/aaa.txt
创建完文件后,使用进程打开它并保持占用,这里用tail -f来模拟:
tail -f /tmp/test/aaa.txt
此时,新开一个终端二,删除aaa.txt文件。
rm -rf /tmp/test/aaa.txt
此时的状态为终端一仍在占用进程,终端二中把文件删除掉了。
场景一恢复:
下面执行恢复操作,使用lsof命令:
# lsof | grep 删除的文件名,如:
lsof | grep aaa.txt
可以看到查询出来的结果处于“deleted”的状态,我需要找到此进程的pid,比如我这里的结果pid为1364000。
根据pid号查找文件句柄:
# cd /proc/记录的pid号/fd,如:
cd /proc/1364000/fd
ll
恢复文件,执行以下命令,可以看到数据已经恢复回来了。
cp 3 /tmp/test/aaa.txt.bak
cat /tmp/test/aaa.txt.bak
4.场景二演示
场景二搭建:
我们这里使用单独的一块硬盘来做演示,我这里的硬盘是/sdb1,格式为ext3.
挂载的目录为/test
我这里在挂载的目录创建aaa.txt,写入内容和aaa的文件夹。
echo "aaa.al" > /test/aaa.txt
mkdir -p /test/aaa
cd /test
ls
然后对硬盘内容删除:
cd /test
rm -rf *
ls
场景二恢复:
恢复前需要对硬盘进行取消挂载:
umount /test -l
# 创建一个用于恢复数据的目录
mkdir /tmp/test
cd /tmp/test
执行extundelete命令,如果没有此命令,可以直接安装:
yum -y install epel-release
yum -y install extundelete
完成后,执行命令,可以看到最后显示出误删除的文件,状态为Deleted。
extundelete /dev/sdb1 --inode 2
开始恢复文件,找到我们需要恢复文件的Inode number,比如我这里图示为12,则执行以下命令。
extundelete /dev/sdb1 --restore-inode 12
执行后,会在当前目录下生成RECOVERED_FILES目录,里面包含我们恢复的文件:
通过查看文件内容,发现和我们需要恢复的文件一致,只是文件名不一样,手动修改即可。
同样的方式,我们还可以恢复文件夹和所有文件,命令格式如下: