何周遅れだよ!って気もするけどext4のディスク上のレイアウトを調べる。現状調べたのはファイルのinodeにたどり着くとこまでで、ファイルのデータにアクセスするところまではできてない。。。
基本的にはext4のwikiにあるExt4_Disk_Layoutのページを参考に。 テスト用に以下のようにディスクイメージを作り、1ファイルほど置いておく。
$ dd if=/dev/zero of=ext4.img bs=1M count=1024 $ mkfs.ext4 ./ext4.img
ファイルの内容はこんな感じで。
#!/bin/bash for i in {1..16} do echo "abcdefgh" >> test.txt done
そうしたらhexdumpでダンプを採ってあとはdebugfsコマンドや、自分でコードを書いたりしながら資料と見比べる。 まずは最初にディスクレイアウトの基本から。レイアウトの説明はwikiのLayoutにて下記のように書かれているだけど、実際にはこの通りにならない。
Group 0 Padding | ext4 Super Block | Group Descriptors | Reserved GDT Blocks | Data Block Bitmap | inode Bitmap | inode Table | Data Blocks |
---|---|---|---|---|---|---|---|
1024 bytes | 1 block | many blocks | many blocks | 1 block | 1 block | many blocks | many more blocks |
Flexible Block Groups(flex_bg)という機能がこれが有効になっている場合はデータの置き方が変わってブロックグループ0にブロックグループ0以外のブロックグループのinode bitmapやらdata block bitmapなどを置くようにするけど、この置き方が連続して置かれない場合もある模様。そうすると上記図のような置き方にならない。 ここで先ほど作ったディスクイメージをdebugfsコマンドで見てみる。コマンドラインはdebugfs -R stats ext4.img
Group 0: block bitmap at 65, inode bitmap at 81, inode table at 97 28585 free blocks, 8180 free inodes, 2 used directories, 8180 unused inodes [Checksum 0xc776] Group 1: block bitmap at 66, inode bitmap at 82, inode table at 609 32702 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes [Inode not init, Checksum 0x4b25] Group 2: block bitmap at 67, inode bitmap at 83, inode table at 1121 32768 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes [Inode not init, Block not init, Checksum 0xfe76] Group 3: block bitmap at 68, inode bitmap at 84, inode table at 1633 32703 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes [Inode not init, Checksum 0x8923] Group 4: block bitmap at 69, inode bitmap at 85, inode table at 2145 24576 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes [Inode not init, Checksum 0xcd19] Group 5: block bitmap at 70, inode bitmap at 86, inode table at 2657 32703 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes [Inode not init, Checksum 0xb41e] Group 6: block bitmap at 71, inode bitmap at 87, inode table at 3169 32768 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes [Inode not init, Block not init, Checksum 0xfd1c] Group 7: block bitmap at 72, inode bitmap at 88, inode table at 3681 32703 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes [Inode not init, Checksum 0xf58d]
このコマンドの出力にある数値はすべて10進数。で、ブロックグループは8個あってブロックグループ0のblock bitmapは65(0x41)ブロック目、ブロックグループ1は66(0x42)、以下略という感じになっている。 そうすると、ブロックグループ7のblock bitmapの終端からブロックグループ1のinode bitmapの開始位置まで空きがあるのがわかり、inode tableも同様なことがわかる。 ということで、ディスク上のレイアウトは図と多少違うということを念頭に進めていく必要がある。。。
では、まずはディスクの先頭部分から。ディスクの先頭は当然ブロックグループ0になっているけど、この中でGroup 0 Paddingの1024バイトの領域は使われない。これは単純な話でディスクの先頭はブートセクタとして利用されている可能性もあるのでそこは飛ばさないといけいないというのが理由。 そして、スーパーブロックはディスクの先頭1024バイト目から始まる。スーパーブロックが1024から始まるのはブロックが1Kでも2K、4Kどの場合でも無駄になる領域が減らせられるからでしょう。ext4のスーパーブロックのサイズは1024バイト。よってブロック0の先頭1024バイトはファイルシステムとしては未使用、1024バイト目から1KiB分がスーバーブロックで残りは未使用。 この辺りのダンプはこのようなもの。
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| <-- block group0 * 00000400 00 00 01 00 00 00 04 00 33 33 00 00 a4 ce 03 00 |........33......| <-- super block 00000410 f4 ff 00 00 00 00 00 00 02 00 00 00 02 00 00 00 |................| 00000420 00 80 00 00 00 80 00 00 00 20 00 00 2f fe e4 52 |......... ../..R| 00000430 44 fe e4 52 01 00 ff ff 53 ef 01 00 01 00 00 00 |D..R....S.......| 00000440 15 fe e4 52 00 00 00 00 00 00 00 00 01 00 00 00 |...R............| 00000450 00 00 00 00 0b 00 00 00 00 01 00 00 3c 00 00 00 |............<...| 00000460 42 02 00 00 7b 00 00 00 b2 79 38 06 17 ac 41 3e |B...{....y8...A>| 00000470 93 eb 4e 00 66 73 8d aa 00 00 00 00 00 00 00 00 |..N.fs..........| 00000480 00 00 00 00 00 00 00 00 2f 6d 6e 74 00 00 00 00 |......../mnt....| 00000490 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 000004c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3f 00 |..............?.| 000004d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 000004e0 08 00 00 00 00 00 00 00 00 00 00 00 2e 56 47 ee |.............VG.| 000004f0 f1 1a 42 cd 84 6b b6 f1 0a 83 e6 65 01 01 00 00 |..B..k.....e....| 00000500 0c 00 00 00 00 00 00 00 15 fe e4 52 0a f3 01 00 |...........R....| 00000510 04 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 |............. ..| 00000520 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000530 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000540 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 |................| 00000550 00 00 00 00 00 00 00 00 00 00 00 00 1c 00 1c 00 |................| 00000560 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000570 00 00 00 00 04 00 00 00 81 81 00 00 00 00 00 00 |................| 00000580 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
ext4のデータはリトルエンディアンでジャーナル機能のjbd2が使用している部分はビッグエンディアンらしい。何でエンディアンを混ぜるか>< この領域がext4のスーパーブロックかどうかをチェックするには0x438-0x439の2バイトを見る。ここが0xEF53ならext4のスーパーブロック。struct ext4_inodeだとs_magicがその部分。 struct ext4_super_blockの定義はここ。
スーパーブロックの次はGroup Descriptors。これは1ブロックに収まるとは限らない。これの開始位置は1ブロック目から。 ここにはBlock Group Descriptorsが置かれていて、データのサイズが64バイトもしくは32バイト。この大きさはスーパーブロックのs_feature_incompatにあるINCOMPAT_64BIT次第。このビットが立っていたら64バイト、そうでなければ32bit。 INCOMPAT_64BITは64bitのアドレッシング(実際は48bitのようだけど)が使えるようになるのでファイルシステムが最大1EiBand、ファイルサイズが最大で16TiB使える。 ext4ではこのような構造体。
285 struct ext4_group_desc 286 { 287 __le32 bg_block_bitmap_lo; /* Blocks bitmap block */ 288 __le32 bg_inode_bitmap_lo; /* Inodes bitmap block */ 289 __le32 bg_inode_table_lo; /* Inodes table block */ 290 __le16 bg_free_blocks_count_lo;/* Free blocks count */ 291 __le16 bg_free_inodes_count_lo;/* Free inodes count */ 292 __le16 bg_used_dirs_count_lo; /* Directories count */ 293 __le16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */ 294 __le32 bg_exclude_bitmap_lo; /* Exclude bitmap for snapshots */ 295 __le16 bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bbitmap) LE */ 296 __le16 bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+ibitmap) LE */ 297 __le16 bg_itable_unused_lo; /* Unused inodes count */ 298 __le16 bg_checksum; /* crc16(sb_uuid+group+desc) */ 299 __le32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ 300 __le32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */ 301 __le32 bg_inode_table_hi; /* Inodes table block MSB */ 302 __le16 bg_free_blocks_count_hi;/* Free blocks count MSB */ 303 __le16 bg_free_inodes_count_hi;/* Free inodes count MSB */ 304 __le16 bg_used_dirs_count_hi; /* Directories count MSB */ 305 __le16 bg_itable_unused_hi; /* Unused inodes count MSB */ 306 __le32 bg_exclude_bitmap_hi; /* Exclude bitmap block MSB */ 307 __le16 bg_block_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bbitmap) BE */ 308 __le16 bg_inode_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+ibitmap) BE */ 309 __u32 bg_reserved; 310 };
ext3のグループディスクリプタはこのような構造体。
102 struct ext3_group_desc 103 { 104 __le32 bg_block_bitmap; /* Blocks bitmap block */ 105 __le32 bg_inode_bitmap; /* Inodes bitmap block */ 106 __le32 bg_inode_table; /* Inodes table block */ 107 __le16 bg_free_blocks_count; /* Free blocks count */ 108 __le16 bg_free_inodes_count; /* Free inodes count */ 109 __le16 bg_used_dirs_count; /* Directories count */ 110 __u16 bg_pad; 111 __le32 bg_reserved[3]; 112 };
グループディスクリプタに限らないけどext3からext4の拡張でext3の頃に使っていたアドレスとかの大きさが増えている。 例えば、ext3のbg_block_bitmapはext4ではbg_block_bitmap_loとして、ブロックビットマップのアドレスの下位32bitとして扱い、上位32ビットはext3では使っていなかったオフセットにあるという感じで。 さて、INCOMPAT_64BITが立っていない場合、ディスクリプタのサイズは32バイトなのでext3_group_descを使っても値は取得できるんだけど、ext4の拡張部分に当たるbg_flagsを扱うにはext4のグループディスクリプタとして見たほうが楽というのもある。bg_flagsはext3のbg_padとbg_reservedを使っているので。
Group Descriptorsは1ブロックとは限らないので何ブロック使っているかは別途計算が必要。 この場合、最初にブロックグループの数を計算する。これはスーパーブロックのs_blocks_count_loとs_blocks_count_hiを64bit整数にしてs_blocks_per_groupで割ればOK。 次に((ブロックグループ数 * ディスクリプタ-のサイズ) / ブロックサイズ) + 1で完了。 cで書くとこんな感じで。
#define make_integer(type, lo, hi) ({\ typeof(type) bitmask = (typeof(type)) -1; \ typeof(type) tmp = bitmask & hi; \ u8 bit_shift = sizeof(typeof(type)) * 8; \ tmp << bit_shift | (lo & bitmask); }) static inline u64 u32_to_u64(u32 lo, u32 hi) { return make_integer(u64, lo, hi); } static void show_ext4_sb_data(const struct ext4_super_block *sb) { ~~~ nr_group_desc = u32_to_u64(sb->s_blocks_count_lo, sb->s_blocks_count_hi) / sb->s_blocks_per_group; printf("[-]Number of Block groups: %d\n", nr_group_desc); putchar('\n'); printf("[-]Flex BG\n"); printf("s_log_groups_per_flex: 0x%x : 0x%x\n", sb->s_log_groups_per_flex, 2 << sb->s_log_groups_per_flex); putchar('\n'); nr_group_desc_blocks = ((nr_group_desc * ((sb->s_feature_incompat & 0x80) ? sizeof(struct ext4_group_desc) : sizeof(struct ext3_group_desc))) / block_size) + 1; printf("Group descriptors use %d blocks\n", nr_group_desc_blocks); ~~~
今使っているディスクイメージの場合、s_blocks_count_loとs_blocks_count_hi、s_blocks_per_groupはこのような値。ブロックサイズは4KiB。
s_blocks_count_lo: 0x40000 s_blocks_count_hi: 0x0 s_blocks_per_group: 0x8000
よって、ブロックグループ数は8。
masami@saga:~/codes/read_ext4$ echo "obase=16;ibase=16; 40000/8000" | bc 8
必要なブロック数は1。
masami@saga:~/codes/read_ext4$ echo "obase=16;ibase=16; ((8 * 32) / 1000) + 1" | bc 1
ということでまたダンプを見てみる。
00001000 41 00 00 00 51 00 00 00 61 00 00 00 a9 6f f4 1f |A...Q...a....o..| <-- group0 descriptors 00001010 02 00 04 00 00 00 00 00 00 00 00 00 f4 1f 76 c7 |..............v.| 00001020 42 00 00 00 52 00 00 00 61 02 00 00 be 7f 00 20 |B...R...a...... | 00001030 00 00 05 00 00 00 00 00 00 00 00 00 00 20 25 4b |............. %K| 00001040 43 00 00 00 53 00 00 00 61 04 00 00 00 80 00 20 |C...S...a...... | 00001050 00 00 07 00 00 00 00 00 00 00 00 00 00 20 76 fe |............. v.| 00001060 44 00 00 00 54 00 00 00 61 06 00 00 bf 7f 00 20 |D...T...a...... | 00001070 00 00 05 00 00 00 00 00 00 00 00 00 00 20 23 89 |............. #.| 00001080 45 00 00 00 55 00 00 00 61 08 00 00 00 60 00 20 |E...U...a....`. | 00001090 00 00 05 00 00 00 00 00 00 00 00 00 00 20 19 cd |............. ..| 000010a0 46 00 00 00 56 00 00 00 61 0a 00 00 bf 7f 00 20 |F...V...a...... | 000010b0 00 00 05 00 00 00 00 00 00 00 00 00 00 20 1e b4 |............. ..| 000010c0 47 00 00 00 57 00 00 00 61 0c 00 00 00 80 00 20 |G...W...a...... | 000010d0 00 00 07 00 00 00 00 00 00 00 00 00 00 20 1c fd |............. ..| 000010e0 48 00 00 00 58 00 00 00 61 0e 00 00 bf 7f 00 20 |H...X...a...... | 000010f0 00 00 05 00 00 00 00 00 00 00 00 00 00 20 8d f5 |............. ..| 00001100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| *
このディスクは32バイトのグループディスクリプタを使っている。最初64バイトだと思っていて計算が合わなかったけど、INCOMPAT_64BITのことに気づいて納得した。 ここの内容は上のほうにも貼ったやつだけど、このような内容。
Group 0: block bitmap at 65, inode bitmap at 81, inode table at 97 28585 free blocks, 8180 free inodes, 2 used directories, 8180 unused inodes [Checksum 0xc776] Group 1: block bitmap at 66, inode bitmap at 82, inode table at 609 32702 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes [Inode not init, Checksum 0x4b25] Group 2: block bitmap at 67, inode bitmap at 83, inode table at 1121 32768 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes [Inode not init, Block not init, Checksum 0xfe76] Group 3: block bitmap at 68, inode bitmap at 84, inode table at 1633 32703 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes [Inode not init, Checksum 0x8923] Group 4: block bitmap at 69, inode bitmap at 85, inode table at 2145 24576 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes [Inode not init, Checksum 0xcd19] Group 5: block bitmap at 70, inode bitmap at 86, inode table at 2657 32703 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes [Inode not init, Checksum 0xb41e] Group 6: block bitmap at 71, inode bitmap at 87, inode table at 3169 32768 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes [Inode not init, Block not init, Checksum 0xfd1c] Group 7: block bitmap at 72, inode bitmap at 88, inode table at 3681 32703 free blocks, 8192 free inodes, 0 used directories, 8192 unused inodes [Inode not init, Checksum 0xf58d]
ちなみに、debugfsの出力だとInode not init、Block not initが出ているけど実際にはEXT4_BG_INODE_ZEROEDというフラグもある。 自分で書いたコードで見てみると各グループは以下のようなビットが立っていた。EXT4_BG_BLOCK_UNINITの立っているグループ2とグループ6は全部0で埋められているのでダンプだと省略されていた。
Group0 EXT4_BG_INODE_ZEROED Group1 EXT4_BG_INODE_UNINIT EXT4_BG_INODE_ZEROED Group2 EXT4_BG_INODE_UNINIT EXT4_BG_BLOCK_UNINIT EXT4_BG_INODE_ZEROED Group3 EXT4_BG_INODE_UNINIT EXT4_BG_INODE_ZEROED Group4 EXT4_BG_INODE_UNINIT EXT4_BG_INODE_ZEROED Group5 EXT4_BG_INODE_UNINIT EXT4_BG_INODE_ZEROED Group6 EXT4_BG_INODE_UNINIT EXT4_BG_BLOCK_UNINIT EXT4_BG_INODE_ZEROED Group7 EXT4_BG_INODE_UNINIT EXT4_BG_INODE_ZEROED
Group Descriptorsの次に来るのはReserved GDT Blocks。これはグループディスクリプタの予約領域。 これの数はs_reserved_gdt_blocksを見れば良くて、debugfsでも当然確認可能。このディスクでは63になっている。ダンプはこのように。
00002000 02 80 00 00 02 80 01 00 02 80 02 00 02 80 03 00 |................| <-- Reserved group descriptors 00002010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00003000 03 80 00 00 03 80 01 00 03 80 02 00 03 80 03 00 |................| 00003010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00004000 04 80 00 00 04 80 01 00 04 80 02 00 04 80 03 00 |................| 00004010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * ~~~ 0003f000 3f 80 00 00 3f 80 01 00 3f 80 02 00 3f 80 03 00 |?...?...?...?...| 0003f010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00040000 40 80 00 00 40 80 01 00 40 80 02 00 40 80 03 00 |@...@...@...@...| 00040010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
次に来るのは何かというとグループディスクリプタでみたblock bitmap。ブロックグループ0は「block bitmap at 65」とdebugfsでも表示されている。 ブロック65ということは0x41(ブロック番号) * 0x1000(ブロックサイズ)して0x41000とわかる。ブロックグループ7はブロック72なので0x49000までがblock bitmapのデータ。
00041000 ff ff ff ff ff ff ff ff ff 3f fe 01 fe ff ff ff |.........?......| <-- group0 block bitmap 00041010 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| * 00041200 ff ff ff ff ff ff ff ff ff ff ff ff 03 00 00 00 |................| 00041210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00042000 ff ff ff ff ff ff ff ff 03 00 00 00 00 00 00 00 |................| <-- group1 block bitmap 00042010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00044000 ff ff ff ff ff ff ff ff 01 00 00 00 00 00 00 00 |................| <-- group3 block bitmap 00044010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00045000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| <-- group4 block bitmap * 00045400 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00046000 ff ff ff ff ff ff ff ff 01 00 00 00 00 00 00 00 |................| <-- group5 block bitmap 00046010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00048000 ff ff ff ff ff ff ff ff 01 00 00 00 00 00 00 00 |................| <-- group7 block bitmap 00048010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
このダンプの中でグループ2とグループ6がないのは多分EXT4_BG_BLOCK_UNINITが立っていたため。
では次はinode bitmapを見てみる。これも先ほどと同じでグループディスクリプタにあるinode bitmapのインデックスからアドレスを出すだけ。
00051000 ff 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| <-- group0 inode bitmap 00051010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00051400 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| * 00052000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| <-- group1 - group7 inode bitmap * 00061000 00 00 00 00 00 00 00 00 19 fe e4 52 19 fe e4 52 |...........R...R| <-- group0 inode table(actualy group0 to group7)
もう見えているけどinode tableの開始位置も見えている。 ここまででブロックグループ0に関してはData Blocks以外は見た形。ビットマップなんかはブロックグループ0にあるので他はみなくても良いや。
ブロックグループ0のダンプを見ているとどこにディレクトリエントリーがあるかはわかるんだけど、なぜ0x49000から32MBの領域なのかは不明。 wikiページの説明によるとグループディスクリプタやらビットマップグループ以外の領域はデータブロックとして使えるようだけど。まあ変なところにあるなと。この辺の理屈はもうちょい調べないとイケナイな。
00049000 02 00 00 00 0c 00 01 02 2e 00 00 00 02 00 00 00 |................| <--- group0 directory entry 00049010 0c 00 02 02 2e 2e 00 00 0b 00 00 00 14 00 0a 02 |................| 00049020 6c 6f 73 74 2b 66 6f 75 6e 64 00 00 0c 00 00 00 |lost+found......| 00049030 d4 0f 08 01 74 65 73 74 2e 74 78 74 00 00 00 00 |....test.txt....| <--- 0xfd is rec_len 00049040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 0004a000 0b 00 00 00 0c 00 01 02 2e 00 00 00 02 00 00 00 |................| <--- end of directory entry for test.txt 0004a010 f4 0f 02 02 2e 2e 00 00 00 00 00 00 00 00 00 00 |................| 0004a020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 0004b000 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 |................| <--- end of directory entory for .. at the address 0x4a0c 0004b010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 0004c000 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 |................| 0004c010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 0004d000 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 |................| 0004d010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00051000 ff 0f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| <-- group0 inode bitmap
ディレクトリエントリーはstruct ext4_dir_entry_2が使われる。サイズは可変長でファイル名は最大EXT4_NAME_LEN文字(255)。
1623 struct ext4_dir_entry_2 { 1624 __le32 inode; /* Inode number */ 1625 __le16 rec_len; /* Directory entry length */ 1626 __u8 name_len; /* Name length */ 1627 __u8 file_type; 1628 char name[EXT4_NAME_LEN]; /* File name */ 1629 };
ディレクトリエントリーのレコード長(rec_len)は4バイトアラインになるように作られ、4バイト境界のサイズにならない場合は'\n0'がnameに追加される。その他の注意点としてディレクトリエントリーはブロックを跨がない、また、最後のレコードのrec_lenはブロックの最後までの長さになる。 どういうことかというと、上のダンプでは"."、".."、"lost+found"、"test.txt"の4つのエントリが1ブロック(0x49000〜0x49fff)にあり、各データはこのようになる。
name: . inode: 0x2 recode length: 0xc name length: 0x1 file type: 0x2 name: .. inode: 0x2 recode length: 0xc name length: 0x2 file type: 0x2 name: lost+found inode: 0xb recode length: 0x14 name length: 0xa file type: 0x2 name: test.txt inode: 0xc recode length: 0xfd4 name length: 0x8 file type: 0x1
ここで最後のエントリはtest.txtで、これのrec_lenが0xfd4。これはエントリの開始位置が0x4902cでブロックの境界が0x4a000なので引き算して0xfd4ということ。 なので最後のエントリの場合は実際に必要なデータのサイズよりも大きい形になる。
とりあえずここまででディレクトリエントリからtest.txtのinodeがわかったのでこのファイルのinodeを見てみる。 inodeのデータ構造はstruct ext4_inodeで定義される。このinodeは他のファイルシステムなどと同様にディスク上のinodeとメモリ上のinodeではデータ構造が変わる。ソースの方にもちゃんと書いてあるけど。
635 /* 636 * Structure of an inode on the disk 637 */ 638 struct ext4_inode {
inodeの大きさはスーパーブロックのs_inode_sizeで読むことができてext4では256バイト。 該当のファイルのinodeからブロックのアドレスを算出するのは以下の用に。 ((inodeサイズ * (inode番号 - 1) * ブロックサイズ )+ inode tableの開始位置
test.txtの場合、inodeのサイズは256バイト、inode番号は0xCなので1引いて-1とすると0xb00となり、これにinode tableの開始位置をブロック番号(0x61) * ブロックサイズ(0x1000)として0x61000を足すと0x61b00となるのでここを見てみる。
00061b00 a4 81 00 00 90 00 00 00 35 fe e4 52 35 fe e4 52 |........5..R5..R| 00061b10 35 fe e4 52 00 00 00 00 00 00 01 00 08 00 00 00 |5..R............| 00061b20 00 00 08 00 01 00 00 00 0a f3 01 00 04 00 00 00 |................| 00061b30 00 00 00 00 00 00 00 00 01 00 00 00 41 80 00 00 |............A...| 00061b40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00061b60 00 00 00 00 63 35 cb df 00 00 00 00 00 00 00 00 |....c5..........| 00061b70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00061b80 1c 00 00 00 30 b1 32 6e 30 b1 32 6e 30 b1 32 6e |....0.2n0.2n0.2n| 00061b90 35 fe e4 52 30 b1 32 6e 00 00 00 00 00 00 00 00 |5..R0.2n........| 00061ba0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| *
これだと分かりづらいのでinodeを読むようなコードを書いて出力してみる。
i_mode: 0x81a4 i_uid: 0x0 i_size_lo: 0x90 i_blocks_lo: 0x8 i_flags: 0x80000 osd1: 0x1 i_block[0]: 0x1f30a i_block[1]: 0x4 i_block[2]: 0x0 i_block[3]: 0x0 i_block[4]: 0x1 i_block[5]: 0x8041 i_block[6]: 0x0 i_block[7]: 0x0 i_block[8]: 0x0 i_block[9]: 0x0 i_block[10]: 0x0 i_block[11]: 0x0 i_block[12]: 0x0 i_block[13]: 0x0 i_block[14]: 0x0 atime: (null) ctime: (null) mtime: Sun Jan 26 21:23:17 2014
これでもイマイチ確認しづらいのでマウントしてlsしたものと比較。
masami@saga:~/codes/read_ext4$ ls -laih /mnt total 28K 2 drwxr-xr-x 3 root root 4.0K Jan 26 21:23 . 2 drwxr-xr-x 21 root root 4.0K Nov 1 06:35 .. 11 drwx------ 2 root root 16K Jan 26 21:22 lost+found 12 -rw-r--r-- 1 root root 144 Jan 26 21:23 test.txt
サイズはi_size_loで0x90、lsの方は144バイトと出ていてOK。mtimeも秒はわからないけどあってるので間違いないはず。
あとはブロックグループ4にディレクトリエントリーがあるとか、
20005000 02 00 00 00 0c 00 01 02 2e 00 00 00 02 00 00 00 |................| <-- block grou4 directory entry 20005010 0c 00 02 02 2e 2e 00 00 0b 00 00 00 14 00 0a 02 |................| 20005020 6c 6f 73 74 2b 66 6f 75 6e 64 00 00 0c 00 00 00 |lost+found......| 20005030 d4 0f 08 01 74 65 73 74 2e 74 78 74 00 00 00 00 |....test.txt....| 20005040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
同じくブロックグループ4にtest.txtのinodeがあるとか、
2000eb00 a4 81 00 00 90 00 00 00 35 fe e4 52 35 fe e4 52 |........5..R5..R| 2000eb10 35 fe e4 52 00 00 00 00 00 00 01 00 08 00 00 00 |5..R............| 2000eb20 00 00 08 00 01 00 00 00 0a f3 01 00 04 00 00 00 |................| 2000eb30 00 00 00 00 00 00 00 00 01 00 00 00 41 80 00 00 |............A...| 2000eb40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 2000eb60 00 00 00 00 63 35 cb df 00 00 00 00 00 00 00 00 |....c5..........| 2000eb70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 2000eb80 1c 00 00 00 30 b1 32 6e 30 b1 32 6e 30 b1 32 6e |....0.2n0.2n0.2n| 2000eb90 35 fe e4 52 30 b1 32 6e 00 00 00 00 00 00 00 00 |5..R0.2n........| 2000eba0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| *
ブロックグループ1のデータブロックにtest.txtのデータがある理由は調べる必要がある。
08041000 61 62 63 64 65 66 67 68 0a 61 62 63 64 65 66 67 |abcdefgh.abcdefg| <-- data of test.txt 08041010 68 0a 61 62 63 64 65 66 67 68 0a 61 62 63 64 65 |h.abcdefgh.abcde| 08041020 66 67 68 0a 61 62 63 64 65 66 67 68 0a 61 62 63 |fgh.abcdefgh.abc| 08041030 64 65 66 67 68 0a 61 62 63 64 65 66 67 68 0a 61 |defgh.abcdefgh.a| 08041040 62 63 64 65 66 67 68 0a 61 62 63 64 65 66 67 68 |bcdefgh.abcdefgh| 08041050 0a 61 62 63 64 65 66 67 68 0a 61 62 63 64 65 66 |.abcdefgh.abcdef| 08041060 67 68 0a 61 62 63 64 65 66 67 68 0a 61 62 63 64 |gh.abcdefgh.abcd| 08041070 65 66 67 68 0a 61 62 63 64 65 66 67 68 0a 61 62 |efgh.abcdefgh.ab| 08041080 63 64 65 66 67 68 0a 61 62 63 64 65 66 67 68 0a |cdefgh.abcdefgh.| 08041090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
debugfsの出力からinodeを使っているのはブロックグループ0だけだし。
( ´ー`)フゥー...
- 作者: Dominic Giampaolo
- 出版社/メーカー: Morgan Kaufmann
- 発売日: 2013/08/29
- メディア: Kindle版
- この商品を含むブログを見る