如何恢复 Linux 上删除的文件 ext2

2023-11-07 17:32
文章标签 linux 恢复 删除 ext2

本文主要是介绍如何恢复 Linux 上删除的文件 ext2,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

                原贴:http://www.linuxeden.com/html/sysadmin/20080311/50582.html                       
           
                       
           
           
           
           
                        <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>           
要想恢复误删除的文件,必须清楚数据在磁盘上究竟是如何存储的,以及如何定位并恢复数据。本文从数据恢复的角度,着重介绍了 ext2 文件系统中使用的一些基本概念和重要数据结构,并通过几个实例介绍了如何手工恢复已经删除的文件。最后针对 ext2 现有实现存在的大文件无法正常恢复的问题,通过修改内核中的实现,给出了一种解决方案。
           

对于很多 Linux 的用户来说,可能有一个问题一直都非常头疼:对于那些不小心删除的数据来说,怎样才能恢复出来呢?大家知道,在 Windows 系统上,回收站中保存了最近使用资源管理器时删除的文件。即便是对于那些在命令行中删除的文件来说,也有很多工具(例如recover4all,FinalData Recovery)可以把这些已经删除的文件恢复出来。在Linux 下这一切是否可能呢?

           

实际上,为了方便用户的使用,现在 Linux 上流行的桌面管理工具(例如gnome和KDE)中都已经集成了回收站的功能。其基本思想是在桌面管理工具中捕获对文件的删除操作,将要删除的文件移动到用户根目录下的 .Trash 文件夹中,但却并不真正删除该文件。当然,像在 Windows 上一样,如果用户在删除文件的同时,按下了 Shift 键并确认删除该文件,那么这个文件就不会被移动到 .Trash 文件夹中,也就无从恢复了。此时,习惯了使用 Windows 上各种恢复工具的人就会顿足捶胸,抱怨 Linux 上工具的缺乏了。但是请稍等一下,难道按照这种方式删除的文件就真的无从恢复了么?或者换一个角度来看,使用 rm 命令删除的文件是否还有办法能够恢复出来呢?

           

背景知识

           

在开始真正进行实践之前,让我们首先来了解一下在 Linux 系统中,文件是如何进行存储和定位的,这对于理解如何恢复文件来说非常重要。我们知道,数据最终以数据块的形式保存在磁盘上,而操作系统是通过文件系统来管理这些数据的。ext2/ext3 是 Linux 上应用最为广泛的文件系统,本文将以 ext2 文件系统为例展开介绍。

           

我们知道,在操作系统中,文件系统是采用一种层次化的形式表示的,通常可以表示成一棵倒置的树。所有的文件和子目录都是通过查找其父目录项来定位的,目录项中通过匹配文件名可以找到对应的索引节点号(inode),通过查找索引节点表(inode table)就可以找到文件在磁盘上的位置,整个过程如图1所示。

           

图 1. 文件数据定位过程文件数据定位过程

           

对于 ext2 类型的文件系统来说,目录项是使用一个名为 ext2_dir_entry_2 的结构来表示的,该结构定义如下所示:

           

清单 1. ext2_dir_entry_2 结构定义           

                                                                                                           
                       
                struct ext2_dir_entry_2 {        __le32  inode;                  /* 索引节点号 */        __le16  rec_len;                /* 目录项的长度 */        __u8    name_len;               /* 文件名长度 */        __u8    file_type;              /* 文件类型 */        char    name[EXT2_NAME_LEN];    /* 文件名 */};
                       
           

           

在 Unix/Linux 系统中,目录只是一种特殊的文件。目录和文件是通过 file_type 域来区分的,该值为 1 则表示是普通文件,该值为 2 则表示是目录。

           

对于每个 ext2 分区来说,其在物理磁盘上的布局如图 2 所示:

           

图 2. ext2 分区的布局ext2 分区的布局

           

从图 2 中可以看到,对于 ext2 文件系统来说,磁盘被划分成一个个大小相同的数据块,每个块的大小可以是1024、2048 或 4096 个字节。其中,第一个块称为引导块,一般保留做引导扇区使用,因此 ext2 文件系统一般都是从第二个块开始的。剩余的块被划分为一个个的块组,ext2 文件系统会试图尽量将相同文件的数据块都保存在同一个块组中,并且尽量保证文件在磁盘上的连续性,从而提高文件读写时的性能。

           

至于一个分区中到底有多少个块组,这取决于两个因素:

           
  1.                
  2. 分区大小。
  3.                
  4. 块大小。
  5.            
           

最终的计算公式如下:

           

分区中的块组数=分区大小/(块大小*8)

           

这是由于在每个块组中使用了一个数据块位图来标识数据块是否空闲,因此每个块组中最多可以有(块大小*8)个块;该值除上分区大小就是分区中总的块组数。

           

每个块组都包含以下内容:

           
  1.                
  2. 超级块。存放文件系统超级块的一个拷贝。
  3.                
  4. 组描述符。该块组的组描述符。
  5.                
  6. 数据块位图。标识相应的数据块是否空闲。
  7.                
  8. 索引节点位图。标识相应的索引节点是否空闲。
  9.                
  10. 索引节点表。存放所有索引节点的数据。
  11.                
  12. 数据块。该块组中用来保存实际数据的数据块。
  13.            
           

在每个块组中都保存了超级块的一个拷贝,默认情况下,只有第一个块组中的超级块结构才会被系统内核使用;其他块组中的超级块可以在 e2fsck 之类的程序对磁盘上的文件系统进行一致性检查使用。在 ext2 文件系统中,超级块的结构会通过一个名为 ext2_super_block 的结构进行引用。该结构的一些重要域如下所示:

           

清单 2. ext2_super_block 结构定义           

                                                                                                           
                       
                struct ext2_super_block {        __le32  s_inodes_count;         /* 索引节点总数 */        __le32  s_blocks_count;         /* 块数,即文件系统以块为单位的大小 */        __le32  s_r_blocks_count;       /* 系统预留的块数 */        __le32  s_free_blocks_count;    /* 空闲块数 */        __le32  s_free_inodes_count;    /* 空闲索引节点数 */        __le32  s_first_data_block;     /* 第一个可用数据块的块号 */        __le32  s_log_block_size;       /* 块大小 */        __le32  s_blocks_per_group;     /* 每个块组中的块数 */        __le32  s_inodes_per_group;     /* 每个块组中的索引节点个数 */        ...}
                       
           

           

每个块组都有自己的组描述符,在 ext2 文件系统中是通过一个名为 ext2_group_desc的结构进行引用的。该结构的定义如下:

           

清单 3. ext2_group_desc 结构定义           

                                                                                                           
                       
                /* * Structure of a blocks group descriptor */struct ext2_group_desc{        __le32  bg_block_bitmap;        /* 数据块位图的块号 */        __le32  bg_inode_bitmap;        /* 索引节点位图的块号 */        __le32  bg_inode_table;         /* 第一个索引节点表的块号 */        __le16  bg_free_blocks_count;   /* 该组中空闲块数 */        __le16  bg_free_inodes_count;   /* 该组中空闲索引节点数 */        __le16  bg_used_dirs_count;     /* 该组中的目录项 */        __le16  bg_pad;        __le32  bg_reserved[3];};
                       
           

           

数据块位图和索引节点位图分别占用一个块的大小,其每一位描述了对应数据块或索引节点是否空闲,如果该位为0,则表示空闲;如果该位为1,则表示已经使用。

           

索引节点表存放在一系列连续的数据块中,每个数据块中可以包括若干个索引节点。每个索引节点在 ext2 文件系统中都通过一个名为 ext2_inode 的结构进行引用,该结构大小固定为 128 个字节,其中一些重要的域如下所示:

           

清单 4. ext2_inode 结构定义           

                                                                                                           
                       
                /* * Structure of an inode on the disk */struct ext2_inode {        __le16  i_mode;         /* 文件模式 */        __le16  i_uid;          /* 文件所有者的 uid */        __le32  i_size;         /* 以字节为单位的文件长度 */        __le32  i_atime;        /* 最后一次访问该文件的时间 */        __le32  i_ctime;        /* 索引节点最后改变的时间 */        __le32  i_mtime;        /* 文件内容最后改变的时间 */        __le32  i_dtime;        /* 文件删除的时间 */        __le16  i_gid;          /* 文件所有者的 gid */        __le16  i_links_count;  /* 硬链接数 */        __le32  i_blocks;       /* 文件的数据块数 */        ...        __le32  i_block[EXT2_N_BLOCKS];/* 指向数据块的指针 */        ...};
                       
           

           

第一个索引节点所在的块号保存在该块组描述符的 bg_inode_table 域中。请注意 i_block 域,其中就包含了保存数据的数据块的位置。有关如何对数据块进行寻址,请参看后文“数据块寻址方式”一节的内容。

           

需要知道的是,在普通的删除文件操作中,操作系统并不会逐一清空保存该文件的数据块的内容,而只会释放该文件所占用的索引节点和数据块,方法是将索引节点位图和数据块位图中的相应标识位设置为空闲状态。因此,如果我们可以找到文件对应的索引节点,由此查到相应的数据块,就可能从磁盘上将已经删除的文件恢复出来。

           

幸运的是,这一切都是可能的!本文将通过几个实验来了解一下如何从磁盘上恢复删除的文件。

           

           

                                                                                                           
           

           

数据块寻址方式

           

回想一下,ext2_inode 结构的 i_block 域是一个大小为 EXT2_N_BLOCKS 的数组,其中保存的就是真正存放文件数据的数据块的位置。通常来说,EXT2_N_BLOCKS 大小为 15。在 ext2 文件系统,采用了直接寻址和间接寻址两种方式来对数据块进行寻址,原理如图3 所示:

           

图 3. 数据块寻址方式数据块寻址方式

           
  •                
  • 对于 i_block 的前 12 个元素(i_block[0]到i_block[11])来说,其中存放的就是实际的数据块号,即对应于文件的 0 到 11 块。这种方式称为直接寻址。
  •                
  • 对于第13个元素(i_block[12])来说,其中存放的是另外一个数据块的逻辑块号;这个块中并不存放真正的数据,而是存放真正保存数据的数据块的块号。即 i_block[12] 指向一个二级数组,其每个元素都是对应数据块的逻辑块号。由于每个块号需要使用 4 个字节表示,因此这种寻址方式可以访问的对应文件的块号范围为 12 到 (块大小/4)+11。这种寻址方式称为间接寻址。
  •                
  • 对于第14个元素(i_block[13])来说,其中存放也是另外一个数据块的逻辑块号。与间接寻址方式不同的是,i_block[13] 所指向的是一个数据块的逻辑块号的二级数组,而这个二级数组的每个元素又都指向一个三级数组,三级数组的每个元素都是对应数据块的逻辑块号。这种寻址方式称为二次间接寻址,对应文件块号的寻址范围为 (块大小/4)+12 到 (块大小/4)2+(块大小/4)+11。
  •                
  • 对于第15个元素(i_block[14])来说,则利用了三级间接索引,其第四级数组中存放的才是逻辑块号对应的文件块号,其寻址范围从 (块大小/4)2+(块大小/4)+12 到 (块大小/4)3+ (块大小/4)2+(块大小/4)+11。
  •            
           

ext2 文件系统可以支持1024、2048和4096字节三种大小的块,对应的寻址能力如下表所示:

           

表 1. 各种数据块对应的文件寻址范围           

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
块大小 直接寻址 间接寻址 二次间接寻址 三次间接寻址
1024 12KB 268KB 64.26MB 16.06GB
2048 24KB 1.02MB 513.02MB 265.5GB
4096 48KB 4.04MB 4GB ~ 4TB
           

           

掌握上面介绍的知识之后,我们就可以开始恢复文件的实验了。

           

           

                                                                                                           
           

           

准备文件系统

           

为了防止破坏已有系统,本文将采用一个新的分区进行恢复删除文件的实验。

           

首先让我们准备好一个新的分区,并在上面创建 ext2 格式的文件系统。下面的命令可以帮助创建一个 20GB 的分区:

           

清单 5. 新建磁盘分区           

                                                                                                           
                       
                # fdisk /dev/sdb << ENDn+20GpwqEND
                       
           

           

在笔者的机器上,这个分区是 /dev/sdb6。然后创建文件系统:

           

清单 6. 在新分区上创建 ext2 文件系统           

                                                                                                           
                       
                # mke2fs /dev/sdb6
                       
           

           

并将其挂载到系统上来:

           

清单 7. 挂载创建的 ext2 文件系统           

                                                                                                           
                       
                # mkdir /tmp/test# mount /dev/sdb6 /tmp/test
                       
           

           

在真正使用这个文件系统之前,让我们首先使用系统提供的一个命令 dumpe2fs 来熟悉一下这个文件系统的一些具体参数:

           

清单 8. 使用 dumpe2fs 熟悉这个文件系统的参数           

                                                                                                           
                       
                # dumpe2fs /dev/sdb6 dumpe2fs 1.39 (29-May-2006)Filesystem volume name:   <none>Last mounted on:          <not available>Filesystem UUID:          d8b10aa9-c065-4aa5-ab6f-96a9bcda52ceFilesystem magic number:  0xEF53Filesystem revision #:    1 (dynamic)Filesystem features:      ext_attr resize_inode dir_index filetype sparse_super large_fileDefault mount options:    (none)Filesystem state:         not cleanErrors behavior:          ContinueFilesystem OS type:       LinuxInode count:              2443200Block count:              4885760Reserved block count:     244288Free blocks:              4797829Free inodes:              2443189First block:              0Block size:               4096Fragment size:            4096Reserved GDT blocks:      1022Blocks per group:         32768Fragments per group:      32768Inodes per group:         16288Inode blocks per group:   509Filesystem created:       Mon Oct 29 20:04:16 2007Last mount time:          Mon Oct 29 20:06:52 2007Last write time:          Mon Oct 29 20:08:31 2007Mount count:              1Maximum mount count:      39Last checked:             Mon Oct 29 20:04:16 2007Check interval:           15552000 (6 months)Next check after:         Sat Apr 26 20:04:16 2008Reserved blocks uid:      0 (user root)Reserved blocks gid:      0 (group root)First inode:              11Inode size:               128Default directory hash:   teaDirectory Hash Seed:      d1432419-2def-4762-954a-1a26fef9d5e8Group 0: (Blocks 0-32767)  Primary superblock at 0, Group descriptors at 1-2  Reserved GDT blocks at 3-1024  Block bitmap at 1025 (+1025), Inode bitmap at 1026 (+1026)  Inode table at 1027-1535 (+1027)  31224 free blocks, 16276 free inodes, 2 directories  Free blocks: 1543-22535, 22537-32767  Free inodes: 12, 14-16288...Group 149: (Blocks 4882432-4885759)  Block bitmap at 4882432 (+0), Inode bitmap at 4882433 (+1)  Inode table at 4882434-4882942 (+2)  2817 free blocks, 16288 free inodes, 0 directories  Free blocks: 4882943-4885759  Free inodes: 2426913-2443200
                       
           

           

应用前面介绍的一些知识,我们可以看到,这个文件系统中,块大小(Block size)为4096字节,因此每个块组中的块数应该是4096*8=32768个(Blocks per group),每个块组的大小是 128MB,整个分区被划分成20GB/(4KB*32768)=160个。但是为什么我们只看到 150 个块组(0到149)呢?实际上,在 fdisk 中,我们虽然输入要创建的分区大小为 20GB,但实际上,真正分配的空间并不是严格的20GB,而是只有大约 20*109 个字节,准确地说,应该是 (4885760 * 4096) / (1024*1024*1024) = 18.64GB。这是由于不同程序的计数单位的不同造成的,在使用存储设备时经常遇到这种问题。因此,这个分区被划分成 150 个块组,前 149 个块组分别包含 32768 个块(即 128B),最后一个块组只包含 3328 个块。

           

另外,我们还可以看出,每个索引节点的大小是 128 字节,每个块组中包含 16288 个索引节点,在磁盘上使用 509 个块来存储(16288*128/4096),在第一个块组中,索引节点表保存在 1027 到 1535 块上。

           

数据块和索引节点是否空闲,是分别使用块位图和索引节点位图来标识的,在第一个块组中,块位图和索引节点位图分别保存在 1025 和 1026 块上。

           

dumpe2fs 的输出结果中还包含了其他一些信息,我们暂时先不用详细关心这些信息。

           

           

                                                                                                           
           

           

准备测试文件

           

现在请将附件中的 createfile.sh 文件下载到本地,并将其保存到 /tmp/test 目录中,这个脚本可以帮助我们创建一个特殊的文件,其中每行包含 1KB 字符,最开始的14个字符表示行号。之所以采用这种文件格式,是为了方便地确认所恢复出来的文件与原始文件之间的区别。这个脚本的用法如下:

           

清单 9. createfile.sh 脚本的用法           

                                                                                                           
                       
                # ./createfile.sh [size in KB] [filename]
                       
           

           

第 1 个参数表示所生成的文件大小,单位是 KB;第 2 个参数表示所生成文件的名字。

           

下面让我们创建几个测试文件:

           

清单 10. 准备测试文件           

                                                                                                           
                       
                # cd /tmp/test#./createfile.sh 35 testfile.35K#./createfile.sh 10240 testfile.10M# cp testfile.35K testfile.35K.orig# cp testfile.10M testfile.10M.orig
                       
           

           

上面的命令新创建了大小为 35 KB 和 9000KB 的两个文件,并为它们各自保存了一个备份,备份文件的目的是为了方便使用 diff 之类的工具验证最终恢复出来的文件与原始文件完全一致。

           

ls 命令的 –i 选项可以查看有关保存文件使用的索引节点的信息:

           

清单11. 查看文件的索引节点号           

                                                                                                           
                       
                # ls -li | sort11 drwx------ 2 root root    16384 Oct 29 20:08 lost+found12 -rwxr-xr-x 1 root root     1406 Oct 29 20:09 createfile.sh13 -rw-

这篇关于如何恢复 Linux 上删除的文件 ext2的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/365200

相关文章

Linux中shell解析脚本的通配符、元字符、转义符说明

《Linux中shell解析脚本的通配符、元字符、转义符说明》:本文主要介绍shell通配符、元字符、转义符以及shell解析脚本的过程,通配符用于路径扩展,元字符用于多命令分割,转义符用于将特殊... 目录一、linux shell通配符(wildcard)二、shell元字符(特殊字符 Meta)三、s

Linux之软件包管理器yum详解

《Linux之软件包管理器yum详解》文章介绍了现代类Unix操作系统中软件包管理和包存储库的工作原理,以及如何使用包管理器如yum来安装、更新和卸载软件,文章还介绍了如何配置yum源,更新系统软件包... 目录软件包yumyum语法yum常用命令yum源配置文件介绍更新yum源查看已经安装软件的方法总结软

linux报错INFO:task xxxxxx:634 blocked for more than 120 seconds.三种解决方式

《linux报错INFO:taskxxxxxx:634blockedformorethan120seconds.三种解决方式》文章描述了一个Linux最小系统运行时出现的“hung_ta... 目录1.问题描述2.解决办法2.1 缩小文件系统缓存大小2.2 修改系统IO调度策略2.3 取消120秒时间限制3

Linux alias的三种使用场景方式

《Linuxalias的三种使用场景方式》文章介绍了Linux中`alias`命令的三种使用场景:临时别名、用户级别别名和系统级别别名,临时别名仅在当前终端有效,用户级别别名在当前用户下所有终端有效... 目录linux alias三种使用场景一次性适用于当前用户全局生效,所有用户都可调用删除总结Linux

Linux:alias如何设置永久生效

《Linux:alias如何设置永久生效》在Linux中设置别名永久生效的步骤包括:在/root/.bashrc文件中配置别名,保存并退出,然后使用source命令(或点命令)使配置立即生效,这样,别... 目录linux:alias设置永久生效步骤保存退出后功能总结Linux:alias设置永久生效步骤

Python脚本实现自动删除C盘临时文件夹

《Python脚本实现自动删除C盘临时文件夹》在日常使用电脑的过程中,临时文件夹往往会积累大量的无用数据,占用宝贵的磁盘空间,下面我们就来看看Python如何通过脚本实现自动删除C盘临时文件夹吧... 目录一、准备工作二、python脚本编写三、脚本解析四、运行脚本五、案例演示六、注意事项七、总结在日常使用

Git中恢复已删除分支的几种方法

《Git中恢复已删除分支的几种方法》:本文主要介绍在Git中恢复已删除分支的几种方法,包括查找提交记录、恢复分支、推送恢复的分支等步骤,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录1. 恢复本地删除的分支场景方法2. 恢复远程删除的分支场景方法3. 恢复未推送的本地删除分支场景方法4. 恢复

使用Python实现在Word中添加或删除超链接

《使用Python实现在Word中添加或删除超链接》在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能,本文将为大家介绍一下Python如何实现在Word中添加或... 在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能。通过添加超

Linux使用fdisk进行磁盘的相关操作

《Linux使用fdisk进行磁盘的相关操作》fdisk命令是Linux中用于管理磁盘分区的强大文本实用程序,这篇文章主要为大家详细介绍了如何使用fdisk进行磁盘的相关操作,需要的可以了解下... 目录简介基本语法示例用法列出所有分区查看指定磁盘的区分管理指定的磁盘进入交互式模式创建一个新的分区删除一个存

Python MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat