首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

如何恢复 Linux 上删除的文件-特殊文件的恢复(3)

如何恢复 Linux 上删除的文件-特殊文件的恢复(3)

现在再来查看一下这两个数据块中内容的变化:
清单16. 分析新目录项中的数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# ./read_dir_entry block.1536.deleted 4096
  offset | inode number | rec_len | name_len | file_type | name
=================================================================
     0:            2          12           1           2  .
    12:            2          12           2           2  ..
    24:           11          20          10           2  lost+found
    44:           12          24          13           1  createfile.sh
    68:           13          20          12           1  testfile.35K
    88:           14          32          12           1  testfile.10M
   108:            0          12           4           2  dir1
   120:           15          28          17           1  testfile.35K.orig
   148:           16        3948          17           1  testfile.10M.orig

# ./read_dir_entry block.88064.deleted 4096
  offset | inode number | rec_len | name_len | file_type | name
=================================================================
     0:        32577          12           1           2  .
    12:            2          12           2           2  ..
    24:        32578          24          13           1  createfile.sh
    48:        32579          16           8           2  subdir11
    64:        48865          16           8           2  subdir12
    80:        32580          20          12           1  testfile.35K
   100:        32581        3996          12           1  testfile.10M




与前面的结果进行一下对比就会发现,dir1 目录的数据块并没有发生任何变化,而根目录的数据块中 dir1 以及之前的一项则变得不同了。实际上,在删除 dir1 目录时,所执行的操作是将 dir1 项中的索引节点号清空,并将这段空间合并到前一项上(即将 dir1 项的 rec_length 加到前一项的 rec_length上)。这也就是为什么我们编写的 read_dir_entry 程序没有采用 rec_length 作为步长来遍历数据的原因。
除了数据之外,索引节点信息也发生了一些变化,现在我们来了解一下最新的索引节点信息:
清单17. 删除子目录后索引节点信息的变化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# debugfs /dev/sdb6
debugfs 1.39 (29-May-2006)
debugfs:  stat <2>
Inode: 2   Type: directory    Mode:  0755   Flags: 0x0   Generation: 0
User:     0   Group:     0   Size: 4096
File ACL: 0    Directory ACL: 0
Links: 3   Blockcount: 8
Fragment:  Address: 0    Number: 0    Size: 0
ctime: 0x474d3387 -- Wed Nov 28 17:23:19 2007
atime: 0x474d33c2 -- Wed Nov 28 17:24:18 2007
mtime: 0x474d3387 -- Wed Nov 28 17:23:19 2007
BLOCKS:
(0):1536
TOTAL: 1

debugfs:  stat <32577>
Inode: 32577   Type: directory    Mode:  0755   Flags: 0x0   Generation: 1695264350
User:     0   Group:     0   Size: 0
File ACL: 1542    Directory ACL: 0
Links: 0   Blockcount: 16
Fragment:  Address: 0    Number: 0    Size: 0
ctime: 0x474d3387 -- Wed Nov 28 17:23:19 2007
atime: 0x474d3387 -- Wed Nov 28 17:23:19 2007
mtime: 0x474d3387 -- Wed Nov 28 17:23:19 2007
dtime: 0x474d3387 -- Wed Nov 28 17:23:19 2007
BLOCKS:
(0):88064
TOTAL: 1




与删除之前的结果进行一下比较就会发现,主要区别包括:
  • 将父目录的 Links 值减 1。
  • 设置 dtime 时间,并更新其他时间字段。
  • 由于目录只有在为空时才会被删除,因此其 Size 值会被设置为 0,Links 字段也被设置为 0。
通过了解数据块和索引节点的相应变化可以为恢复目录提供一个清晰的思路,其具体步骤如下:
  • 确定删除目录所对应的索引节点号。
  • 按照恢复文件的方法恢复索引节点对应的数据块。
  • 遍历数据块内容,恢复其中包含的文件和子目录。
  • 更新索引节点对应信息。
  • 修改父目录的索引节点信息和数据块中对应目录项的内容。
实际上,步骤3并不是必须的,因为如果这个目录中包含文件或子目录,使用 debugfs 的 lsdel 命令(遍历索引节点表)也可以找到所删除的索引节点记录,采用本文中介绍的方法也可以将其逐一恢复出来。
debugfs 的 mi 命令可以用来直接修改索引节点的信息,下面我们就使用这个命令来修改 dir1 这个目录对应的索引节点的信息:
清单18. 使用 debugfs 的 mi 命令直接修改索引节点信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# debugfs -w /dev/sdb6
debugfs 1.39 (29-May-2006)
debugfs:  lsdel
Inode  Owner  Mode    Size    Blocks   Time deleted
32577      0  40755      0    1/   1 Wed Nov 28 17:23:19 2007
32578      0 100755   1406    1/   1 Wed Nov 28 17:23:19 2007
32579      0  40755      0    1/   1 Wed Nov 28 17:23:19 2007
32580      0 100644  35840    9/   9 Wed Nov 28 17:23:19 2007
32581      0 100644 10485760 2564/2564 Wed Nov 28 17:23:19 2007
48865      0  40755      0    1/   1 Wed Nov 28 17:23:19 2007
6 deleted inodes found.
debugfs:  mi <32577>
                          Mode    [040755]
                       User ID    [0]
                      Group ID    [0]
                          Size    [0] 4096
                 Creation time    [1196241799]
             Modification time    [1196241799]
                   Access time    [1196241799]
                 Deletion time    [1196241799] 0
                    Link count    [0] 4
                   Block count    [16]
                    File flags    [0x0]
                    Generation    [0x650bae5e]
                      File acl    [1542]
                 Directory acl    [0]
              Fragment address    [0]
               Fragment number    [0]
                 Fragment size    [0]
               Direct Block #0    [88064]
               Direct Block #1    [0]
               Direct Block #2    [0]
               Direct Block #3    [0]
               Direct Block #4    [0]
               Direct Block #5    [0]
               Direct Block #6    [0]
               Direct Block #7    [0]
               Direct Block #8    [0]
               Direct Block #9    [0]
              Direct Block #10    [0]
              Direct Block #11    [0]
                Indirect Block    [0]
         Double Indirect Block    [0]
         Triple Indirect Block    [0]
debugfs:  link <32577> dir1
debugfs:  q




注意要使用 mi 命令直接修改索引节点的信息,在执行 debugfs 命令时必须加上 –w 选项,表示以可写方式打开该设备文件。在上面这个例子中,lsdel 命令找到 6 个已经删除的文件,其中 32577 就是 dir1 目录原来对应的索引节点。接下来使用 mi 命令修改这个索引节点的内容,将 Size 设置为 4096(Block count * 512),Deletion Time 设置为 0,Links count 设置为 4。最后又执行了一个 link 命令,为这个索引节点起名为 dir1(这样并不会修改父目录的 Links count 值)。
退出 debugfs 并重新挂载这个设备,就会发现 dir1 目录已经被找回来了,不过尽管该目录下面的目录结构都是正确的,但是这些文件和子目录的数据都是错误的:
清单19. 验证恢复结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# mount /dev/sdb6 /tmp/test
# ls -li /tmp/test
total 20632
   12 -rwxr-xr-x 1 root root     1406 Nov 28 16:53 createfile.sh
32577 drwxr-xr-x 4 root root     4096 Nov 28 17:23 dir1
   11 drwx------ 2 root root    16384 Nov 28 16:52 lost+found
   14 -rw-r--r-- 1 root root 10485760 Nov 28 16:54 testfile.10M
   16 -rw-r--r-- 1 root root 10485760 Nov 28 16:57 testfile.10M.orig
   13 -rw-r--r-- 1 root root    35840 Nov 28 16:53 testfile.35K
   15 -rw-r--r-- 1 root root    35840 Nov 28 16:56 testfile.35K.orig

# ls -li /tmp/test/dir1
total 0
??--------- ? ? ? ?            ? /tmp/test/dir1/createfile.sh
??--------- ? ? ? ?            ? /tmp/test/dir1/subdir11
??--------- ? ? ? ?            ? /tmp/test/dir1/subdir12
??--------- ? ? ? ?            ? /tmp/test/dir1/testfile.10M
??--------- ? ? ? ?            ? /tmp/test/dir1/testfile.35K




其原因是 dir1 中所包含的另外两个子目录和三个文件都还没有恢复。可以想像,恢复一个删除的目录会是件非常复杂而繁琐的事情。幸运的是,e2fsck 这个工具可以很好地理解 ext2 文件系统的实现,它可以用来对文件系统进行检查,并自动修复诸如链接数不对等问题。现在请按照上面的方法使用 mi 命令将其他 5 个找到的索引节点 Deletion Time 设置为 0,并将 Link count 设置为 1。然后使用下面的命令,强制 e2fsck 对整个文件系统进行检查:
清单20. 使用 e2fsck 强制对文件系统进行一致性检查
1
# e2fsck -f -y /dev/sdb6 > e2fsck.out 2>&1




e2fsck 的结果保存在 e2fsck.out 文件中。查看这个文件就会发现,e2fsck要执行 4 个步骤的检查:
  • 检查并修复索引节点、数据块和大小。比如已删除子目录的索引节点大小为0,则会根据所占用的块数(每个块为512字节)换算出来。
  • 检查目录结构的问题。检查索引节点的父目录,如果不存在,就认为父目录就是根目录。对于目录节点,需要检查是否包含当前目录和父目录项。
  • 检查目录结构的连通性。防止出现按照绝对路径无法访问文件的情况出现,将这些有问题的文件或目录放入 lost+found 目录中。
  • 检查并修复引用计数。统计对索引节点的引用计数值。
  • 检查并修复块组信息,包括块位图、索引节点位图,计算块组中的空闲块数、空闲索引节点数等。
现在重新挂载这个文件系统,会发现所有的文件已经全部恢复出来了。
返回列表