前一篇博文已经提到了目录文件的内容,这一篇在这个基础上描述如何恢复误删除的文件。由于目前主流是ext3文件系统,后面也会提到如何恢复ext3中误删除的文件。
首先删除 test 文件:
删除前:
- [root@localhost raw]# ll -ai
- total 48
- 65541 drwxr-xr-x 3 root root 4096 Aug 11 14:17 .
- 65537 drwxr-xr-x 6 root root 4096 Aug 11 14:06 ..
- 65542 -rw-r--r-- 1 root root 12 Aug 11 14:07 hello
- 65545 drwxr-xr-x 2 root root 4096 Aug 11 14:17 sub_dir
- 65543 -rw-r--r-- 1 root root 13 Aug 11 14:07 test
- 65544 -rw-r--r-- 1 root root 21 Aug 11 14:14 test_another
删除后:
- [root@localhost raw]# ll -ai
- total 40
- 65541 drwxr-xr-x 3 root root 4096 Aug 11 17:05 .
- 65537 drwxr-xr-x 6 root root 4096 Aug 11 16:34 ..
- 65542 -rw-r--r-- 1 root root 12 Aug 11 14:07 hello
- 65545 drwxr-xr-x 2 root root 4096 Aug 11 14:17 sub_dir
- 65544 -rw-r--r-- 1 root root 21 Aug 11 14:14 test_another
看到了test文件被我们删除了。现在用上一节parse 目录文件的程序看下,目录文件变成什么样了? 为了方便各位看代码,我将上篇博文的code再贴出来:
- #include <stdio.h>
- #include <stdlib.h>
- #include <ext2fs/ext2_fs.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include<errno.h>
- #include<string.h>
- #define BUFSZ 4096
- #define EXT2_DIR_PAD 4
- #define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
- #define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
- ~EXT2_DIR_ROUND)
- struct ext2_dir_entry_part {
- __u32 inode; /* Inode number */
- __u16 rec_len; /* Directory entry length */
- __u8 name_len; /* Name length */
- __u8 file_type;
- } ;
- void usage()
- {
- printf("read_dir_entry [dir entry filename]\n");
- }
- int main(int argc, char **argv)
- {
- struct ext2_dir_entry_2 de;
- char *filename = NULL;
- int fd ;
- int rtn = 0;
- int length = 0;
- char buf[BUFSZ] = {0};
- char name[512] = {0};
- struct ext2_dir_entry_part *dir = NULL;
- if (argc < 2)
- {
- printf("Too few parameters!\n");
- usage();
- exit(1);
- }
- filename = argv[1];
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- {
- printf("cannot open file: %s\n", filename);
- exit(1);
- }
- printf(" offset | inode number | rec_len | name_len | file_type | name\n");
- printf("======================================================================\n");
-
- int pos = 0;
-
- while ( rtn = read(fd,buf,BUFSZ))
- {
- if (rtn < 0)
- {
- fprintf(stderr, "read dir file (%s) failed ,(%s)\n ",filename,strerror(errno));
- return -1;
- }
- loop:
- dir = (struct ext2_dir_entry_part*) (buf + pos);
- if(dir->rec_len == 0)
- {
- break;
- }
- strncpy(name,(char*)(dir+1),dir->name_len);
-
- printf("%6d: %12d%12d%12d%12d %s\n",
- pos, dir->inode, dir->rec_len, dir->name_len, dir->file_type,name);
- // pos += EXT2_DIR_REC_LEN(dir->name_len);
- pos +=dir->rec_len;
- memset(name,0,512);
- if(dir->rec_len == 0 )
- {
- break;
- }
- if (pos < rtn - sizeof(struct ext2_dir_entry_part))
- {
- goto loop;
- }
-
- }
- close(fd);
- }
请注意后面有这么两行:- // pos += EXT2_DIR_REC_LEN(dir->name_len);
- 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对应文件的数据块的块号:
- debugfs: stat <65543>
- Inode: 65543 Type: regular Mode: 0644 Flags: 0x0 Generation: 3830748592
- User: 0 Group: 0 Size: 13
- File ACL: 66562 Directory ACL: 0
- Links: 0 Blockcount: 16
- Fragment: Address: 0 Number: 0 Size: 0
- ctime: 0x5026c91f -- Sat Aug 11 17:05:35 2012
- atime: 0x5026a23a -- Sat Aug 11 14:19:38 2012
- mtime: 0x50269f5d -- Sat Aug 11 14:07:25 2012
- dtime: 0x5026c91f -- Sat Aug 11 17:05:35 2012
- BLOCKS:
- (0):96258
- TOTAL: 1
可以看到只有一个块,块号为96258。用dd命令,把这个块的内容取出来,保存到test.recover文件里。- [root@localhost ext2_study]# dd if=/dev/loop0 of=/tmp/test.recover bs=4K skip=96258 count=1
- 1+0 records in
- 1+0 records out
- 4096 bytes (4.1 kB) copied, 0.0224192 seconds, 183 kB/s
- [root@localhost ext2_study]# cat /tmp/test.recover
- this is test
- [root@localhost ext2_study]#
可以看到,我们成功恢复出来了ext2文件系统的内容。
总结一下:
1 通过debugfs的lsdel命令找到你删掉文件的inode。
2 通过debugfs 找到inode对应的block位置
3 dd 读取对应block的内容到临时文件。
一种有一点需要注意,误删文件后,就不要再动误删文件的文件系统了,尤其不要写入新的文件。这也是将test.recover放在/tmp的原因 。上一篇博文,将raw_block存放到了的ext3文件系统中了,请看:
- [root@localhost ext2_study]# pwd
- /home/manu/code/C/ext2_study
- [root@localhost ext2_study]# ll
- total 84
- -rw-r--r-- 1 root root 3838 Aug 11 14:29 block_group
- -rw-r--r-- 1 root root 339 Aug 11 10:08 dir_C.log
- -rw-r--r-- 1 root root 3838 Aug 11 16:30 group_info.log
- -rw-r--r-- 1 root root 4096 Aug 11 17:07 raw_block
- -rw-r--r-- 1 root root 394 Aug 11 14:51 raw_info.log
- -rw-r--r-- 1 root root 4096 Aug 11 14:20 raw_log
- -rwxr-xr-x 1 root root 6597 Aug 11 18:28 read_dir_entry
- -rw-r--r-- 1 root root 2126 Aug 11 16:40 read_dir_entry.c
- -rwxr-xr-x 1 root root 9745 Aug 11 16:40 read_dir_entry_normal
有些人关心ext3 文件系统的恢复,因为ext3是主流在用的文件系统,酷壳的陈皓有篇文章比较好,我就不再浪费笔墨了,大家可以去这个链接去看:。
参考文件:
1 恢复Ext3下被删除的文件
2 如何恢复 Linux 上删除的文件,第 2 部分
阅读(858) | 评论(0) | 转发(0) |