linux ext2文件系统浅析
文章目录
- 前言
- ext2内容概述
- 实验准备
- 二进制对比分析
- 1 super block
- 2 group desc
- 3 block bitmap
- 4 inode bitmap
- 5 inode_table
- inode 1
- inode 2
- inode 11
- inode 12
- 6 dir entry
- 7 data区
- 8 间接块
- 9 块组
前言
网上关于ext2文件系统的博客有很多,但看完之后还是有些云里雾里,于是我分析了一下数据结构和文件系统镜像二进制数据
【为了避免排版混乱,我引用了很多代码块标签,因为markdown会自动处理掉多的空格等符号】
ext2内容概述
第一部分 super block
第二部分 group_desc
第三部分 block_bitmap
第四部分 inode_bitmap
第五部分 inode_table
第六部分 dir entry
第七部分 data区
第八部分 间接块
第九部分 块组
实验准备
e2progfs源码下载地址
https://sourceforge.net/projects/e2fsprogs/
创建文件系统脚本
create_ext2img.sh
umount mnt
dd if=/dev/zero of=ext2.img bs=1024 count=128
mke2fs -t ext2 ext2.img -b 1024
hexdump -Cv ext2.img > 00.hex
创建几个制定大小文件脚本
make_files.sh
# 需要一个超多字符1的文件c1
# 只需改动bs即可改变目标文件大小
dd if=c1 of=file1 bs=16384 count=1
cp file1 file2
cp file1 file3
cp file1 file4
cp file1 file5
sed -i 's/1/2/g' file2
sed -i 's/1/3/g' file3
sed -i 's/1/4/g' file4
sed -i 's/1/5/g' file5
写入文件并导出2进制数据
mount ext2.img mnt
cp file1 mnt
cp file2 mnt
cp file3 mnt
cp file4 mnt
cp file5 mnt
umount mnt
hexdump -Cv ext2.img > f5.hex
二进制对比分析
以下是格式化完成之后 和按脚本操作写入文件之后的二进制对比
1 super block
超级块结构体定义
struct ext2_super_block {
/*000*/ __u32 s_inodes_count; /* Inodes count */__u32 s_blocks_count; /* Blocks count */__u32 s_r_blocks_count; /* Reserved blocks count */__u32 s_free_blocks_count; /* Free blocks count */
/*010*/ __u32 s_free_inodes_count; /* Free inodes count */__u32 s_first_data_block; /* First Data Block */__u32 s_log_block_size; /* Block size */__u32 s_log_cluster_size; /* Allocation cluster size */
/*020*/ __u32 s_blocks_per_group; /* # Blocks per group */__u32 s_clusters_per_group; /* # Fragments per group */__u32 s_inodes_per_group; /* # Inodes per group */__u32 s_mtime; /* Mount time */
/*030*/ __u32 s_wtime; /* Write time */__u16 s_mnt_count; /* Mount count */__s16 s_max_mnt_count; /* Maximal mount count */__u16 s_magic; /* Magic signature */__u16 s_state; /* File system state */__u16 s_errors; /* Behaviour when detecting errors */__u16 s_minor_rev_level; /* minor revision level */
/*040*/ __u32 s_lastcheck; /* time of last check */__u32 s_checkinterval; /* max. time between checks */__u32 s_creator_os; /* OS */__u32 s_rev_level; /* Revision level */
/*050*/ __u16 s_def_resuid; /* Default uid for reserved blocks */__u16 s_def_resgid; /* Default gid for reserved blocks */__u32 s_first_ino; /* First non-reserved inode */__u16 s_inode_size; /* size of inode structure */__u16 s_block_group_nr; /* block group # of this superblock */__u32 s_feature_compat; /* compatible feature set */
/*060*/ __u32 s_feature_incompat; /* incompatible feature set */__u32 s_feature_ro_compat; /* readonly-compatible feature set */
/*068*/ __u8 s_uuid[16] __nonstring; /* 128-bit uuid for volume */
/*078*/ __u8 s_volume_name[EXT2_LABEL_LEN] __nonstring; /* volume name, no NUL? */
/*088*/ __u8 s_last_mounted[64] __nonstring; /* directory last mounted on, no NUL? */
/*0c8*/ __u32 s_algorithm_usage_bitmap; /* For compression */__u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/__u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */__u16 s_reserved_gdt_blocks; /* Per group table for online growth */
/*0d0*/ __u8 s_journal_uuid[16] __nonstring; /* uuid of journal superblock */
/*0e0*/ __u32 s_journal_inum; /* inode number of journal file */__u32 s_journal_dev; /* device number of journal file */__u32 s_last_orphan; /* start of list of inodes to delete */
/*0ec*/ __u32 s_hash_seed[4]; /* HTREE hash seed */
/*0fc*/ __u8 s_def_hash_version; /* Default hash version to use */__u8 s_jnl_backup_type; /* Default type of journal backup */__u16 s_desc_size; /* Group desc. size: INCOMPAT_64BIT */
/*100*/ __u32 s_default_mount_opts; /* default EXT2_MOUNT_* flags used */__u32 s_first_meta_bg; /* First metablock group */__u32 s_mkfs_time; /* When the filesystem was created */
/*10c*/ __u32 s_jnl_blocks[17]; /* Backup of the journal inode */
/*150*/ __u32 s_blocks_count_hi; /* Blocks count high 32bits */__u32 s_r_blocks_count_hi; /* Reserved blocks count high 32 bits*/__u32 s_free_blocks_hi; /* Free blocks count */__u16 s_min_extra_isize; /* All inodes have at least # bytes */__u16 s_want_extra_isize; /* New inodes should reserve # bytes */
/*160*/ __u32 s_flags; /* Miscellaneous flags */__u16 s_raid_stride; /* RAID stride in blocks */__u16 s_mmp_update_interval; /* # seconds to wait in MMP checking */__u64 s_mmp_block; /* Block for multi-mount protection */
/*170*/ __u32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/__u8 s_log_groups_per_flex; /* FLEX_BG group size */__u8 s_checksum_type; /* metadata checksum algorithm */__u8 s_encryption_level; /* versioning level for encryption */__u8 s_reserved_pad; /* Padding to next 32bits */__u64 s_kbytes_written; /* nr of lifetime kilobytes written */
/*180*/ __u32 s_snapshot_inum; /* Inode number of active snapshot */__u32 s_snapshot_id; /* sequential ID of active snapshot */__u64 s_snapshot_r_blocks_count; /* active snapshot reserved blocks */
/*190*/ __u32 s_snapshot_list; /* inode number of disk snapshot list */
#define EXT4_S_ERR_START ext4_offsetof(struct ext2_super_block, s_error_count)__u32 s_error_count; /* number of fs errors */__u32 s_first_error_time; /* first time an error happened */__u32 s_first_error_ino; /* inode involved in first error */
/*1a0*/ __u64 s_first_error_block; /* block involved in first error */__u8 s_first_error_func[32] __nonstring; /* function where error hit, no NUL? */
/*1c8*/ __u32 s_first_error_line; /* line number where error happened */__u32 s_last_error_time; /* most recent time of an error */
/*1d0*/ __u32 s_last_error_ino; /* inode involved in last error */__u32 s_last_error_line; /* line number where error happened */__u64 s_last_error_block; /* block involved of last error */
/*1e0*/ __u8 s_last_error_func[32] __nonstring; /* function where error hit, no NUL? */
#define EXT4_S_ERR_END ext4_offsetof(struct ext2_super_block, s_mount_opts)
/*200*/ __u8 s_mount_opts[64] __nonstring; /* default mount options, no NUL? */
/*240*/ __u32 s_usr_quota_inum; /* inode number of user quota file */__u32 s_grp_quota_inum; /* inode number of group quota file */__u32 s_overhead_clusters; /* overhead blocks/clusters in fs */
/*24c*/ __u32 s_backup_bgs[2]; /* If sparse_super2 enabled */
/*254*/ __u8 s_encrypt_algos[4]; /* Encryption algorithms in use */
/*258*/ __u8 s_encrypt_pw_salt[16]; /* Salt used for string2key algorithm */
/*268*/ __le32 s_lpf_ino; /* Location of the lost+found inode */__le32 s_prj_quota_inum; /* inode for tracking project quota */
/*270*/ __le32 s_checksum_seed; /* crc32c(orig_uuid) if csum_seed set */
/*274*/ __u8 s_wtime_hi;__u8 s_mtime_hi;__u8 s_mkfs_time_hi;__u8 s_lastcheck_hi;__u8 s_first_error_time_hi;__u8 s_last_error_time_hi;__u8 s_first_error_errcode;__u8 s_last_error_errcode;
/*27c*/ __le16 s_encoding; /* Filename charset encoding */__le16 s_encoding_flags; /* Filename charset encoding flags */__le32 s_orphan_file_inum; /* Inode for tracking orphan inodes */__le32 s_reserved[94]; /* Padding to the end of the block */
/*3fc*/ __u32 s_checksum; /* crc32c(superblock) */
};
部分二进制对比
00:
00000400 10 00 00 00 80 00 00 00 06 00 00 00 6b 00 00 00 |............k...|
00000410 05 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 |................|
00000420 00 20 00 00 00 20 00 00 10 00 00 00 00 00 00 00 |. ... ..........|
00000430 10 73 89 66 00 00 ff ff 53 ef 01 00 01 00 00 00 |.s.f....S.......|
00000440 10 73 89 66 00 00 00 00 00 00 00 00 01 00 00 00 |.s.f............|
00000450 00 00 00 00 0b 00 00 00 80 00 00 00 38 00 00 00 |............8...|
f5:
00000400 10 00 00 00 80 00 00 00 06 00 00 00 16 00 00 00 |................|
00000410 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 |................|
00000420 00 20 00 00 00 20 00 00 10 00 00 00 13 73 89 66 |. ... .......s.f|
00000430 13 73 89 66 01 00 ff ff 53 ef 01 00 01 00 00 00 |.s.f....S.......|
00000440 10 73 89 66 00 00 00 00 00 00 00 00 01 00 00 00 |.s.f............|
00000450 00 00 00 00 0b 00 00 00 80 00 00 00 38 00 00 00 |............8...|
super block从磁盘的第1000个字节开始,前面的留给MBR什么启动分区使用
部分数据含义:
inode总数 16个
0x400 s_inodes_count = 0x10;
块总数 128个
0x404 s_blocks_count = 0x80;
保留块总数 6个
0x408 s_r_blocks_count = 0x06;
空闲块总数 从107个变成了22个(df可看)
0x40c s_free_blocks_count = 0x6b -> 0x16;
空闲inode数 刚格式化完是5个,写了5个文件就没有了
0x410 s_free_inodes_count = 0x05 -> 0x00;
每个块组拥有的块数
0x420 s_blocks_per_group = 0x2000;
inode大小 为128字节(有的环境是256字节)
0x458 s_inode_size = 0x80;
2 group desc
struct ext2_group_desc
{__u32 bg_block_bitmap; /* Blocks bitmap block */__u32 bg_inode_bitmap; /* Inodes bitmap block */__u32 bg_inode_table; /* Inodes table block */__u16 bg_free_blocks_count; /* Free blocks count */__u16 bg_free_inodes_count; /* Free inodes count */__u16 bg_used_dirs_count; /* Directories count */__u16 bg_flags;__u32 bg_exclude_bitmap_lo; /* Exclude bitmap for snapshots */__u16 bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */__u16 bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */__u16 bg_itable_unused; /* Unused inodes count */__u16 bg_checksum; /* crc16(s_uuid+group_num+group_desc)*/
};
group desc紧随super block之后
如果第一个文件系统的块大小为1024,那么group desc位于第二个块,否则位于第一个块
【解释:如果super block为1k大小,如果块大小不为1024,那就是2048或4096,这样第一个块就可以同时装下super block和group desc】
00:
00000800 03 00 00 00 04 00 00 00 05 00 00 00 6b 00 05 00 |............k...|
f5:
00000800 03 00 00 00 04 00 00 00 05 00 00 00 16 00 00 00 |................|
部分数据含义:
块位图所在的块编号 3,所以块位图在第3个块,从0xc00开始
0x800 bg_block_bitmap = 0x03;
inode位图所在的块编号 4,所以inode位图在第4个块,从0x1000开始
0x804 bg_inode_bitmap = 0x04;
inode表所在的块编号 5,所以inode位图在第5个块,从0x1400开始
0x808 bg_inode_table = 0x05;
0x80c bg_free_blocks_count = 0x69 -> 0x14;
0x80e bg_free_inodes_count = 0x05 -> 0x00;
3 block bitmap
这部分没啥好说的,就是bitmap
00:
00000c00 ff ff 0f 00 00 00 00 00 00 00 00 00 00 00 00 80 |................|
f5:
00000c00 ff ff ff ff ff ff ff ff ff 03 00 00 ff ff ff ff |................|
4 inode bitmap
一样
00:
00001000 ff 07 ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
f5:
00001000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
5 inode_table
inode的size在super block中可以查看,这里是128字节
struct ext2_inode_large {
/*00*/ __u16 i_mode; /* File mode */__u16 i_uid; /* Low 16 bits of Owner Uid */__u32 i_size; /* Size in bytes */__u32 i_atime; /* Access time */__u32 i_ctime; /* Inode Change time */
/*10*/ __u32 i_mtime; /* Modification time */__u32 i_dtime; /* Deletion Time */__u16 i_gid; /* Low 16 bits of Group Id */__u16 i_links_count; /* Links count */__u32 i_blocks; /* Blocks count */
/*20*/ __u32 i_flags; /* File flags */union {struct {__u32 l_i_version; /* was l_i_reserved1 */} linux1;struct {__u32 h_i_translator;} hurd1;} osd1; /* OS dependent 1 */
/*28*/ __u32 i_block[15];/* Pointers to blocks */
/*64*/ __u32 i_generation; /* File version (for NFS) */__u32 i_file_acl; /* File ACL */__u32 i_size_high;
/*70*/ __u32 i_faddr; /* Fragment address */union {struct {__u16 l_i_blocks_hi;__u16 l_i_file_acl_high;__u16 l_i_uid_high; /* these 2 fields */__u16 l_i_gid_high; /* were reserved2[0] */__u16 l_i_checksum_lo; /* crc32c(uuid+inum+inode) */__u16 l_i_reserved;} linux2;struct {__u8 h_i_frag; /* Fragment number */__u8 h_i_fsize; /* Fragment size */__u16 h_i_mode_high;__u16 h_i_uid_high;__u16 h_i_gid_high;__u32 h_i_author;} hurd2;} osd2; /* OS dependent 2 */
/*80*/ __u16 i_extra_isize;__u16 i_checksum_hi; /* crc32c(uuid+inum+inode) */__u32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */__u32 i_mtime_extra; /* extra Modification time (nsec << 2 | epoch) */__u32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */
/*90*/ __u32 i_crtime; /* File creation time */__u32 i_crtime_extra; /* extra File creation time (nsec << 2 | epoch)*/__u32 i_version_hi; /* high 32 bits for 64-bit version */
/*9c*/ __u32 i_projid; /* Project ID */
};
inode 1
不知道干啥的,没有块指针
00001400 00 00 00 00 00 00 00 00 10 73 89 66 10 73 89 66 |.........s.f.s.f|
00001410 10 73 89 66 00 00 00 00 00 00 00 00 00 00 00 00 |.s.f............|
00001420 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
inode 2
根目录
00001480 ed 41 00 00 00 04 00 00 10 73 89 66 13 73 89 66 |.A.......s.f.s.f|
00001490 13 73 89 66 00 00 00 00 00 00 03 00 02 00 00 00 |.s.f............|
000014a0 00 00 00 00 05 00 00 00 07 00 00 00 00 00 00 00 |................|
........ 00 00
i_block[15];定义了15个块指针,其中第0-11个是直接块指针,第12个是单间接块指针,第13个是双重间接块指针,第14个是三间接块指针
从addr+0x28 -> addr+0x54都是直接块,这里,根目录有一个直接块指向07(dir entry)
inode 11
lost+found
00001900 c0 41 00 00 00 30 00 00 10 73 89 66 10 73 89 66 |.A...0...s.f.s.f|
00001910 10 73 89 66 00 00 00 00 00 00 02 00 18 00 00 00 |.s.f............|
00001920 00 00 00 00 00 00 00 00 08 00 00 00 09 00 00 00 |................|
00001930 0a 00 00 00 0b 00 00 00 0c 00 00 00 0d 00 00 00 |................|
00001940 0e 00 00 00 0f 00 00 00 10 00 00 00 11 00 00 00 |................|
00001950 12 00 00 00 13 00 00 00 00 00 00 00 00 00 00 00 |................|
00001960 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00001970 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
lost+found的直接块指向0x08-0x13
所以在第0x2000-0x4c00的位置
inode 12
第一个普通文件,也就是我们file1的inode(之前是全0)
00001980 a4 81 00 00 00 40 00 00 13 73 89 66 13 73 89 66 |.....@...s.f.s.f|
00001990 13 73 89 66 00 00 00 00 00 00 01 00 22 00 00 00 |.s.f........"...|
000019a0 00 00 00 00 01 00 00 00 7f 00 00 00 7d 00 00 00 |............}...|
000019b0 7e 00 00 00 15 00 00 00 16 00 00 00 17 00 00 00 |~...............|
000019c0 18 00 00 00 79 00 00 00 7a 00 00 00 7b 00 00 00 |....y...z...{...|
000019d0 7c 00 00 00 19 00 00 00 1a 00 00 00 00 00 00 00 ||...............|
000019e0 00 00 00 00 b6 00 95 b6 00 00 00 00 00 00 00 00 |................|
直接块指向0x7f 0x7d 0x7e 0x15 0x16 0x17 0x18 0x79 0x7a 0x7b 0x7c 0x19
【0x15-0x19 0x79-0x7f】
还有间接块0x1a
inode table从0x1400开始,但几个文件的inode排列在最后的原因:
前11个inode已经预留了,普通文件的inode从第12个开始
inode没有id之类的序号,查找依靠的就是在inode table里的索引
6 dir entry
存放目录和文件名的块?
00001c00 02 00 00 00 0c 00 01 02 2e 00 00 00 02 00 00 00 |................|
00001c10 0c 00 02 02 2e 2e 00 00 0b 00 00 00 14 00 0a 02 |................|
00001c20 6c 6f 73 74 2b 66 6f 75 6e 64 00 00 0c 00 00 00 |lost+found......|
00001c30 10 00 05 01 66 69 6c 65 31 00 00 00 0d 00 00 00 |....file1.......|
00001c40 10 00 05 01 66 69 6c 65 32 00 00 00 0e 00 00 00 |....file2.......|
00001c50 10 00 05 01 66 69 6c 65 33 00 00 00 0f 00 00 00 |....file3.......|
00001c60 10 00 05 01 66 69 6c 65 34 00 00 00 10 00 00 00 |....file4.......|
00001c70 94 03 05 01 66 69 6c 65 35 00 00 00 00 00 00 00 |....file5.......|
struct ext2_dir_entry_2 {__u32 inode; /* Inode number */__u16 rec_len; /* Directory entry length */__u8 name_len; /* Name length */__u8 file_type;char name[EXT2_NAME_LEN]; /* File name */
};
这个块里存放了很多ext2_dir_entry_2条目,他们以4字节对齐,紧凑连接(长度不固定
上述数据分析:
# 第1个是.目录
inode rec_len name_len file_type name
02 0c 01 02 2e 00 00 00# 第2个是..目录
inode rec_len name_len file_type name
02 0c 02 02 2e 2e 00 00# 第3个是lost+found目录
inode rec_len name_len file_type name
0b 14 0a 02 6c 6f 73 74 2b 66 6f 75 6e 64 00 00# 第4个是文件file1
inode rec_len name_len file_type name
0c 10 05 01 66 69 6c 65 31 00 00 00
7 data区
我也是服了,不同的环境他的这个分布策略也不太一样
之前我在其他环境上测试的结果是连续的,这里就不解释了
00005400 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 |1111111111111111|
...
000067f0 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 |1111111111111111|
00006800 1b 00 00 00 1c 00 00 00 1d 00 00 00 1e 00 00 00 |................|
...
00006c00 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 |1111111111111111|
...
00007bf0 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 |1111111111111111|
00007c00 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222|
...
000083f0 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222|
00008400 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 |3333333333333333|
...
00008ff0 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 |3333333333333333|
00009000 25 00 00 00 26 00 00 00 27 00 00 00 28 00 00 00 |%...&...'...(...|
...
00009400 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 |3333333333333333|
...
0000a3f0 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 |3333333333333333|
0000a400 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 |4444444444444444|
...
0000d3f0 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 |4444444444444444|
0000d400 36 00 00 00 37 00 00 00 38 00 00 00 39 00 00 00 |6...7...8...9...|
...
0000d800 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 |4444444444444444|
...
0000e7f0 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 |4444444444444444|
0000e800 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 |5555555555555555|
...
000117f0 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 |5555555555555555|
00011800 47 00 00 00 48 00 00 00 49 00 00 00 4a 00 00 00 |G...H...I...J...|
...
00011c00 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 |5555555555555555|
...
000117f0 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 |5555555555555555|
00011800 47 00 00 00 48 00 00 00 49 00 00 00 4a 00 00 00 |G...H...I...J...|
...
00011c00 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 |5555555555555555|
...
00012bf0 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 |5555555555555555|00012c00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
...
000183f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00018400 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222|
...
00018bf0 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222|
00018c00 64 00 00 00 65 00 00 00 66 00 00 00 67 00 00 00 |d...e...f...g...|
...
00019000 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222|
...
00019ff0 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222|
0001a000 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 |3333333333333333|
...
0001c3f0 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 |3333333333333333|
0001c400 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222|
...
0001e3f0 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222|
0001e400 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 |1111111111111111|
...
0001fff0 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 |1111111111111111|
8 间接块
需要结合前面的inode和data区中一些奇怪的数据来看
inode table部分我们已经说过,file有一个指向0x1a的单间接块
然后0x1a块的内容:
00006800 1b 00 00 00 1c 00 00 00 1d 00 00 00 1e 00 00 00 |................|
这就是单间接块,块里面充斥着32位无符号数,这里的每个数都表示着一个直接指向的块
0x1b -> 0x1e 【0x6c00 - 0x7800 + 0x400 -1】因为0x7800是最后一个块的起始地址,还要再加上块的大小
对照#7的这段数据,果然符合
00006c00 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 |1111111111111111|
...
00007bf0 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 |1111111111111111|
00007c00 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222|
双重间接块里放的就是单间接块的地址,以此类推
9 块组
那么,块组在哪里?
其他人写的ext2文件系统博客,总是有一个很经典的图
————————————————————————————————————————————————————
| boot block | Block Group 1 | Block Group 2 | ... |
————————————————————————————————————————————————————
而如果按照我提供的制作脚本制作文件系统镜像,却并没发现第二个块组的踪影,这是为什么呢?
我也是很费解的,linux内核文档有这么一段
Block Groups
------------Blocks are clustered into block groups in order to reduce fragmentation
and minimise the amount of head seeking when reading a large amount
of consecutive data. Information about each block group is kept in a
descriptor table stored in the block(s) immediately after the superblock.
Two blocks near the start of each group are reserved for the block usage
bitmap and the inode usage bitmap which show which blocks and inodes
are in use. Since each bitmap is limited to a single block, this means
that the maximum size of a block group is 8 times the size of a block.
this means that the maximum size of a block group is 8 times the size of a block
如果我没理解错的话,一个块组最多有8个块
那我这个划了128个块的小文件系统镜像应该有十几个块组啊?
好吧,实际上他不是这么实现的
在super block那一节,有这么一个属性:
s_blocks_per_group = 0x2000; 【每个块组拥有8192个块】
我的理解是,至少要划分超过8k个块才会出现第二个块组
但是,以每个块1024的大小计算,8k个块划出的镜像大小超过8MB,这个数据量显然不是我可以手工分析的
所以,就这样
相关文章:

linux ext2文件系统浅析
文章目录 前言ext2内容概述实验准备二进制对比分析1 super block2 group desc3 block bitmap4 inode bitmap5 inode_tableinode 1inode 2inode 11inode 12 6 dir entry7 data区8 间接块9 块组 前言 网上关于ext2文件系统的博客有很多,但看完之后还是有些云里雾里&a…...

「树莓派入门」树莓派进阶02-传感器应用与交通灯项目
传感器是树莓派实现智能化的关键。通过本教程,你可以开始尝试使用传感器来增强树莓派的功能。 一、传感器在树莓派中的作用 传感器是树莓派与外界环境交互的重要工具。它们可以检测各种物理量,如光、声音、温度等,并将这些物理量转换为电信号,供树莓派读取和处理。 二、数…...

pytorch 指定GPU设备
使用os.environ["CUDA_VISIBLE_DEVICES"] 这种方法是通过环境变量限制可见的CUDA设备,从而在多个GPU的机器上只让PyTorch看到并使用指定的GPU。这种方式的好处是所有后续的CUDA调用都会使用这个GPU,并且代码中不需要显式地指定设备索引。 im…...

华为od-C卷200分题目6 - 5G 网络建设
华为od-C卷200分题目6 - 5G 网络建设 题目描述 现需要在某城市进行 5G 网络建设,已经选取 N 个地点设置 5G 基站,编号固定为 1 到 N,接下来需要各个基站之间使用光纤进行连接以确保基站能互联互通,不同基站之间架设光纤的成本各不…...

步进电机(STM32+28BYJ-48)
一、简介 步进电动机(stepping motor)把电脉冲信号变换成角位移以控制转子转动的执行机构。在自动控制装置中作为执行器。每输入一个脉冲信号,步进电动机前进一步,故又称脉冲电动机。步进电动机多用于数字式计算机的外部设备&…...

Node.js介绍 , 安装与使用
1.Node.js 1 什么是Node.js 官网:https://nodejs.org/zh-cn/ 中文学习网:http://nodejs.cn/learn1.Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。 2.前端的底层 html…...

JavaEE初阶-网络原理1
文章目录 前言一、UDP报头二、UDP校验和2.1 CRC2.2 md5 前言 学习一个网络协议,最主要就是学习的报文格式,对于UDP来说,应用层数据到达UDP之后,会给应用层数据报前面加上UDP报头。 UDP数据报UDP包头载荷 一、UDP报头 如上图UDP的…...

leetcode秋招冲刺 (专题16--18)
专题16:分治 题目169:多数元素(YES) 解题思路:使用哈希表可以统计出现次数的性质,直接统计就行。 给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊…...

学懂C#编程:实用方法——string字符串指定连接符拼接之 string.Join 的详细用法
在C#中,string.Join 方法用于将一个字符串数组或集合中的元素连接成一个单一的字符串,并在每个元素之间插入指定的分隔符。这个方法非常有用,特别是在需要将多个字符串合并成一个字符串时。以下是 string.Join 方法的详细用法: 方…...

Javascript常见数据结构和设计模式
在JavaScript中,常见的数据结构包括两大类:原始数据类型(Primitive Types)和对象类型(Object Types)。对象类型又可以进一步细分为多种内置对象、数组、函数等。下面是一些JavaScript中常见的数据结构&…...

【ChatGPT】全面解析 ChatGPT:从起源到未来
ChatGPT 是由 OpenAI 开发的一个基于 GPT(Generative Pre-training Transformer)架构的聊天机器人。通过自然语言处理(NLP)技术,ChatGPT 能够理解和生成语言,与人类进行对话。本文将深入探讨其起源、发展、…...

html+css+js贪吃蛇游戏
贪吃蛇游戏🕹四个按钮控制方向🎮 源代码在图片后面 点赞❤️关注🙏收藏⭐️ 互粉必回🙏🙏😍😍😍 源代码📟 <!DOCTYPE html> <html lang"en"&…...

新手必学:掌握Excel中这些常用公式,轻松提升数据处理能力
各位同学好,今天和大家来分享几个常用函数公式的典型用法。 1、提取指定条件的不重复名单 如下图所示,某公司课程比赛,同一员工有多个比赛项目。希望从左侧的列表中,提取出财务部的参赛人员名单。F2单元格输入以下公式࿰…...

经济寒冬:竞品凶猛,你的产品如何求生?
那些年曾被竞品干掉的产品 1997年到2010年左右是国内互联网行业的快速发展和多元化发展的时期,这一时期涌现出来一大批优秀的产品,市场竞争越来越激烈。苹果 在20 世纪 80 年代,乔布斯的苹果电脑,在当时可是PC行业的老大…...

信号量——Linux并发之魂
欢迎来到 破晓的历程的 博客 引言 今天,我们继续学习Linux线程本分,在Linux条件变量中,我们对条件变量的做了详细的说明,今天我们要利用条件变量来引出我们的另一个话题——信号量内容的学习。 1.复习条件变量 在上一期博客中&…...

自动驾驶中的逆透视变换(Inverse Perspective Mapping,IPM)详解
前言 IPM(Inverse Perspective Mapping,逆透视变换)图的历史可以追溯到计算机视觉和图像处理领域的发展。逆透视变换是一种用于消除图像中透视效应的技术,使得原本由于透视产生的形变得以纠正,进而更准确地描述和理解图像中的场景。比如在行车中的车道线检测,泊车中的常见…...

Python地震波逆问题解构算法复杂信号分析
🎯要点 🎯时域、时频域以及时间和频率相关联偏振特性分析三种算法 | 🎯时域波参数估计算法 | 🎯机器学习模型波形指纹分析算法 | 🎯色散曲线和频率相关波分析算法 | 🎯动态倾斜校正算法 | 🎯声…...

C语言 -- 深入理解指针(二)
C语言 -- 深入理解指针(二) 1. 数组名的理解2. 使用指针访问数组3. 一维数组传参的本质4. 冒泡排序5. 二级指针6. 指针数组7. 指针数组模拟二维数组8. 字符指针变量9. 数组指针变量2.1数组指针变量是什么?2.2 数组指针变量怎么初始化 10. 二维…...

HTTP协议详解
HTTP协议详解 一、HTTP协议概述二、网络基础与HTTP2.1 TCP/IP协议2.2 发送HTTP请求过程2.3 HTTP请求的组成部分 三、HTTP报文HTTP请求报文HTTP响应报文 结语 一、HTTP协议概述 HTTP,即超文本传输协议(Hypertext Transfer Protocol)ÿ…...

一年时间业绩增长2倍,茅台保健酒业公司在川销售的“三板斧”
执笔 | 尼 奥 编辑 | 扬 灵 作为土地面积全国第5、人口总数全国第3、GDP全国第6的产酒、销酒大省,四川酒类消费总额已达800亿元,其中白酒市场规模达到500亿元。 近年来,随着省外名酒提升对四川市场重视,其市场份额也从20年前的3%…...

土豆炒肉做法
菜单:土豆、葱、铁辣子、纯瘦肉、淀粉、生抽、酱油、刀、案板、十三香、盐巴、擦板 流程: 洗土豆,削皮,擦成条,用凉水过滤两遍淀粉,顺便放个燥里洗肉,切成条,按照生抽、酱油、淀粉、…...

VPS拨号服务器:独享的高效与安全
在当今互联网高速发展的时代,虚拟私人服务器(VPS)已成为许多企业和个人用户托管网站、应用程序的首选。特别是带有拨号功能的VPS服务器,以其独特的优势受到广泛关注。本文将深入探讨VPS拨号服务器的独享特性,以及它如何…...

网络安全设备——防火墙
网络安全设备防火墙是一种用来加强网络之间访问控制的特殊网络互联设备。以下是对防火墙的详细解释: 一、定义与基本概念 定义:防火墙是指设置在不同网络(如可信任的企业内部网和不可信的公共网)或网络安全域之间的一系列部件的…...

Redis 管道技术
Redis 管道技术 引言 Redis,作为一个高性能的键值存储系统,被广泛应用于各种场景,如缓存、消息队列等。为了进一步提高Redis的处理能力和效率,Redis管道技术应运而生。本文将深入探讨Redis管道技术的原理、应用及其优势。 什么是Redis管道技术 Redis管道技术是一种允许…...

使用vue3-treeselect问题
1.当vue3-treeselect是单选时,使用watch监听绑定value,无法监听到值清空 对照后将:value改为v-model,如图 2.使用vue3-treeselect全部清空按钮如何置空select的值,使用watch监听 多选:pageInfo.officeName(val) {// …...

每日直播分享车载知识:硬件在环、UDS诊断、OTA升级、TBOX测试、CANoe、ECU刷写、CAN一致性测试:物理层、数据链路层等
每日直播时间:(进腾讯会议方式:QazWsxEdc_2010) 周一到周五:20:00-23:00(讲一个小时,实操两个小时) 周六与周日:9:00-17:0…...

flex布局---子元素未设置高度,默认与父元素同高---侧轴方向的拉伸
父元素未设置固定高度,由子元素高度撑开,并给父元素开启 flex 布局,成为伸缩容器。 父元素中有三个子元素,为伸缩项目,三个伸缩项目都未指定高度,div.inner1 的高度由内容撑开,div.inner2 和 d…...

资源分享—2021版三调符号库
汇总整理平台软件支持过程中客户项目提供的各类资源(包括但不限于符号库、地图模板等),在客户允许情况下进行集团内分享。 本次分享新版国土空间规划【三调符号库(2021版)】,提供SuperMap格式符号库下载。 …...

解决selenium手动下载驱动问题
解决selenium手动下载驱动问题 每次都需要手动下载驱动很头疼,今天发现一个可以自动下载最新驱动的包webdriver_manager,挺不错的 安装依赖包 pip install selenium pip install webdriver_manager from selenium import webdriver from selenium.webdr…...

使用fifo IP核,给fifo写数据,当检测到ALMOST_EMPTY时,为什么不能立即赋值
这涉及到FIFO(先入先出缓冲器)的内部工作机制和时序考虑。让我详细解释为什么在检测到ALMOST_EMPTY信号时不能立即向FIFO写入数据。 ALMOST_EMPTY信号的特性: ALMOST_EMPTY是一个预警信号,表示FIFO中的数据量已经接近空。这个信号…...