Chinaunix首页 | 论坛 | 博客
  • 博客访问: 109603
  • 博文数量: 58
  • 博客积分: 67
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-21 13:20
文章分类

全部博文(58)

文章存档

2014年(4)

2013年(54)

我的朋友

分类: LINUX

2013-10-10 15:43:05

    前一篇博文已经提到了目录文件的内容,这一篇在这个基础上描述如何恢复误删除的文件。由于目前主流是ext3文件系统,后面也会提到如何恢复ext3中误删除的文件。

    首先删除 test 文件:
    删除前:

  1. [root@localhost raw]# ll -ai
  2. total 48
  3. 65541 drwxr-xr-x 3 root root 4096 Aug 11 14:17 .
  4. 65537 drwxr-xr-x 6 root root 4096 Aug 11 14:06 ..
  5. 65542 -rw-r--r-- 1 root root 12 Aug 11 14:07 hello
  6. 65545 drwxr-xr-x 2 root root 4096 Aug 11 14:17 sub_dir
  7. 65543 -rw-r--r-- 1 root root 13 Aug 11 14:07 test
  8. 65544 -rw-r--r-- 1 root root 21 Aug 11 14:14 test_another
    删除后:

  1. [root@localhost raw]# ll -ai
  2. total 40
  3. 65541 drwxr-xr-x 3 root root 4096 Aug 11 17:05 .
  4. 65537 drwxr-xr-x 6 root root 4096 Aug 11 16:34 ..
  5. 65542 -rw-r--r-- 1 root root 12 Aug 11 14:07 hello
  6. 65545 drwxr-xr-x 2 root root 4096 Aug 11 14:17 sub_dir
  7. 65544 -rw-r--r-- 1 root root 21 Aug 11 14:14 test_another
    看到了test文件被我们删除了。现在用上一节parse 目录文件的程序看下,目录文件变成什么样了?
    为了方便各位看代码,我将上篇博文的code再贴出来:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <ext2fs/ext2_fs.h>
  4. #include <sys/stat.h>
  5. #include <fcntl.h>
  6. #include <sys/types.h>
  7. #include <unistd.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. #include<errno.h>
  12. #include<string.h>
  13. #define BUFSZ 4096

  14. #define EXT2_DIR_PAD             4
  15. #define EXT2_DIR_ROUND             (EXT2_DIR_PAD - 1)
  16. #define EXT2_DIR_REC_LEN(name_len)    (((name_len) + 8 + EXT2_DIR_ROUND) & \
  17.                      ~EXT2_DIR_ROUND)

  18. struct ext2_dir_entry_part {
  19.         __u32 inode; /* Inode number */
  20.         __u16 rec_len; /* Directory entry length */
  21.         __u8 name_len; /* Name length */
  22.         __u8 file_type;
  23. } ;

  24. void usage()
  25. {
  26.   printf("read_dir_entry [dir entry filename]\n");
  27. }

  28. int main(int argc, char **argv)
  29. {

  30.   struct ext2_dir_entry_2 de;
  31.   char *filename = NULL;
  32.   int fd ;
  33.   int rtn = 0;
  34.   int length = 0;
  35.   char buf[BUFSZ] = {0};
  36.   char name[512] = {0};

  37.   struct ext2_dir_entry_part *dir = NULL;
  38.   if (argc < 2)
  39.   {
  40.     printf("Too few parameters!\n");
  41.     usage();
  42.     exit(1); 
  43.   }

  44.   filename = argv[1];

  45.   fd = open(filename, O_RDONLY); 
  46.   if (fd < 0)
  47.   {
  48.     printf("cannot open file: %s\n", filename);
  49.     exit(1);
  50.   }

  51.   printf(" offset | inode number | rec_len | name_len | file_type | name\n");
  52.   printf("======================================================================\n");
  53.   
  54.   int pos = 0;
  55.  
  56.   while ( rtn = read(fd,buf,BUFSZ))
  57.   {
  58.     if (rtn < 0)
  59.     {
  60.         fprintf(stderr, "read dir file (%s) failed ,(%s)\n ",filename,strerror(errno));
  61.         return -1;
  62.     }
  63. loop:
  64.     dir = (struct ext2_dir_entry_part*) (buf + pos);
  65.     if(dir->rec_len == 0)
  66.     {
  67.        break;
  68.     }
  69.     strncpy(name,(char*)(dir+1),dir->name_len); 

  70.     
  71.    printf("%6d: %12d%12d%12d%12d %s\n", 
  72.             pos, dir->inode, dir->rec_len, dir->name_len, dir->file_type,name);


  73.    // pos += EXT2_DIR_REC_LEN(dir->name_len);
  74.     pos +=dir->rec_len;
  75.     memset(name,0,512);
  76.     if(dir->rec_len == 0 )
  77.     {
  78.          break;
  79.     }
  80.     if (pos < rtn - sizeof(struct ext2_dir_entry_part)) 
  81.     {
  82.         goto loop;
  83.     } 
  84.   
  85.  }


  86.   close(fd); 
  87. }
    请注意后面有这么两行:

  1. // pos += EXT2_DIR_REC_LEN(dir->name_len);
  2.     pos +=dir->rec_len;
    如果我采用上面注释掉的代码,把下面一行注释掉,生成可执行文件read_dir_entry。
    如果我采用下面一行的代码,把上面一行注释掉,生成可执行文件read_dir_entry_normal。 其实列目录此采用的是这种方法,删除掉的文件的信息就显示不出来了。
    
    下面先看删除前的输出,read_dir_entry 和read_dir_entry_normal都是一样的。:

    下面看删除后的输出: 


注意: 删除前hello文件所在的条目
 offset | inode number | rec_len | name_len | file_type | name
   24:        65542             16                 5           1       hello

删除后
   24:        65542             28                 5           1        hello

因为hello文件是已删除文件test的上一条目,test条目不再是有效的条目了,所以讲inode的清零,但是其他的信息并没有清楚,还暂时占据着磁盘上的空间。 回想下rec_len的定义:从当前条目的rec_len的末尾到下一个条目rec_len末尾的偏移量。由于test条目已经不是有效条目了,所以下一个条目是test_another.他就将test条目的长度12也加了进去,变成了16+12 = 28.

    这也就帮助我们理解了rec_len的真实含义,不是条目的长度,而是本条目rec_len末尾到下一个有效条目rec_len末尾的偏移量。

    现在我们如何恢复误删除的test文件呢?没有普通文件的inode是不可能恢复出普通文件的,因为inode记录了文件所在数据块的块号。但是如果我的确没有记住test文件的inode,那怎么办呢?

    debugfs有个针对ext2文件的命令lsdel,可以列出删掉的文件的inode。

[root@localhost /]# debugfs /dev/loop0
debugfs 1.39 (29-May-2006)
debugfs:  lsdel
 Inode  Owner  Mode    Size    Blocks   Time deleted
 65547      0 100644   4096    1/   1 Sat Aug 11 16:34:07 2012
 65546      0 100644   4096    1/   1 Sat Aug 11 16:34:11 2012
 65543      0 100644     13    1/   1 Sat Aug 11 17:05:35 2012
3 deleted inodes found.

    从时间上看,最后一个inode 号是65543是我删除的test文件。(当然不确定的话,你可以挨个试试)。(注:前两个是我其他实验中删除的文件)。

    然后用上一节提到的方法,找到inode对应文件的数据块的块号:

  1. debugfs: stat <65543>
  2. Inode: 65543 Type: regular Mode: 0644 Flags: 0x0 Generation: 3830748592
  3. User: 0 Group: 0 Size: 13
  4. File ACL: 66562 Directory ACL: 0
  5. Links: 0 Blockcount: 16
  6. Fragment: Address: 0 Number: 0 Size: 0
  7. ctime: 0x5026c91f -- Sat Aug 11 17:05:35 2012
  8. atime: 0x5026a23a -- Sat Aug 11 14:19:38 2012
  9. mtime: 0x50269f5d -- Sat Aug 11 14:07:25 2012
  10. dtime: 0x5026c91f -- Sat Aug 11 17:05:35 2012
  11. BLOCKS:
  12. (0):96258
  13. TOTAL: 1
    可以看到只有一个块,块号为96258。用dd命令,把这个块的内容取出来,保存到test.recover文件里。

  1. [root@localhost ext2_study]# dd if=/dev/loop0 of=/tmp/test.recover bs=4K skip=96258 count=1
  2. 1+0 records in
  3. 1+0 records out
  4. 4096 bytes (4.1 kB) copied, 0.0224192 seconds, 183 kB/s
  5. [root@localhost ext2_study]# cat /tmp/test.recover
  6. this is test
  7. [root@localhost ext2_study]#
    可以看到,我们成功恢复出来了ext2文件系统的内容。

总结一下:
1 通过debugfs的lsdel命令找到你删掉文件的inode。
2 通过debugfs 找到inode对应的block位置
3 dd 读取对应block的内容到临时文件。

    一种有一点需要注意,误删文件后,就不要再动误删文件的文件系统了,尤其不要写入新的文件。这也是将test.recover放在/tmp的原因 。上一篇博文,将raw_block存放到了的ext3文件系统中了,请看:

  1. [root@localhost ext2_study]# pwd
  2. /home/manu/code/C/ext2_study
  3. [root@localhost ext2_study]# ll
  4. total 84
  5. -rw-r--r-- 1 root root 3838 Aug 11 14:29 block_group
  6. -rw-r--r-- 1 root root 339 Aug 11 10:08 dir_C.log
  7. -rw-r--r-- 1 root root 3838 Aug 11 16:30 group_info.log
  8. -rw-r--r-- 1 root root 4096 Aug 11 17:07 raw_block
  9. -rw-r--r-- 1 root root 394 Aug 11 14:51 raw_info.log
  10. -rw-r--r-- 1 root root 4096 Aug 11 14:20 raw_log
  11. -rwxr-xr-x 1 root root 6597 Aug 11 18:28 read_dir_entry
  12. -rw-r--r-- 1 root root 2126 Aug 11 16:40 read_dir_entry.c
  13. -rwxr-xr-x 1 root root 9745 Aug 11 16:40 read_dir_entry_normal
    有些人关心ext3 文件系统的恢复,因为ext3是主流在用的文件系统,酷壳的陈皓有篇文章比较好,我就不再浪费笔墨了,大家可以去这个链接去看:。

参考文件:
1 恢复Ext3下被删除的文件
如何恢复 Linux 上删除的文件,第 2 部分

    
阅读(858) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~