如何制作Ext4文件系统镜像

如何制作Ext4文件系统镜像

Android中system.img的两种格式及其相互转换方法

搞Android的同学经常会接触到system.img。但是该文件经常以两种格式出现:raw和sparse。
一种是raw ext4 image,即经常说的raw image,使用file观察它: 其特点是完整的ext4分区镜像(包含很多全零的无效填充区),可以直接使用mount进行挂载,因此比较大(一般1G左右)。
$ file system.img
system.img: Linux rev 1.0 ext4 filesystem data, UUID=57f8f4bc-abf4-655f-bf67-946fc0f9f25b (extents) (large files)
信息非常明确了。
另一种是sparse ext4 image,即经常说的simg,使用file观察它:
$ file system.img
system.img: data
就是说是一个非常普通的dat文件。由于它将raw ext4进行稀疏描述,因此尺寸比较小(没有全零的无效填充区,一般在300到500M之间)。
android本身提供了源代码工具在两者之间转换,源代码位于:
system/core/libsparse/simg2img.c // 将sparse image转换为raw image;
system/core/libsparse/img2simg.c // 将raw image转换为sparse image;

如果完整的进行过一次Android的编译,默认会将simg2img当作主机工具编译出来,放在out/host/linux-x86/bin/simg2img处。 但默认是不会编译img2simg的,我们可以手工进行编译:
$ . build/envsetup.sh
$ lunch aosp_hammerhead-userdebug
$ make img2simg_host

这样就会编译出out/host/linux-x86/bin/img2simg。 如果要将system.raw.img转换为system.simg: $ img2simg system.raw.img system.simg

编译Android源码最后是使用make_ext4生成 Ext4镜像+签名(更新:合理使用make_ext4参数是不会导致添加签名的),如果需要纯Ext4镜像,那么需要再去掉签名,使用simg2img。这个两个工具都是在编译Android源码时编译出来的,如果没有Android源码编译环境,当然也可以使用Ubuntu社区已经整理好的工具集android-tools-fsutils,该工具集文件列表如下:(来自android-tools-fsutils/filelist)

/usr/bin/ext2simg
/usr/bin/ext4fixup
/usr/bin/img2simg
/usr/bin/make_ext4fs
/usr/bin/mkuserimg
/usr/bin/simg2img
/usr/bin/simg2simg
/usr/bin/simg_dump
/usr/bin/test_ext4fixup

工具集安装方法:

sudo apt-get install android-tools-fsutils

    1

    1

制作Ext4文件系统镜像:

# 创建测试目录
mkdir /tmp/ext4 && cd /tmp/ext4 &&
mkdir test test_mount &&
echo "Hello Ext4" > test/HelloExt4.txt &&

# 生成名为test.ext4的Ext4镜像
make_ext4fs -l 512M test.ext4 test &&

# 挂载test.ext4到test_mount测试
mount -t ext4 -o loop test.ext4 test_mount &&
ls test_mount || echo "Error!"


一、在(yourAndroid code path)/out/  目录里查找这个工具 

unyaffs: 用于解压system.img  

mkyaffs2image: 用于打包system.img

呵呵, find 命令肯定会吧?  find  out/   -name mkyaffs2image
找到了后,记住这个目录. 我的是(codePATH)/out/host/linux-x86/bin/

1.在任意文件夹下面建立一个system文件夹,我的是在home/changjiang/下面建的,这个是用来存放你解压system.img出来的文件,然后将找到的两个工具 unyaffs、mkyaffs2image拷贝到/changjiang/home/system

2.将编译出来的system.img或者下载的system.img复制到system文件夹中。

3.在终端中输入如下命令操作(/home/changjiang/替换成自己电脑中的路径,你的不是我的)
cd /home/changjiang/system
./unyaffs /home/changjiang/system/system.img(用unyaffs命令解压system.img),解压出来的有各种应用,库等等,你可以修改或者替换


二、重新打包system.img,虽然我不知道为什么要这样做,但是我知道这样做是可以的.

呵呵,linux没有不可能的事情.朝鲜的  红星操作系统就是例子.
具体办法是
 system/  这个目录,这个目录就是用来生成system.img 的.

 mkyaffs2image    system/   system.img

 

在Ubuntu中第一次使用mkyaffs2image命令时,会提示

mkyaffs2image:找不到命令

还需要安装mkyaffs2image

http://code.google.com/p/fatplus/downloads/detail?name=yaffs2-source.tar&can=2&q=

下载yaffs2-source.tar 

解压后,进入utils文件夹,然后make

将make之后生成的mkyaffs2image文件拷贝到/usr/bin目录下

$ su
# cp mkyaffs2image /usr/bin/
# chmod 777 /usr/bin/mkyaffs2image

之后

$ mkyaffs2image 
mkyaffs2image: image building tool for YAFFS2 built Jan  6 2012
usage: mkyaffs2image dir image_file [convert]
           dir        the directory tree to be converted
           image_file the output file to hold the image
           'convert'  produce a big-endian image from a little-endian machine

表明安装成功,同时也可以看到该命令的用法

mkyaffs2image dir image_file
例如:

mkyaffs2image am1808-fs am1808-fs.yaffs//创建jffs2文件


搞Android的同学经常会接触到system.img。但是该文件经常以两种格式出现:raw和sparse。
一种是raw ext4 image,即经常说的raw image,使用file观察它: 其特点是完整的ext4分区镜像(包含很多全零的无效填充区),可以直接使用mount进行挂载,因此比较大(一般1G左右)。

$ file system.img
system.img: Linux rev 1.0 ext4 filesystem data, UUID=57f8f4bc-abf4-655f-bf67-946fc0f9f25b (extents) (large files)
信息非常明确了。
另一种是sparse ext4 image,即经常说的simg,使用file观察它:
$ file system.img
system.img: data
就是说是一个非常普通的dat文件。由于它将raw ext4进行稀疏描述,因此尺寸比较小(没有全零的无效填充区,一般在300到500M之间)。
android本身提供了源代码工具在两者之间转换,源代码位于:
system/core/libsparse/simg2img.c // 将sparse image转换为raw image;
system/core/libsparse/img2simg.c // 将raw image转换为sparse image;

如果完整的进行过一次Android的编译,默认会将simg2img当作主机工具编译出来,放在out/host/linux-x86/bin/simg2img处。 但默认是不会编译img2simg的,我们可以手工进行编译:
$ . build/envsetup.sh
$ lunch aosp_hammerhead-userdebug
$ make img2simg_host

这样就会编译出out/host/linux-x86/bin/img2simg。 如果要将system.raw.img转换为system.simg: $ img2simg system.raw.img system.simg
为了方便没有源代码的同学,这里提供img2simg的下载路径: http://download.csdn.net/detail/howellzhu/8399215
对于simg2img,到处都可以找到了,还有windows版本的,这里就不提供了。 使用方法:
$ simg2img  
$ img2simg   []



1、解压system.img

先用file命令查看system.img的文件类型

file system.img

 system.img: Linux rev 1.0 ext4 filesystem data, UUID=57f8f4bc-abf4-655f-bf67-946fc0f9f25b (needs journal recovery) (extents) (large files)

看到没 ext4 filesystem data

那好办,采用挂载分区的方式来打开system.img文件

mount -t ext4 -o loop system.img  systemimg    //此命令的意思将system.img镜像文件挂载到systemimg目录

cd systemimg

Android标准的文件结构就出来了,里面可以“随意”定制

2、重新打包生成system.img

打包命令:

./make_ext4fs -l 1024M -s -a system system_new.img systemimg

参数解析:1024M代表你要打包的system.img大小,这个值可以参考挂载前system.img的大小

"-a system",是指这个img用于android系统,挂载点是/system,使用这个参数,make_ext4fs会根据private/android_filesystem_config.h里定义好的权限来给文件夹里的所有文件重新设置权限,如果你刷机以后发现有文件权限不对,可以手工修改android_filesystem_config.h来添加权限,重新编译make_ext4fs,也可以不使用 “-a system”参数,这样就会使用文件的默认权限。

system_new.img代表新生成的img

systemimg就是上面挂载后的目录

一般很多人认为这样生成的system_new.img就可以用了,其实不然

再次用file命令查看文件类型

file system_new.img

 system_new.img: data

跟之前的输出截然不同,这显然不是ext4文件类型,啥情况???

方法就是继续使用simg2img工具将其转换成真正的ext4文件

./simg2img system_new.img system_out.img

得到system_out.img

file system_out.img

system_out.img: Linux rev 1.0 ext4 filesystem data, UUID=57f8f4bc-abf4-655f-bf67-946fc0f9f25b (extents) (large files)

怎么样?这次得到的img就是ext4了吧?ok,那么这个system_out.img就是我们重新打包生成的img了,这就可以烧到手机里面看看效果了。。。

PS:上面提到的make_ext4fs simg2img等工具在android环境的out/host/linux-x86/bin目录下。

上文说到 通过remount的方式来修改/system/bin 下的权限;

还有一种办法就是在打包system.img时就设置好权限,而这种办法就是通过修改:make.ext4fs


system/core/include/private/android_filesystem_config.h

         +    { 00777, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },

     编译make.ext4fs:

# mmm system/extras/ext4_utils/

       #mmm system/core/

     再打包 ------- ,然后全部重新烧录:可以看到权限被修改过来。



参考转载:http://blog.csdn.net/myxmu/article/details/8583470

make_ext4fs用于Android平台上制作ext4文件系统的镜像。用法举例:

make_ext4fs -l 512M -s -a system system.ext4img system

之后再使用simg2img制作镜像。

有一个问题是,使用这样制作的镜像,system分区文件的权限都是预定的,即使先修改system目录文件权限后在制作镜像,烧入设备后,其权限仍未改变。关键问题在make_ext4fs工具,在制作ext4fs时更改了权限,其依据为system/core/private/android_ilesystem_config.h所定义的权限。

查询make_ext4fs的参数含义,可以了解到这一点。


-l 512M"是分区大小,i9100的system分区是512M;
-s就是生成ext4的S模式制作;
"-a system",是指这个img用于android系统,挂载点是/system,使用这个参数,make_ext4fs会根据private/android_filesystem_config.h里定义好的权限来给文件夹里的所有文件重新设置权限,如果你刷机以后发现有文件权限不对,可以手工修改android_filesystem_config.h来添加权限,重新编译make_ext4fs,也可以不使用 “-a system”参数,这样就会使用文件的默认权限。

如果不使用-a参数,则可。

今天偶尔看到有人问起,如何解包打包安卓的各类 img 文件。下面介绍下

首先可以去 https://android.googlesource.com/platform/system/extras下载工具源代码

$ git clone https://android.googlesource.com/platform/system/extras /your/path

checkout 你需要的版本,譬如 android-5.1.1_r13

$ cd /your/path/extras
$ git checkout android-5.1.1_r13

编译 simg2img,这里你需要 gcc 工具,linux 用户基本都由现成的,mac 用户通过 homebrew 安装一个去

$ cd /your/path/extras/ext4_utils
$ gcc -o simg2img -lz sparse_crc32.c simg2img.c
$ gcc -o make_ext4fs -lz make_ext4fs_main.c make_ext4fs.c ext4fixup.c ext4_utils.c allocate.c backed_block.c output_file.c contents.c extent.c indirect.c uuid.c sha1.c sparse_crc32.c wipe.c

当前目录会生成 simg2img 与 make_ext4fs 两进制文件

下面解包开始,以 system.img 为例

$ ./simg2img system.img system.ext4

随后,可以直接挂载,需要 root 权限

# mkdir /your/path/system-data
# mount -t ext4 -o loop system.ext4 /your/path/system-data

打包的话,则是如此操作

$ ./make_ext4fs -s -l 512M -a system system-data.img /your/path/system-data

或者使用源代码中的脚本

$ cd /your/path/extras
$ PATH="$PATH:$(pwd)/ext4_utils/make_ext4fs" ./ext4_utils/mkuserimg.sh -s /your/path/system-data system-data.img ext4 /tmp 512M

最后转换下

$ ./simg2img system-data.img system.img

OK,你可以刷入你的手机了,Good luck!



Super block

只是在ext3的基础上扩展了一些字段,可以支持更大的硬盘和更大的文件。如:s_blocks_count  修改为s_blocks_count_lo和s_blocks_count_hi

结构体如下:

  1. /*  
  2.  *Structure of the super block  
  3.  */  
  4. struct ext4_super_block {  
  5. /*00*/ __le32  s_inodes_count;         /* Inodes count文件系统中inode的总数*/  
  6.        __le32  s_blocks_count_lo;      /* Blocks count文件系统中块的总数*/  
  7.        __le32  s_r_blocks_count_lo;    /* Reserved blocks count保留块的总数*/  
  8.        __le32  s_free_blocks_count_lo; /*Free blocks count未使用的块的总数(包括保留块)*/  
  9. /*10*/ __le32  s_free_inodes_count;    /* Free inodes count未使用的inode的总数*/  
  10.        __le32  s_first_data_block;     /* First Data Block第一块块ID,在小于1KB的文件系统中为0,大于1KB的文件系统中为1*/  
  11.        __le32  s_log_block_size;       /* Block size用以计算块的大小(1024算术左移该值即为块大小)(0=1K, 1=2K, 2=4K) */  
  12.        __le32  s_obso_log_frag_size;   /* Obsoleted fragment size用以计算段大小(为正则1024算术左移该值,否则右移)*/  
  13. /*20*/ __le32  s_blocks_per_group;     /* # Blocks per group每个块组中块的总数*/  
  14.        __le32  s_obso_frags_per_group; /*Obsoleted fragments per group每个块组中段的总数*/  
  15.        __le32  s_inodes_per_group;     /* # Inodes per group每个块组中inode的总数*/  
  16.        __le32  s_mtime;                /* Mount time POSIX中定义的文件系统装载时间*/  
  17. /*30*/ __le32  s_wtime;                /* Write time POSIX中定义的文件系统最近被写入的时间*/  
  18.        __le16  s_mnt_count;            /* Mount count最近一次完整校验后被装载的次数*/  
  19.        __le16  s_max_mnt_count;        /* Maximal mount count在进行完整校验前还能被装载的次数*/  
  20.        __le16  s_magic;                /* Magic signature文件系统标志*/  
  21.        __le16  s_state;                /* File system state文件系统的状态*/  
  22.        __le16  s_errors;               /* Behaviour when detectingerrors文件系统发生错误时驱动程序应该执行的操作*/  
  23.        __le16  s_minor_rev_level;      /* minor revision level局部修订级别*/  
  24. /*40*/ __le32  s_lastcheck;            /* time of last check POSIX中定义的文件系统最近一次检查的时间*/  
  25.        __le32  s_checkinterval;        /* max. time between checks POSIX中定义的文件系统最近检查的最大时间间隔*/  
  26.        __le32  s_creator_os;           /* OS生成该文件系统的操作系统*/  
  27.        __le32  s_rev_level;            /* Revision level修订级别*/  
  28. /*50*/ __le16  s_def_resuid;           /* Default uid for reserved blocks报留块的默认用户ID */  
  29.        __le16  s_def_resgid;           /* Default gid for reserved blocks保留块的默认组ID */  
  30.        /*  
  31.         * These fields are for EXT4_DYNAMIC_REV superblocks only.  
  32.         *  
  33.         * Note: the difference between the compatible feature set and  
  34.         * the incompatible feature set is that if there is a bit set  
  35.         * in the incompatible feature set that the kernel doesn't  
  36.         * know about, it should refuse to mount the filesystem.  
  37.         *  
  38.         * e2fsck's requirements are more strict; if it doesn't know  
  39.         * about a feature in either the compatible or incompatible  
  40.         * feature set, it must abort and not try to meddle with  
  41.         * things it doesn't understand...  
  42.         */  
  43.        __le32  s_first_ino;            /* First non-reserved inode标准文件的第一个可用inode的索引(非动态为11)*/  
  44.        __le16  s_inode_size;           /* size of inode structure inode结构的大小(非动态为128)*/  
  45.        __le16  s_block_group_nr;       /* block group # of this superblock保存此超级块的块组号*/  
  46.        __le32  s_feature_compat;       /* compatible feature set兼容特性掩码*/  
  47. /*60*/ __le32  s_feature_incompat;     /* incompatible feature set不兼容特性掩码*/  
  48.        __le32  s_feature_ro_compat;    /* readonly-compatible feature set只读特性掩码*/  
  49. /*68*/ __u8    s_uuid[16];             /* 128-bit uuid for volume卷ID,应尽可能使每个文件系统的格式唯一*/  
  50. /*78*/ char    s_volume_name[16];      /* volume name卷名(只能为ISO-Latin-1字符集,以'\0'结束)*/  
  51. /*88*/ char    s_last_mounted[64];     /* directory where last mounted最近被安装的目录*/  
  52. /*C8*/ __le32  s_algorithm_usage_bitmap;/* For compression文件系统采用的压缩算法*/  
  53.        /*  
  54.         * Performance hints.  Directorypreallocation should only  
  55.         * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on.  
  56.         */  
  57.        __u8    s_prealloc_blocks;      /* Nr of blocks to try to preallocate预分配的块数*/  
  58.        __u8   s_prealloc_dir_blocks;  /* Nr topreallocate for dirs给目录预分配的块数*/  
  59.        __le16 s_reserved_gdt_blocks;  /* Pergroup desc for online growth */  
  60.        /*  
  61.         * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.  
  62.         */  
  63. /*D0*/ __u8    s_journal_uuid[16];     /* uuid of journal superblock日志超级块的卷ID */  
  64. /*E0*/ __le32  s_journal_inum;         /* inode number of journal file日志文件的inode数目*/  
  65.        __le32  s_journal_dev;          /* device number of journal file日志文件的设备数*/  
  66.        __le32  s_last_orphan;          /* start of list of inodes to delete要删除的inode列表的起始位置*/  
  67.        __le32  s_hash_seed[4];         /* HTREE hash seed HTREE散列种子*/  
  68.        __u8    s_def_hash_version;     /* Default hash version to use默认使用的散列函数*/  
  69.        __u8    s_jnl_backup_type;  
  70.        __le16  s_desc_size;            /* size of group descriptor */  
  71. /*100*/ __le32  s_default_mount_opts;  
  72.        __le32  s_first_meta_bg;        /* First metablock block group块组的第一个元块*/  
  73.         __le32 s_mkfs_time;            /* Whenthe filesystem was created */  
  74.        __le32  s_jnl_blocks[17];       /* Backup of the journal inode */  
  75.        /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */  
  76. /*150*/ __le32  s_blocks_count_hi;      /* Blocks count */  
  77.        __le32  s_r_blocks_count_hi;    /* Reserved blocks count */  
  78.        __le32  s_free_blocks_count_hi; /*Free blocks count */  
  79.        __le16  s_min_extra_isize;      /* All inodes have at least # bytes */  
  80.        __le16  s_want_extra_isize;     /* New inodes should reserve # bytes */  
  81.        __le32  s_flags;                /* Miscellaneous flags */  
  82.        __le16  s_raid_stride;          /* RAID stride */  
  83.        __le16 s_mmp_update_interval;  /* #seconds to wait in MMP checking */  
  84.         __le64 s_mmp_block;            /* Blockfor multi-mount protection */  
  85.        __le32  s_raid_stripe_width;    /* blocks on all data disks (N*stride)*/  
  86.        __u8   s_log_groups_per_flex;  /* FLEX_BGgroup size */  
  87.        __u8    s_reserved_char_pad;  
  88.        __le16  s_reserved_pad;  
  89.        __le64  s_kbytes_written;       /* nr of lifetime kilobytes written */  
  90.        __le32  s_snapshot_inum;        /* Inode number of active snapshot */  
  91.        __le32  s_snapshot_id;          /* sequential ID of active snapshot*/  
  92.        __le64  s_snapshot_r_blocks_count;/* reserved blocks for active  
  93.                                              snapshot's future use */  
  94.        __le32  s_snapshot_list;        /* inode number of the head of the  
  95.                                            on-disk snapshot list */  
  96. #define EXT4_S_ERR_START offsetof(structext4_super_block, s_error_count)  
  97.        __le32  s_error_count;          /* number of fs errors */  
  98.        __le32  s_first_error_time;     /* first time an error happened */  
  99.        __le32  s_first_error_ino;      /* inode involved in first error */  
  100.        __le64  s_first_error_block;    /* block involved of first error */  
  101.        __u8    s_first_error_func[32]; /*function where the error happened */  
  102.        __le32  s_first_error_line;     /* line number where error happened */  
  103.        __le32  s_last_error_time;      /* most recent time of an error */  
  104.        __le32  s_last_error_ino;       /* inode involved in last error */  
  105.        __le32  s_last_error_line;      /* line number where error happened */  
  106.        __le64  s_last_error_block;     /* block involved of last error */  
  107.        __u8   s_last_error_func[32];  /*function where the error happened */  
  108. #define EXT4_S_ERR_END offsetof(structext4_super_block, s_mount_opts)  
  109.        __u8    s_mount_opts[64];  
  110.        __le32  s_reserved[112];        /* Padding to the end of the block */  
  111. };  

group descriptor

块组描述信息。

包含了blockbitmap、inode bitmap、inode table等存放的块地址。

结构体如下:


  1. /*  
  2.  *Structure of a blocks group descriptor  
  3.  */  
  4. struct ext4_group_desc  
  5. {  
  6.        __le32  bg_block_bitmap_lo;     /* Blocks bitmap block块位图所在的第一个块的块ID */  
  7.        __le32  bg_inode_bitmap_lo;     /* Inodes bitmap block inode位图所在的第一个块的块ID */  
  8.        __le32  bg_inode_table_lo;      /* Inodes table block inode表所在的第一个块的块ID */  
  9.        __le16  bg_free_blocks_count_lo;/*Free blocks count块组中未使用的块数*/  
  10.        __le16  bg_free_inodes_count_lo;/*Free inodes count块组中未使用的inode数*/  
  11.        __le16 bg_used_dirs_count_lo;  /*Directories count块组分配的目录的inode数*/  
  12.        __le16  bg_flags;               /* EXT4_BG_flags (INODE_UNINIT,etc) */  
  13.        __u32   bg_reserved[2];         /* Likely block/inode bitmap checksum*/  
  14.        __le16  bg_itable_unused_lo;    /* Unused inodes count */  
  15.        __le16  bg_checksum;            /* crc16(sb_uuid+group+desc) */  
  16.        __le32  bg_block_bitmap_hi;     /* Blocks bitmap block MSB */  
  17.        __le32  bg_inode_bitmap_hi;     /* Inodes bitmap block MSB */  
  18.        __le32  bg_inode_table_hi;      /* Inodes table block MSB */  
  19.        __le16  bg_free_blocks_count_hi;/*Free blocks count MSB */  
  20.        __le16  bg_free_inodes_count_hi;/*Free inodes count MSB */  
  21.        __le16 bg_used_dirs_count_hi;  /*Directories count MSB */  
  22.        __le16  bg_itable_unused_hi;    /* Unused inodes count MSB */  
  23.        __u32   bg_reserved2[3];  
  24. };  

inode

保存了每个节点的信息。

该节点的属性、所占的块地址。

结构体如下:


  1. /*  
  2.  *Structure of an inode on the disk  
  3.  */  
  4. struct ext4_inode {  
  5.        __le16  i_mode;         /* File mode文件格式和访问权限*/  
  6.        __le16  i_uid;          /* Low 16 bits of Owner Uid文件所有者ID的低16位*/  
  7.        __le32  i_size_lo;      /* Size in bytes文件字节数*/  
  8.        __le32  i_atime;        /* Access time文件上次被访问的时间*/  
  9.        __le32  i_ctime;        /* Inode Change time文件创建时间*/  
  10.        __le32  i_mtime;        /* Modification time文件被修改的时间*/  
  11.        __le32  i_dtime;        /* Deletion Time文件被删除的时间(如果存在则为0)*/  
  12.        __le16  i_gid;          /* Low 16 bits of Group Id文件所有组ID的低16位*/  
  13.        __le16  i_links_count;  /* Links count此inode被连接的次数*/  
  14.        __le32  i_blocks_lo;    /* Blocks count文件已使用和保留的总块数(以512B为单位)*/  
  15.        __le32  i_flags;        /* File flags */  
  16.        union {  
  17.                 struct {  
  18.                         __le32  l_i_version;  
  19.                 } linux1;  
  20.                 struct {  
  21.                         __u32  h_i_translator;  
  22.                 } hurd1;  
  23.                 struct {  
  24.                         __u32  m_i_reserved1;  
  25.                 } masix1;  
  26.        } osd1;                         /*OS dependent 1 */  
  27.        __le32  i_block[EXT4_N_BLOCKS];/*Pointers to blocks定位存储文件的块的数组*/  
  28.        __le32  i_generation;   /* File version (for NFS) 用于NFS的文件版本*/  
  29.        __le32  i_file_acl_lo;  /* File ACL包含扩展属性的块号,老版本中为0*/  
  30.        __le32  i_size_high;  
  31.        __le32  i_obso_faddr;   /* Obsoleted fragment address */  
  32.        union {  
  33.                 struct {  
  34.                         __le16  l_i_blocks_high; /* were l_i_reserved1 */  
  35.                         __le16  l_i_file_acl_high;  
  36.                         __le16  l_i_uid_high;   /* these 2 fields */  
  37.                         __le16  l_i_gid_high;   /* were reserved2[0] */  
  38.                         __u32   l_i_reserved2;  
  39.                 } linux2;  
  40.                 struct {  
  41.                         __le16  h_i_reserved1;  /* Obsoleted fragment number/size which areremoved in ext4 */  
  42.                         __u16   h_i_mode_high;  
  43.                         __u16   h_i_uid_high;  
  44.                         __u16   h_i_gid_high;  
  45.                         __u32   h_i_author;  
  46.                 } hurd2;  
  47.                 struct {  
  48.                         __le16  h_i_reserved1;  /* Obsoleted fragment number/size which areremoved in ext4 */  
  49.                         __le16  m_i_file_acl_high;  
  50.                         __u32   m_i_reserved2[2];  
  51.                 } masix2;  
  52.        } osd2;                         /*OS dependent 2 */  
  53.        __le16  i_extra_isize;  
  54.        __le16  i_pad1;  
  55.        __le32  i_ctime_extra;  /* extra Change time      (nsec << 2 | epoch) */  
  56.        __le32  i_mtime_extra;  /* extra Modification time(nsec << 2 |epoch) */  
  57.        __le32  i_atime_extra;  /* extra Access time      (nsec << 2 | epoch) */  
  58.        __le32  i_crtime;       /* File Creation time */  
  59.        __le32  i_crtime_extra; /* extraFileCreationtime (nsec << 2 | epoch) */  
  60.        __le32  i_version_hi;   /* high 32 bits for 64-bit version */  
  61. };  

Dir

用于保存所有目录的信息。

根目录总是在inode表的第二项,而其子目录则在根目录文件的内容中定义。

结构体如下:


  1. struct ext4_dir_entry {  
  2.        __le32  inode;                  /* Inode number文件入口的inode号,0表示该项未使用*/  
  3.        __le16  rec_len;                /* Directory entry length目录项长度*/  
  4.        __le16  name_len;               /* Name length文件名包含的字符数*/  
  5.        char    name[EXT4_NAME_LEN];    /* File name文件名*/  
  6. }; 

关键词汇

先回顾几个基本的概念,如果不是特别清楚下面几个概念的话,可以去google一下。

inode:索引节点

superblock:超级块

block:文件系统块

block group:文件系统块组

disk block:磁盘块(512字节)

block device:块设备

VFS:虚拟文件系统

EXT4存储结构

假如把整个超级块比如一本书,那么文件系统的工作就是把要记录的内容,按页码,行段记录在这本书里。这当然也包括书的目录了。我们使用dumpe2fs工具输出:

root@ubuntu:/home/user1# dumpe2fs -h s.img.ext4
dumpe2fs 1.42.9 (4-Feb-2014)
Filesystem volume name:   <none>
Last mounted on:          <not available>
Filesystem UUID:          57f8f4bc-abf4-655f-bf67-946fc0f9f25b
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal resize_inode filetype needs_recovery extent sparse_super large_file uninit_bg
Default mount options:    (none)
Filesystem state:         clean
Errors behavior:          Remount read-only
Filesystem OS type:       Linux
Inode count:              46080
Block count:              184320
Reserved block count:     0
Free blocks:              3382
Free inodes:              44404
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      47
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         7680
Inode blocks per group:   480
Last mount time:          Tue Jul 19 07:59:31 2016
Last write time:          Tue Jul 19 07:59:31 2016
Mount count:              2
Maximum mount count:      -1
Last checked:             Wed Dec 31 16:00:00 1969
Check interval:           0 (<none>)
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:	          256
Required extra isize:     28
Desired extra isize:      28
Journal inode:            8
Default directory hash:   tea
Journal backup:           inode blocks
Journal features:         (none)
Journal size:             11M
Journal length:           2880
Journal sequence:         0x00000004
Journal start:            0



Reserved GDT blocks:      609

Blocks per group:         32768

Fragments per group:      32768

Inodes per group:         8128

Inode blocks per group:   508

Flex block group size:    16

Filesystem created:       Mon May 14 13:30:51 2012

Last mount time:          Sun Jan  6 18:51:16 2013

Last write time:          Sun Jan  6 18:51:16 2013

Mount count:              282

Maximum mount count:      -1

Last checked:             Mon May 14 13:30:51 2012

Check interval:           0 (<none>)

Lifetime writes:          20 GB

Reserved blocks uid:      0 (user root)

Reserved blocks gid:      0 (group root)

First inode:              11

Inode size:               256

Required extra isize:     28

Desired extra isize:      28

Journal inode:            8

 

首先,映入眼帘的是该超级块的相关重要参数,比如inode大小,块组含块数,块组inode数目等等。这些数据是存在ext4_super_blockext4_sb_info这两个结构体中,定义在ext4.h头文件里,它们不是本篇重要讨论的内容。我们只需要知道它们是存放一些超级块信息的结构体即可。

接下来,可以看到ext4硬盘上的存储结构:

Group 0: (Blocks 0-32767) [ITABLE_ZEROED]

  Checksum 0x7cf3, unused inodes 0

  Primary superblock at 0, Group descriptors at 1-2

  Reserved GDT blocks at 3-611

  Block bitmap at 612 (+612), Inode bitmap at 628 (+628)

  Inode table at 644-1151 (+644)

  2720 free blocks, 0 free inodes, 1383 directories

  Free blocks: 8888-8959, 9068, 9071-9135, 9144-9175, 9200-9207, 9213-9214, 9279, 9700-10120, 11823-11964, 12213-12870, 12879-13043, 13139-13254, 18432-19021, 22748-22975, 32549-32767

  Free inodes:

 

这是块组0的情况,它表明块组0由块号为0-3276732768个块组成,超级块基本信息存在块0,块组描述符在块1-2,预留的块组描述符表在块3-611,块位图在块612中,inode位图在块628中,Inode表在块644-1151中,空闲的块有很多,空闲的inode没了。

接下来,我们将重点分析这句废话中每个词的含义

        超级块基本信息:

                  我们在前面已经讲过了。顾名思义,不多解释。

         块组描述符

                  在内核中就是结构体ext4_group_desc,它包括的内容为:块位图块号,inode位图块号,inode表块号,空闲块计数,自由块计数等等。

         预留的块组描述符表

                  为以后要使用所留下来的空间。

         块位图

                  这个就是一个块使用情况记录表。记录哪些块使用,哪些块未使用。它的原理就是对整个块组中0-32767这总共32768个块中作一个映射。根据一个bytes8个位00000000,一个块有4096bytes也就是有4096*8=32768个位,这32768个位刚好对应了块组中32768的块。如果第N个块被使用了则标记第N位为1,否则为0

         inode位图

                  和上面的块位图一样,这个是inode的使用情况记录表。由超级块基本信息可以看到每个块组有8128inode,这里对inode的映射原理和块位图也是一样,只不过         没有用满一个块。

         inode

                  inode表就是具体存放inode信息的地方。在ext4中,inode的大小为256字节(ext2/3中仅有它的一半,128字节),一个块可以存放16inode,由于一个块组有8128          inode,总共需要8128/16=508个块存放inode表。这个值可以在超级块基本信息中的Inode blocks per group中看到。

讲完了这些词的含义,我们对group 0有了初步的了解。那么group 1呢?

Group 1: (Blocks 32768-65535) [ITABLE_ZEROED]

  Checksum 0xbb99, unused inodes 0

  Backup superblock at 32768, Group descriptors at 32769-32770

  Reserved GDT blocks at 32771-33379

  Block bitmap at 613 (+4294935141), Inode bitmap at 629 (+4294935157)

  Inode table at 1152-1659 (+4294935680)

  598 free blocks, 0 free inodes, 648 directories

  Free blocks: 33424-33439, 33442-33443, 33564-33627, 33644-33647, 33652-33663, 33725-33871, 33878-33931, 33934-33973, 33976-33983, 34046-34047, 34176-34303, 36008, 36015, 36019, 36412, 40299-40415

  Free inodes:

 

我们看到group 1 中,primary superblock 变为了backup superblock,由于超级块基本信息对于文件系统至关重要,为了系统的健壮性,ext文件系统在每个块组中都进行了备份。ext4考虑到在每个块组中都备份有点多余,尤其是组描述符表所以就仅在块号以357为幂的块组上进行备份。

用个表格表示超级块中块组的结构:

ext4 超级块

块组描述符

Reserved GDT Blocks

数据块位图

Inode位图

inode 表

数据块

1 block

若干blocks

若干 blocks

1 block

1 block

若干

好多好多块

                                                                                                                                                    

inode

Purpose

0

Doesn't exist; there is no inode 0.

1

List of defective blocks.

2

Root directory.

3

ACL index.

4

ACL data.

5

Boot loader.

6

Undelete directory.

7

Reserved group descriptors inode.

8

Journal inode.

11

First non-reserved inode. Usually this is the lost+found directory.

 

块寻址

ext4的块寻址已经改为48位。这种设计改动是为了支持更大的文件系统大小。EXT4使用了区段(extents)这个概念,取代了过去早期UNIX文件系统中(ext2/3)中低效的非直接块映射机制。区段和NTFS上的cluster有点类似,它们都是选定了一个特定的块地址并把数个块组合一个区间。一个文件如果是碎片化的,那么就意味它着拥有多个区段,ext4会尽它自己的努力保持文件连续。

 

这种新的块寻址策略导致了先前工具的大部分问题。举个列子:

 

[root@localhost Desktop]# stat math.c

  File: `math.c'

  Size: 1477               Blocks: 8          IO Block: 4096   regular file

Device: fd00h/64768d     Inode:420402      Links: 1

Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)

Access: 2013-01-05 15:07:11.815541582 +0800

Modify: 2012-08-20 13:40:02.496797954 +0800

Change: 2012-12-30 11:28:54.751357610 +0800

 

 

由上面得到文件math.cInode号为420402

[root@localhost Desktop]# istat /dev/mapper/VolGroup-lv_root 420402

inode: 420402

Allocated

Group: 51

Generation Id: 1062005310

uid / gid: 0 / 0

mode: rrw-r--r--

Flags:

size: 1477

num of links: 1

 

Inode Times:

Accessed:         2013-01-05 15:07:11 (CST)

File Modified:   2012-08-20 13:40:02 (CST)

Inode Modified:        2012-12-30 11:28:54 (CST)

 

Direct Blocks:

127754

 

 

由上面的命令结果可以看到,Inode位于节点上块组51上,留意上面命令最下面有Direct Blocks这一行,这一行写着127754。在ext4的文件系统中,由于direct block映射的块寻址机制被取代,而采取的是extent区段树的块寻址。这个地方的值基本上是无效的。127754这个值十六进制表示为0x1f30a,我们在稍后的讨论这个值的来源。

我们知道了math.c这个文件的inode号码为420402,那么怎样知道它数据块是拿一个呢?

由前面的内容我们知道,每个块可以存16inode,那么420402则在第420402/16=26275.125个块中,也就是位于第26275个块的第二个位置。每个块组有508inode块,那么26725/508=51.72可以得知,位于块组51号之中,这个值可以在我们之前istat中可以验证。

那么具体是51块组中的哪个块呢?我们先确定这个inode块是在块组中的第几个块。因为每个块组有508inode块,51块组前面共有51*508=25908个块。第26275inode块在51块组中排在26275-25908=367的位置。查看51块组的描述:

 

Group 51: (Blocks 1671168-1703935) [ITABLE_ZEROED]

  Checksum 0x5ffd, unused inodes 0

  Block bitmap at 1572867 (+4294868995), Inode bitmap at 1572883 (+4294869011)

  Inode table at 1574420-1574927 (+4294870548)

  34 free blocks, 1 free inodes, 541 directories

  Free blocks: 1672899, 1673339, 1673344, 1674035, 1674054, 1674062, 1674077, 16

74334, 1674353-1674354, 1674423, 1675259, 1675754-1675755, 1675763, 1675860-1675

861, 1675867, 1675979, 1676183, 1676287, 1676367, 1676507, 1676526-1676527, 1676

567, 1676711, 1676743, 1676924-1676925, 1676934, 1691649, 1691658, 1691707

  Free inodes: 422608

 

看到inode的起点位于1574420,由此,我们想要找的inode信息的块就存在于1574787inode块中的第二个。

可以使用blkcat查看1574787的内容,我们用vi切换到16进制模式打开如下:

 

0000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................

0000080: 1c00 0000 4430 c1a7 c8f1 733d fc8a 6cb1  ....D0....s=..l.

0000090: 58a8 b04f 04a0 6538 0000 0000 0000 02ea  X..O..e8........

00000a0: 0706 3c00 0000 0000 2200 0000 0000 0000  ..<.....".......

00000b0: 7365 6c69 6e75 7800 0000 0000 0000 0000  selinux.........

00000c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................

00000d0: 0000 0000 0000 0000 0000 0000 7379 7374  ............syst

00000e0: 656d 5f75 3a6f 626a 6563 745f 723a 6164  em_u:object_r:ad

00000f0: 6d69 6e5f 686f 6d65 5f74 3a73 3000 0000  min_home_t:s0...

0000100: a481 0000 c505 0000 1fd1 e750 f6b4 df50  ...........P...P

0000110: b2cd 3150 0000 0000 0000 0100 0800 0000  ..1P............

0000120: 0000 0800 0100 0000 0af3 0100 0400 0000  ................

0000130: 0000 0000 0000 0000 0100 0000 d64a 1c00  .............J..

0000140: 0000 0000 0000 0000 0000 0000 0000 0000  ................

 

 我们知道inodesize大小为256字节,那么第二个inode的起始位置也就是256=0x100处。

这个时候,我们看下inode的数据结构:

 

位置

名称

描述

0x0

__le16

i_mode

文件模式

0x2

__le16

i_uid

所有者UID.

0x4

__le32

i_size_lo

文件大小.

0x8

__le32

i_atime

读取时间.

0xC

__le32

i_ctime

Inode修改时间

0x10

__le32

i_mtime

文件修改时间.

0x14

__le32

i_dtime

删除时间

0x18

__le16

i_gid

GID.

0x1A

__le16

i_links_count

硬链接计数.

0x1C

__le32

i_blocks_lo

块计数(512字节)

0x20

__le32

i_flags

文件标识(ext4使用extent需要标记0x80000)

...

0x28

__le32

i_block[EXT4_N_BLOCKS=15]

块映射(ext2/3)或区段树(ext4)

...

 

我们按照表中的结构,对照上面的块码:

 

偏移

大小

名称

描述

0x0

0x81a4

i_mode

文件模式

0x2

0x0000

i_uid

所有者UID.

0x4

0x0000 05c5

i_size_lo

文件大小.

0x8

0x50e7 d11f

i_atime

读取时间.

0xC

0x50df b4f6

i_ctime

Inode修改时间

0x10

0x5031 b2cd

i_mtime

文件修改时间.

0x14

0x0000 0000

i_dtime

删除时间

0x18

0x0000

i_gid

GID.

0x1A

0x0001

i_links_count

硬链接计数.

0x1C

0x0000 0008

i_blocks_lo

块计数(512字节)

0x20

0x0080 0000

i_flags

文件标识(ext4使用extent需要标记0x80000)

...

0x28

 ...

i_block[EXT4_N_BLOCKS=15]

块映射(ext2/3)或区段树(ext4)

...

 

细心的同学会发现大小的顺序是倒过来的,这是因为__lexx类型,lelittle endian小端开始的缩写,意思就是从小到大的顺序。我们看到文件的大小为0x5c5=1477,这说明我们找的正是math.cinode

 

因为ext4 使用区段去代替了块映射去查找文件的内容。从40-9960个字节过去是用作块映射的,如今用作存储extent信息。extent结构体有12字节的大小,反应快的同学马上会说,那么一个inode可以存放最多5extent。然而这是不对的,因为前12个字节(40-51)被段头(extent header)所占据,所以,一个inode中的区段数最多只能是4

 

现在,我们重点开始讲区段树(extent tree)

ext4中,区段树取代了旧式的逻辑块映射。这是因为在老的模式中,分配连续的1000个块需要映射这1000个块的地址。但使用了区段,只需要映射一个区段并把区段的长度标记为1000ee_len=1000)。如果起用了flex_bg的功能,一个区段可以分配一个很大的文件,这降低了元数据的大小,也提高了硬盘的效率。inode必须使用区段标记0x80000开启区段的功能。

区段的结构是树形的。每个树节点的起始为:struct ext4_extent_header(这是一个结构体,我们接下来会给大家描述它的内容)。如果一个节点是树的内部节点(即eh.eh_depth>0),那么eh.eh_entries的指针将指向struct ext4_extent_idx;每个这些索引都指向一个块,块中包含更多的区段树中的节点。如果节点是树的叶子节点(eh.eh_depth=0),那么eh.eh_entries的指针将指向struct ext4_extent;这些结构体中指向文件的数据块。区段树的根节点存在inode.i_block,也就是我们在前面讨论的从40-99的那60个字节里。

 

说了这么多,我们还是赶紧看看extent的结构吧;

 

首先出场的是段头(extent header)

 

偏移

大小

名称

描述

0x0

__le16

eh_magic

幻数magic number, 0xF30A.

0x2

__le16

eh_entries

区段数.

0x4

__le16

eh_max

最大的区段数.

0x6

__le16

eh_depth

段节点在段树中的深度。0则表示为叶子节点,指向数据块;否则指向其它段节点。

0x8

__le32

eh_generation

暂不讨论

 

同样的,对照我们的实际数据看看

 

偏移

大小

名称

描述

0x0

0xf30a

eh_magic

幻数magic number, 0xF30A.

0x2

0x0001

eh_entries

区段数.

0x4

0x0004

eh_max

最大的区段数.

0x6

0x0000

eh_depth

段节点在段树中的深度。0则表示为叶子节点,指向数据块;否则指向其它段节点。

0x8

0x0000 0000

eh_generation

暂不讨论

 

 

接下来我们先看struct ext4_extent_idx,这个结构在前面我们有提到过,用于extent树的内部节点。

 

偏移

大小

名称

描述

0x0

__le32

ei_block

逻辑块号.

0x4

__le32

ei_leaf_lo

区段树中下一层的区段节点块地址(低32位),可以指向叶子节点或者内部节点。

0x8

__le16

ei_leaf_hi

上一栏的高16位地址

0xA

__u16

ei_unused

未使用

 

我们接着看struct ext4_extent,叶子节点的结构体

 

偏移

大小

名称

描述

0x0

__le32

ee_block

此区段的第一个块号,起始块号

0x4

__le16

ee_len

区段内包含的块数.

0x6

__le16

ee_start_hi

此区段所指向的块号(高16位)

0x8

__le32

ee_start_lo

此区段所指向的块号(低32位)

 

对照我们的实际数据看看

 

偏移

大小

名称

描述

0x0

0x0000 0000

ee_block

此区段的第一个块号,起始块号

0x4

0x0001

ee_len

区段内包含的块数.

0x6

0x0000

ee_start_hi

此区段所指向的块号(高16位)

0x8

0x001c 4ad6

ee_start_lo

此区段所指向的块号(低32位)

 

由上表可以看到,因为我们的文件较小,这里作为叶子节点直接指向了文件数据块。数据块号为0x001c4ad6=1854166。我们使用命令查看块中的内容:

[root@localhost Desktop]# blkcat /dev/mapper/VolGroup-lv_root 1854166

#include <stdlib.h>

#include <math.h>

...

 

呵呵,可以看到,这就是我们的math.c文件。

 

思考:

请读者找一个大于4k的文件,看看能不能找到它的数据块。

 

删除文件

执行rm后删除文件,数据块并没有被清除,inode被释放,有下面3项会改变: 1. 文件大小被置为0

    2. 段头中的区段值被设为0

    3. 区段被清空

清空了区段意味着我们会失去文件起始物理块的地址和区段的长度。也就是说,在inode中已经不存在元数据可以帮我们恢复文件。这种行为和ext3回收inode时清除inode中的块指针很相似。这样就意味着我们只能靠传统的file-carving去恢复文件。

还记得在上一章中,我们提到过的结构体struct ext4_extent_idx。这个结构体表示在extent tree中的节点。 我们在前面的章节已经阐述过,ext4使用extent取代了传统的block映射方式。我们的案例中只展示了只有一个extent的情况。本篇文章将介绍多个extent情况下的具体细节。

 

在本文中,我们选取了文件/var/log/messages,它是系统日志的记录文件,由于它的角色特殊,时间长了会造成给很多的碎片。我们还是先看看他的inode,方法和(一)中描述的一致,在此不重复了。

 

 

0000c00: 8081 0000 d036 0000 814b ee50 7f4b ee50  .....6...K.P.K.P

0000c10: 7f4b ee50 0000 0000 0000 0100 2000 0000  .K.P........ ...

0000c20: 0000 0800 0100 00000af30400 0400 0000  ................

0000c30: 0000 0000 0000 0000 0100 0000 58c2 0b00  ............X...

0000c40: 0100 0000 0100 0000 e599 1b00 0200 0000  ................

0000c50: 0100 0000 41e6 2f00 0300 0000 0100 0000  ....A./.........

0000c60: b878 1c00 275f ea72 0000 0000 0000 0000  .x..'_.r........

0000c70: 0000 0000 0000 0000 0000 0000 0000 0000  ................

0000c80: 1c00 0000 c018 94d1 c018 94d1 c0e5 ea86  ................

0000c90: 9bea e850 d0a4 fcb4 0000 0000 0000 02ea  ...P............

0000ca0: 0706 4000 0000 0000 1f00 0000 0000 0000  ..@.............

0000cb0: 7365 6c69 6e75 7800 0000 0000 0000 0000  selinux.........

0000cc0: 0000 0000 0000 0000 0000 0000 0000 0000  ................

0000cd0: 0000 0000 0000 0000 0000 0000 0000 0000  ................

0000ce0: 7379 7374 656d 5f75 3a6f 626a 6563 745f  system_u:object_

0000cf0: 723a 7661 725f 6c6f 675f 743a 7330 0000  r:var_log_t:s0..

 

 

0x0af3开始,这是extent header起始的标记,我们还是像(一)那样,对照着表看

 

偏移

大小

名称

描述

0x0

0xf30a

eh_magic

幻数magic number, 0xF30A.

0x2

0x0004

eh_entries

区段数.

0x4

0x0004

eh_max

最大的区段数.

0x6

0x0000

eh_depth

段节点在段数中的深度。0则表示为叶子节点,指向数据块;否则指向其它段节点。

0x8

0x0000

eh_generation

暂不讨论

 

因为这里看到depth0,说明extent中指向的是数据块。在extent header中接下来的将extent是我们把接下来的数据对应到它的表中

 

偏移

大小

名称

描述

0x0

0x0000 0000

ee_block

此区段的第一个块号,起始块号

0x4

0x0001

ee_len

区段内包含的块数.

0x6

0x0000

ee_start_hi

此区段所指向的块号(高16位)

0x8

0x000b c258

ee_start_lo

此区段所指向的块号(低32位)

 

接下来的12个字节

 

偏移

大小

名称

描述

0x0

0x0000 0001

ee_block

此区段的第一个块号,起始块号

0x4

0x0001

ee_len

区段内包含的块数.

0x6

0x0000

ee_start_hi

此区段所指向的块号(高16位)

0x8

0x001b 99e5

ee_start_lo

此区段所指向的块号(低32位)

 

再接下来的12个字节

 

偏移

大小

名称

描述

0x0

0x0000 0002

ee_block

此区段的第一个块号,起始块号

0x4

0x0001

ee_len

区段内包含的块数.

0x6

0x0000

ee_start_hi

此区段所指向的块号(高16位)

0x8

0x00f2 e641

ee_start_lo

此区段所指向的块号(低32位)

 

最后的12个字节 

偏移

大小

名称

描述

0x0

0x0000 0003

ee_block

此区段的第一个块号,起始块号

0x4

0x0001

ee_len

区段内包含的块数.

0x6

0x0000

ee_start_hi

此区段所指向的块号(高16位)

0x8

0x001c 78b8

ee_start_lo

此区段所指向的块号(低32位)

 

可以通过使用blkcat看到4个块刚好凑成了messages文件,疑心重的同学可以把4个块拼成一个文件,用md5sum比较一下。这里我们并没有想看到extent中的内部节点情况。没关系,我们系统日志文件时会随着时间增长。正在笔者撰写此文时,messages已经变大了,并且超过了16k的大小,也就是超出了4个块。这时候我们看看messagesinode信息,方法不重复了。

 

0000c00: 8081 0000 4f51 0000 eb84 ef50 ea84 ef50  ....OQ.....P...P

0000c10: ea84 ef50 0000 0000 0000 0100 3800 0000  ...P........8...

0000c20: 0000 0800 0100 00000af3 0100 0400 0100  ................

0000c30: 0000 0000 0000 0000 7c03 1c00 0000 0b00  ........|.......

0000c40: 0100 0000 0100 0000 e599 1b00 0200 0000  ................

0000c50: 0100 0000 41e6 2f00 0300 0000 0100 0000  ....A./.........

0000c60: b878 1c00 275f ea72 0000 0000 0000 0000  .x..'_.r........

0000c70: 0000 0000 0000 0000 0000 0000 0000 0000  ................

0000c80: 1c00 0000 c80e c097 c80e c097 accd 3948  ..............9H

0000c90: 9bea e850 d0a4 fcb4 0000 0000 0000 02ea  ...P............

0000ca0: 0706 4000 0000 0000 1f00 0000 0000 0000  ..@.............

0000cb0: 7365 6c69 6e75 7800 0000 0000 0000 0000  selinux.........

0000cc0: 0000 0000 0000 0000 0000 0000 0000 0000  ................

0000cd0: 0000 0000 0000 0000 0000 0000 0000 0000  ................

0000ce0: 7379 7374 656d 5f75 3a6f 626a 6563 745f  system_u:object_

0000cf0: 723a 7661 725f 6c6f 675f 743a 7330 0000  r:var_log_t:s0..

 

 

经过一段时间的练习,同学们应该不需要对照表来识辨这些16进制码的含义了,如果不熟练的话,可以回过头多看几遍。我们看到这个inode较之前有了变化。extent的区段数变成了1,区段树的深度变成了1。区段树深度为1,这说明非叶子节点。

 

偏移

大小

名称

描述

0x0

0x0000 0000

ei_block

逻辑块号.

0x4

0x001c 037c

ei_leaf_lo

区段树中下一层的区段节点块地址(低32位),可以指向叶子节点或者内部节点。

0x8

0x0000

ei_leaf_hi

上一栏的高16位地址

0xA

0x000b

ei_unused

未使用

 

使用blkcat查看文件系统块1835900的内容,

 

0000000: 0af3 0e00 5401 0000 0000 0000 0000 0000  ....T...........

0000010: 0100 0000 58c2 0b00 0100 0000 0100 0000  ....X...........

0000020: e599 1b00 0200 0000 0100 0000 41e6 2f00  ............A./.

0000030: 0300 0000 0100 0000 b878 1c00 0400 0000  .........x......

0000040: 0100 0000 2d8b 1b00 0500 0000 0100 0000  ....-...........

0000050: 9a79 1c00 0600 0000 0100 0000 0d82 1b00  .y..............

0000060: 0700 0000 0100 0000 1182 1b00 0800 0000  ................

0000070: 0100 0000 1382 1b00 0900 0000 0100 0000  ................

0000080: 1682 1b00 0a00 0000 0100 0000 1882 1b00  ................

0000090: 0b00 0000 0300 0000 034e 1c00 0e00 0000  .........N......

00000a0: 0200 0000 074e 1c00 1000 0000 0400 0000  .....N..........

00000b0: e082 0c00 0000 0000 0000 0000 0000 0000  ................

 

 

从上面的数据,我们可以看到有0x000e个区段,也就是在extent header后有14extent或者extent ixd的结构体。接着看到extent最大数为0x0154=340,这个数字是怎么来的呢?我们知道在一个inode里面,这个值是4,那是因为('extent space' - 'extent header size') / 'extent size'  (60-12)/12=4,那么在这里也一样,只不过60这里要变为4096,因为我们不在inode中,而是在一个块中,即4096-12=4084,4084/12340.333,最后还剩4个字节浪费了。再接着,是树的深度,也就是0x0000表明是叶子节点。那么我们知道,这个文件由着14block的块组成。有兴趣的同学可以自己把文件dump出来拼一下。呵呵。


simg2img system.img s.new

mount  s.new /mnt/data

修改launcher2.apk

make_ext4fs -l 891M -s s.s /mnt/data

void CSortlogcatDlg::OnButton2() 
{
	// TODO: Add your control notification handler code here
	CString strText;
	CString szLine; //存储行字符串
	
	CStdioFile file;
	CString filepath;
	GetDlgItemText(IDC_EDIT1,filepath);
	file.Open(filepath,CFile::modeRead);//打开文件
	
	//逐行读取字符串
	int linescount=0;
	int linestot=0;

	typedef CArray <int,int&> array;  //   定义二维动态数组  
	array num;

	num.SetSize(1000);
	int tot=0;
	
	while( file.ReadString( szLine ) )
	{
	    char* p = strstr(szLine,".xml:");
		if(p==0)continue;
		p += strlen(".xml:");
		char* pafter = strchr(p,':');
		if(pafter){
			pafter[0]=0;
			//m_list.AddString(p);			
			int d = atoi(p);
			num[tot]=d;
			tot++;
		}		
	}
	
	//关闭文件
	file.Close();
	int i;
	int j;
	int temp;
	for(i=0;i<tot-1;i++){
		for(j=i+1;j<tot;j++){
			if(num[j]<num[i]){
				temp=num[j];
				num[j]=num[i];
				num[i]=temp;
			}
		}
	}
	CString cs;
	for(i=0;i<tot;i++){
		cs.Format("%d",num[i]);
		m_list.AddString(cs);
		if(num[i+1]!=num[i]+1){
			m_list.AddString("==========================");
		}
	}
}



展开阅读全文

没有更多推荐了,返回首页