一、背景
在很多Linux系统运维工作中,很多人会遇到敲错命令,或复制命令出错,或直接执行了rm -rf命令,事后才恍然大悟,闯下大祸,抛开问题,如果真的遇到这种情况,我们该如何应对呢,跑路是一个可选项,显然有人不答应!基于此,本文来研究下如何利用一些手段、工具完成紧急情况下的数据恢复,将损失降到最小。
二、数据删除的原理
Linux系统中文件删除的原理是通过文件系统的机制实现的。Linux系统上的文件名是存储在父目录的Block里面的,并指向了这个文件的Inode节点,这个文件的Inode节点再标记指向存放这个文件的Block的数据块。从文件存储特性来看,一个文件在文件系统中的存放分为两个部分:数据部分和指针部分,指针位于文件系统的meta-data中,当用户删除文件时,系统首先会将该文件的索引节点标记为已删除,即这个指针就从meta-data中清除了,而数据部分存储在磁盘block中,等待新的数据到来进行分配,该文件占用的存储空间被释放。但是,再文件没有实际分配到该block块存储空间之前,实际上文件的内容并没有被立即删除,还是留在磁盘上,如果这时对该数据块重新建立索引(link),即标记为数据占用,同步更新node MAP和Block MAP,则该数据相当于被“恢复”,所占的空间也就不会再“释放”给其他数据来使用了。
Linux系统是通过Link的数量来控制文件是否被删除的,只有当一个文件不存在任何Link的时候,这个文件才会被删除,一般每个文件都有2个Link计数器,既i_count和i_nlink。 i_nlink的意义就是硬链接的数量,i_nlink可以理解为磁盘的引用计数器;i_count的意义就是当前文件使用者(例如,被进程调用)的数量,i_count可以理解为内存的引用计数器。当为文件创建硬链接的时候,对应i_nlink的数量就会增加,而当一个文件被某个进程调用时,对应i_count的数量就会增加。通过rm删除命令删除文件,实际上就是减少文件的磁盘引用计数i_nlink的数量(及硬链接的数量)。如果在执行rm删除命令之前有程序调用了该文件,调用还没有结束;此时执行rm命令后,i_nlink=0(硬链接数为0),但是i_count不为0,因为此时还有程序在调用该文件,该文件会继续占用磁盘空间。只能i_nlink和i_count同时为0时,该文件才是被成功删除。代码层面也可参看Linux删除文件过程解析来理解。
在Linux中,文件系统使用了超级块(superblock)来管理文件的生命周期。超级块包含了文件系统的元数据信息,包括文件系统类型、块大小、inode数量等。文件系统通过分析超级块来确定文件系统的类型,并根据文件系统类型的不同来执行相应的删除操作。研究表明,rm大文件会导致IO问题,当我们直接rm一个大文件时,大量的日志更新操作将会影响到其他进程的I/O性能。如果其他进程是I/O密集型的程序,以MySQL为例,rm大文件与之同时运行将会使得其QPS降低,响应时间也会增加。 为避免这种影响,不应该直接使用rm对大文件进行删除,而应该采用其他方法。例如,可每次将大文件truncate一部分并sleep一段时间,将删除的I/O负载分散到每次truncate操作,不会出现I/O负载在一段时间内突然增高的现象。或者直接echo写空也行,$ > access.log
常用几种清空大文件的命令示例:
# : 符号,它是 shell 的一个内置命令,等同于 true 命令,都是输出重定向(置空)到文件中
$: > access.log# true > access.log
#利用/dev/null
cat /dev/null > access.log
dd if=/dev/null of=access.log
cp /dev/null access.log
echo "" > access.log #这个只是空字符,cat会看懂啊一个空行
echo > access.log
echo -n "" > access.log #使用-n参数,告诉 echo 不再像上面的那个命令那样输出结尾的那个新行
#用 truncate 命令来清空文件内容,它常被用来将一个文件缩小或者扩展到某个给定的大小
truncate -s 0 access.log #s参数指定文件的大小
#删除文件名带有空格或特殊字符的文件
rm "file name with space.txt"
rm file\ name\ with\ space.txt
对于仍被进程或其他窗口占用的误删除文件恢复,请参看:Linux文件系统使用率过高清理文件后空间未成功释放处理,这里重点说下那些已经未被进程占用,已被确认删除的场景,主要借助工具实现。
三、使用工具恢复文件
注:如果是系统根分区遭到误删除,就要进入单用户模式,将根分区以只读的方式挂载,尽可能避免数据被覆盖。
1)extundelete工具
它使用存储在分区日志中的信息,尝试恢复已从ext3或ext4的分区中删除的文件,恢复仍有一定的机率失败,提前只读并做好备份。extundelete下载地址:http://extundelete.sourceforge.net/,extundelete官方地址(官方文档):http://extundelete.sourceforge.net
wget https://nchc.dl.sourceforge.net/project/extundelete/extundelete/0.2.4/extundelete-0.2.4.tar.bz2
yum -y install bzip2 gcc-c++ build-essential e2fslibs-dev e2fslibs-dev e2fsprogs-devel e2fsprogs
tar jxvf extundelete-0.2.4.tar.bz2 #解压该文件
cd extundelete-0.2.4
./configure
make && make install
#备份被删文件所在目录到sdc1分区,如果提示设备busy,可以用fuser命令强制卸载:
fuser -m -v -i -k ./
dd if=/path/filename of=/dev/sdc1
#卸载删除数据所在盘
umount
mkdir recovertest
extundelete /dev/sdb1 --inode 2 #按i节点恢复,加入在sdb1分区,根分区的inode值是2
extundelete /dev/sdb1 --restore-file 待恢复的单个文件 #恢复文件是放到了当前目录
extundelete /dev/sdb1 --restore-directory 待恢复的目录名
extundelete /dev/sdb1 --restore-all #恢复所有
extundelete /dev/sdb1 --restore-inode 14 #恢复指定的inode,注意恢复inode的时候,恢复出来的文件名和之前不一样,需要单独进行改名
2)Knoppix工具
Knoppix是从损坏的机器中恢复数据的最佳工具之一。它有一个可引导的CD版本,友好的用户界面。它可以让你轻松安装驱动器,然后复制数据。 Knoppix自身携带了一整套的Linux命令。
官方网站:http://www.knopper.net/knoppix/index-en.html
3)Trinity rescue kit工具
它是专为Linux设计的,是一款恢复和修复操作的免费软件。它有一个易于使用的滚动文本菜单,只要有键盘和懂点英文就可以在计算机上执行维护和修理操作,工作范围从密码重置、磁盘清理再到病毒扫描等等。可以在以下三方面使用TRK:
官方网站:http://trinityhome.org/Home/index.php?wpid=1&front_id=12
4)Ddrescue
Ddrescue的目的是将这个文件中的数据复制到另一个。这对恢复放在崩溃和损坏磁盘上的数据非常有帮助。 Ddrescuelog是操纵ddrescue日志文件的工具,能显示日志文件的内容,实现日志文件与其他格式文件的相互转换、压缩日志文件、测试救援状态等,并且在完成救援之后还可以删除日志文件。此外,ddrescue的基本操作都是全自动的。
官方网站:http://www.gnu.org/software/ddrescue/ddrescue.html
5)Test disk
它是基于GNU通用公共许可证授权的开源软件。它也是免费的数据恢复软件。Test disk可以帮助你修复分区表、恢复已删除的分区、修复FAT表和重建NTFS引导扇区。这个软件还能从备份中恢复NTFS引导扇区。Test disk非常易于操作,使用非常简单。
如果你主要是想恢复视频、文档和归档类文件,你应该试试PhotoRec。PhotoRec的优点在于它完全忽略了文件系统,只去搜寻底层的数据。这表示如果设备损坏或者被重新格式化了PhotoRec仍然能工作。
为了防止在使用PhotoRec时所产生的任何问题,该工具在恢复数据时采用只读方式——这样它就不会意外地覆盖掉你希望得到恢复的数据。使用PhotoRec时请注意,一旦你需要恢复某个文件,请立刻停止任何的写磁盘操作。否则就会存在底层的数据被新写入的数据覆盖的可能,那样就没法再恢复了。
注意:使用这个工具时有很多的选项可供使用,包括可选择你希望恢复的文件扩展名,因此为了能正确使用这个工具请先查看工具的文档说明。要安装这个工具,你可以在软件源中搜索testdisk或photorec。
官方网站:http://www.cgsecurity.org/wiki/TestDisk
6)System rescue CD
SystemrescueCD能帮助你修复系统和数据,并且它也是一种Linux系统急救盘,可作为可引导的CD ROM和USB存储器用于管理。该软件提供了处理各种任务的工具,例如分区操作、文件恢复、硬盘测试以及硬盘格式化。此数据恢复工具还可以用于Linux和Windows电脑。
官方网站:http://www.sysresccd.org/SystemRescueCd_Homepage
7)Ubuntu rescue remix
Ubuntu Rescue Remix是最好的Linux数据恢复工具之一,是一种GNU/ Linux的实时系统。它简直就是数据恢复专家,配置了免费的开源数据恢复和取证工具的命令行界面环境。这个工具在恢复和救援文件、系统文件,以及修复来自非标准外部驱动器的数据时,非常有用。它可以用一种非常简单的方法恢复删除的文件。
官方网站:http://ubuntu-rescue-remix.org/
8)Stellar
Stellar可以恢复基于Linux卷上丢失了的、格式化的和被删除的数据。它可以恢复基于Linux卷的Ext4、Ext3、FAT32、FAT16以及FAT12文件系统的数据。它可以恢复所有丢失的文件、目录和硬卷。它可以轻易地恢复所有可用的硬驱类型数据,包括SCCI、ATA、EIDE和IDE。而且界面非常友好,可以形象化整个硬盘、卷和其他任何选定的区域。
官方网站:http://www.stellarinfo.com/linux-data-recovery.htm
9)R-studio
该软件拥有灵活的参数和自定义设置。它能让用户完全控制数据恢复的任务。它可以恢复来自Windows、FreeBSD/open BSD/NetBSD/ Solaris和Macintosh格式化磁盘上的文件。它可以恢复已经在计算机中删除并被垃圾桶清空的文件。它还可以安全地恢复由于病毒、断电或突然关机而损坏的文件。
官方网站:http://www.r-tt.com/data_recovery_linux/
10)F-Secure Rescue CD
此Linux数据恢复工具基于Linux OS的Knnopix衍生产品,可以帮助用户从CD运行软件,并检查已安装了的应用程序的完整性。F-Secure Rescue安能让你轻松地执行高级数据修复和恢复操作。
官方网站:https://www.f-secure.com/en/web/labs_global/rescue-cd11
11)foremost工具
是一款根据文件头,尾和内部结构来尝试从镜像文件(或者磁盘)中恢复文件的工具。foremost 默认可以扫描出 jpg, gif, png, bmp, avi, exe, mpg, mp4, wav, riff, wmv, mov, pdf, ole, doc, zip, rar, html, cpp 文件。另还可通过配置它的配置文件(默认为 /etc/foremost.conf),你还可以为它增加新的支持类型。CentOS/RHEL 7,它是目前在生产环境使用最广泛的工具。
rpm -Uvh https://rpmfind.net/linux/dag/redhat/el7/en/x86_64/dag/RPMS/foremost-1.5.7-1.el7.rf.x86_64.rpm
#验证
foremost -h #常用选项释义:
-t:指定要恢复的文件类型如jpeg,pdf,exe,doc等,如果要恢复所有文件类似,指定参数值为"all"即可。
-d:打开间接块检测(对于 UNIX 文件系统)。
-i:指定输入文件(默认为标准输入)。
-a:不执行错误检测(损坏的文件)。
-w:只输出审计文件,不输出被删除的文件至磁盘上。
-o:设置输出目录(默认为输出)。
#示例
sudo foremost -t 文件类型 -i 被删除文件的磁盘/镜像文件 -o 临时存储恢复文件的分区目录
sudo formost -t db -i /dev/sda1 -T #T 选项让 foremost 自动根据当前时间戳来生成 output 目录,目录格式类似:output_Thu_Mar__8_11_43_40_2018
#扫描整个磁盘或镜像文件来查找可能的文件,这常常是一个很漫长的过程,可以使用 -q 来加快扫描速度。当启用 -q 选项后, foremost 会仅仅在每个扇区的开始位置与文件头进行对比,这会极大地减少扫描时间,但可能会丢失一些嵌套在其他文件内的文件(比如嵌套在doc文件中的图片)
sudo formost -q -t png -i /dev/sda1 -T
sudo formost -q -b 4096 -t png -i /dev/sda1 -T #-b number, 它可以指定磁盘每个扇区的大小,默认是512个字节。但对于 ext4 文件系统来说,这个值一般是 4096,具体可通过 dumpe2fs 来查看
sudo dumpe2fs /dev/sda1 |grep "Block size" |cut -f2 -d ":"
#综上,合并如下
TYPE=$1
DIR=$2
fs=$(df ${DIR}|tail -n 1 |cut -f 1 -d " ")
block_size=$(sudo dumpe2fs ${fs} |grep "Block size" |cut -f2 -d ":")
foremost -t ${TYPE} -q -b ${block_size} -i ${fs} -T