本文意在让初学者对于硬盘内的数据结构有一个基本的理解……
对 于 ext2 文件系 统 来 说 ,硬 盘 分区首先被划分 为 一个个的 block ,一个 ext2 文件系 统 上的 每 个 block 都是一 样 大小的,但是 对 于不同的 ext2 文件系 统 , block 的大小可以有区 别 。 典型的 block 大小是 1024 bytes 或者 4096 bytes 。 这 个大小在 创 建 ext2 文件系 统 的 时 候被决定,它可以由系 统 管理 员 指定,也可以由文件系 统 的 创 建程序根据硬 盘 分区的大小,自 动选择 一个 较 合理的 值 。 这 些 blocks 被聚在一起分成几个大的 block group 。 每 个 block group 中有多少个 block 是固定的。
每 个 block group 都相 对应 一个 group descriptor , 这 些 group descriptor 被聚在一起放在硬 盘 分区的 开头 部分,跟在 super block 的后面。所 谓 super block ,我 们 下面 还 要 讲 到。在 这 个 descriptor 当中有几个重要的 block 指 针 。我 们这 里所 说 的 block 指 针 ,就是指硬 盘 分区上的 block 号数,比如,指 针 的 值为 0 ,我 们 就 说 它是指向硬 盘 分区上的 block 0 ;指 针 的 值为 1023 ,我 们 就 说 它是指向硬 盘 分区上的 block 1023 。 我 们 注意到,一个硬 盘 分区上的 block 计 数是从 0 开 始的,并且 这 个 计 数 对 于 这 个硬 盘 分区来 说 是全局性 质 的。
在 block group 的 group descriptor 中,其中有一个 block 指 针 指向 这 个 block group 的 block bitmap ,block bitmap 中的 每 个 bit 表示一个 block ,如果 该 bit 为 0 ,表示 该 block 中有数据,如果 bit 为 1 , 则 表示 该 block 是空 闲 的。注意, 这 个 block bitmap 本身也正好只有一个 block 那 么 大小。假 设 block 大小 为 S bytes ,那 么 block bitmap 当中只能 记载 8*S 个 block 的情况(因 为 一个 byte 等于 8 个 bits ,而一个 bit 对应 一个 block )。 这 也就是 说 ,一个 block group 最多只能有 8*S*S bytes 这么 大。
在 block group 的 group descriptor 中另有一个 block 指 针 指向 inode bitmap , 这 个 bitmap 同 样 也是正好有一个 block 那 么 大,里面的 每 一个 bit 相 对应 一个 inode 。 硬 盘 上的一个 inode 大体上相 对应 于文件系 统 上的一个文件或者目 录 。 关 于 inode ,我 们 下面 还 要 进 一 步讲 到。
在 block group 的 descriptor 中另一个重要的 block 指 针 ,是指向所 谓 的 inode table 。 这 个 inode table 就不止一个 block 那 么 大了。 这 个 inode table 就是 这 个 block group 中所聚集到的全部 inode 放在一起形成的。
一个 inode 当中 记载 的最 关键 的信息,是 这 个 inode 中的用 户 数据存放在什 么 地方。 我 们 在前面提到,一个 inode 大体上相 对应 于文件系 统 中的一个文件,那 么 用 户 文件的内容存放在什 么 地方, 这 就是一个 inode 要回答的 问题 。一个 inode 通 过 提供一系列的 block 指 针 ,来回答 这 个 问题 。 这 些 block 指 针 指向的 block ,里面就存放了用 户 文件的内容。
回 顾
现 在我 们 回 顾 一下。硬 盘 分区首先被分 为 好多个 block 。 这 些 block 聚在一起,被分成几 组 ,也就是 block group 。 每 个 block group 都有一个 group descriptor 。所有 这 些 descriptor 被聚在一起,放在硬 盘 分区的 开头 部分,跟在 super block 的后面。从 group descriptor 我 们 可以通 过 block 指 针 ,找到 这 个 block group 的 inode table 和 block bitmap 等等。从 inode table 里面,我 们 就可以看到一个个的 inode 了。从一个 inode ,我 们 通 过 它里面的 block 指 针 ,就可以 进 而找到存放用 户 数据的那些 block 。我 们还 要提一下, block 指 针 不是可以到 处 乱指的。一个 block group 的 block bitmap 和 inode bitmap 以及 inode table ,都依次存放在 这 个 block group 的 开头 部分,而那些存放用 户 数据的 block 就 紧 跟在它 们 的后面。 一个 block group 结 束后,另一个 block group 又跟着 开 始。
详细 的布局情况
Super Block
所 谓 ext2 文件系 统 的 super block ,就是硬 盘 分区 开头 ( 开头 的第一个 byte 是 byte 0 )从 byte 1024 开 始往后的一部分数据。由于 block size 最小是 1024 bytes ,所以 super block 可能是在 block 1 中(此 时 block 的大小正好是 1024 bytes ),也可能是在 block 0 中。
硬 盘 分区上 ext3 文件系 统 的 super block 的 详细 情况如下。其中 __u32 是表示 unsigned 不 带 符号的 32 bits 的数据 类 型,其余 类 推。 这 是 Linux 内核中所用到的数据 类 型,如果是 开发 用 户 空 间 (user-space )的程序,可以根据具体 计 算机平台的情况,用 unsigned long 等等来代替。下面列表中 关 于 fragments 的部分可以忽略,Linux 上的 ext3 文件系 统 并没有 实现 fragments 这 个特性。另外要注意,ext3 文件系 统 在硬 盘 分区上的数据是按照 Intel 的 Little-endian 格式存放的,如果是在 PC 以外的平台上 开发 ext3 相 关 的程序,要特 别 注意 这 一点。如果只是在 PC 上做 开发 ,倒不用特 别 注意。
struct ext3_super_block {
/*00*/ __u32 s_inodes_count; /* inodes 计 数 */
__u32 s_blocks_count; /* blocks 计 数 */
__u32 s_r_blocks_count; /* 保留的 blocks 计 数 */
__u32 s_free_blocks_count; /* 空 闲 的 blocks 计 数 */
/*10*/ __u32 s_free_inodes_count; /* 空 闲 的 inodes 计 数 */
__u32 s_first_data_block; /* 第一个数据 block */
__u32 s_log_block_size; /* block 的大小 */
__s32 s_log_frag_size; /* 可以忽略 */
/*20*/ __u32 s_blocks_per_group; /* 每 block group 的 block 数量 */
__u32 s_frags_per_group; /* 可以忽略 */
__u32 s_inodes_per_group; /* 每 block group 的 inode 数量 */
__u32 s_mtime; /* Mount time */
/*30*/ __u32 s_wtime; /* Write time */
__u16 s_mnt_count; /* Mount count */
__s16 s_max_mnt_count; /* Maximal mount count */
__u16 s_magic; /* Magic 签 名 */
__u16 s_state; /* File system state */
__u16 s_errors; /* Behaviour when detecting errors */
__u16 s_minor_rev_level; /* minor revision level */
/*40*/ __u32 s_lastcheck; /* time of last check */
__u32 s_checkinterval; /* max. time between checks */
__u32 s_creator_os; /* 可以忽略 */
__u32 s_rev_level; /* Revision level */
/*50*/ __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 */
/*60*/ __u32 s_feature_incompat; /* incompatible feature set */
__u32 s_feature_ro_compat; /* readonly-compatible feature set */
/*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */
/*78*/ char s_volume_name[16]; /* volume name */
/*88*/ char s_last_mounted[64]; /* directory where last mounted */
/*C8*/ __u32 s_algorithm_usage_bitmap; /* 可以忽略 */
__u8 s_prealloc_blocks; /* 可以忽略 */
__u8 s_prealloc_dir_blocks; /* 可以忽略 */
__u16 s_padding1; /* 可以忽略 */
/*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */
/*E0*/ __u32 s_journal_inum; /* 日志文件的 inode 号数 */
__u32 s_journal_dev; /* 日志文件的 设备 号 */
__u32 s_last_orphan; /* start of list of inodes to delete */
/*EC*/ __u32 s_reserved[197]; /* 可以忽略 */
};
我 们 可以看到,super block 一共有 1024 bytes 那 么 大。在 super block 中,我 们 第一个要 关 心的字段是 magic 签 名, 对 于 ext2 和 ext3 文件系 统 来 说 , 这 个字段的 值应该 正好等于 0xEF53 。 如果不等的 话 ,那 么这 个硬 盘 分区上肯定不是一个正常的 ext2 或 ext3 文件系 统 。从 这 里,我 们 也可以估 计 到, ext2 和 ext3 的兼容性一定是很 强 的,不然的 话 , Linux 内核的 开发 者 应该 会 为 ext3 文件系 统 另 选 一个 magic 签 名才 对 。
在 super block 中另一个重要的字段是 s_log_block_size 。从 这 个字段,我 们 可以得出真正的 block 的大小。我 们 把真正 block 的大小 记 作 B ,B = 1 << (s_log_block_size + 10) , 单 位是 bytes 。 举 例来 说 ,如果 这 个字段是 0 ,那 么 block 的大小就是 1024 bytes , 这 正好就是最小的 block 大小;如果 这 个字段是 2 ,那 么 block 大小就是 4096 bytes 。 从 这 里我 们 就得到了 block 的大小 这 一非常重要的数据。
Group Descriptors
我 们继续 往下,看跟在super block 后面的一堆group descriptors 。首先注意到super block 是从 byte 1024 开 始,一共有1024 bytes 那 么 大。而 group descriptors 是从super block 后面的第一个 block 开 始。也就是 说 ,如果 super block 是在block 0 ,那 么 group descriptors 就是从 block 1 开 始;如果 super block 是在 block 1 ,那 么 group descriptors 就是从 block 2 开 始。因 为 super block 一共只有 1024 bytes 那 么 大,所以不会超出一个 block 的 边 界。如果一个 block 正好是 1024 bytes 那 么 大的 话 ,我 们 看到 group descriptors 就是 紧 跟在 super block 后面的了,没有留一点空隙。而如果一个 block 是 4096 bytes 那 么 大的 话 ,那 么 在 group descriptors (从 byte 4096 开 始)和 super block 的 结 尾之 间 ,就有一定的空隙(4096 - 2048 bytes )。
那 么 硬 盘 分区上一共有多少个 block group ,或者 说 一共有多少个 group descriptors , 这 我 们 要在 super block 中找答案。super block 中的 s_blocks_count 记录 了硬 盘 分区上的 block 的 总 数,而 s_blocks_per_group 记录 了 每 个 group 中有多少个 block 。 显 然,文件系 统 上的 block groups 数量,我 们 把它 记 作 G ,G = (s_blocks_count - s_first_data_block - 1) / s_blocks_per_group + 1 。 为 什 么 要减去 s_first_data_block ,因 为 s_blocks_count 是硬 盘 分区上全部的 block 的数量,而在 s_first_data_block 之前的 block 是不 归 block group 管的,所以当然要减去。最后 为 什 么 又要加一, 这 是因 为 尾巴上可能多出来一些 block , 这 些 block 我 们 要把它划在一个相 对较 小的 group 里面。
注意,硬 盘 分区上的所有 这 些 group descriptors 要能塞在一个 block 里面。也就是 说 groups_count * descriptor_size 必 须 小于等于 block_size 。
知道了硬 盘 分区上一共有多少个 block group ,我 们 就可以把 这么 多个 group descriptors 读 出来了。先来看看 group descriptor 是什 么样 子的。
struct ext3_group_desc
{
__u32 bg_block_bitmap; /* block 指 针 指向 block bitmap */
__u32 bg_inode_bitmap; /* block 指 针 指向 inode bitmap */
__u32 bg_inode_table; /* block 指 针 指向 inodes table */
__u16 bg_free_blocks_count; /* 空 闲 的 blocks 计 数 */
__u16 bg_free_inodes_count; /* 空 闲 的 inodes 计 数 */
__u16 bg_used_dirs_count; /* 目 录计 数 */
__u16 bg_pad; /* 可以忽略 */
__u32 bg_reserved[3]; /* 可以忽略 */
};
每 个 group descriptor 是 32 bytes 那 么 大。从上面,我 们 看到了三个 关键 的 block 指 针 , 这 三个 关键 的 block 指 针 ,我 们 已 经 在前面都提到 过 了。
Inode
前面都准 备 好了以后,我 们现 在 终 于可以 开 始 读 取文件了。首先要 读 的,当然是文件系 统 的根目 录 。注意, 这 里所 谓 的根目 录 ,是相 对 于 这 一个文件系 统 或者 说 硬 盘 分区而言的,它并不一定是整个 Linux 操作系 统 上的根目 录 。 这 里的 这 个 root 目 录 存放在一个固定的 inode 中, 这 就是文件系 统 上的 inode 2 。需要提到 inode 计 数同 block 计 数一 样 ,也是全局性 质 的。 这 里需要特 别 注意的是, inode 计 数是从 1 开 始的,而前面我 们 提到 过 block 计 数是从 0 开 始, 这 个不同在 开发 程序的 时 候要特 别 留心。( 这 一奇怪的 inode 计 数方法,曾 经让 本文作者大 伤脑 筋。)
那 么 ,我 们 先来看一下得到一个 inode 号数以后,怎 样读 取 这 个 inode 中的用 户 数据。在 super block 中有一个字段 s_inodes_per_group 记载 了 每 个 block group 中有多少个 inode 。用我 们 得到的 inode 号数除以 s_inodes_per_group ,我 们 就知道了我 们 要的 这 个 inode 是在哪一个 block group 里面, 这 个除法的余数也告 诉 我 们 ,我 们 要的 这 个 inode 是 这 个 block group 里面的第几个 inode ;然后,我 们 可以先找到 这 个 block group 的 group descriptor ,从 这 个 descriptor ,我 们 找到 这 个 group 的 inode table ,再从 inode table 找到我 们 要的第几个 inode ,再以后,我 们 就可以 开 始 读 取 inode 中的用 户 数据了。
这 个公式是 这样 的:block_group = (ino - 1) / s_inodes_per_group 。 这 里 ino 就是我 们 的 inode 号数。而 offset = (ino - 1) % s_inodes_per_group , 这 个 offset 就指出了我 们 要的 inode 是 这 个 block group 里面的第几个 inode 。
找到 这 个 inode 之后,我 们 来具体的看看 inode 是什 么样 的。
struct ext3_inode {
__u16 i_mode; /* File mode */
__u16 i_uid; /* Low 16 bits of Owner Uid */
__u32 i_size; /* 文件大小, 单 位是 byte */
__u32 i_atime; /* Access time */
__u32 i_ctime; /* Creation time */
__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 计 数 */
__u32 i_flags; /* File flags */
__u32 l_i_reserved1; /* 可以忽略 */
__u32 i_block[EXT3_N_BLOCKS]; /* 一 组 block 指 针 */
__u32 i_generation; /* 可以忽略 */
__u32 i_file_acl; /* 可以忽略 */
__u32 i_dir_acl; /* 可以忽略 */
__u32 i_faddr; /* 可以忽略 */
__u8 l_i_frag; /* 可以忽略 */
__u8 l_i_fsize; /* 可以忽略 */
__u16 i_pad1; /* 可以忽略 */
__u16 l_i_uid_high; /* 可以忽略 */
__u16 l_i_gid_high; /* 可以忽略 */
__u32 l_i_reserved2; /* 可以忽略 */
};
我 们 看到在 inode 里面可以存放 EXT3_N_BLOCKS (= 15 ) 这么 多个 block 指 针 。用 户 数据就从 这 些 block 里面 获 得。15 个 blocks 不一定放得下全部的用 户 数据,在 这 里 ext3 文件系 统 采取了一 种 分 层 的 结 构。 这组 15 个 block 指 针 的前 12 个是所 谓 的 direct blocks ,里面直接存放的就是用 户 数据。第 13 个 block ,也就是所 谓 的 indirect block ,里面存放的全部是 block 指 针 , 这 些 block 指 针 指向的 block 才被用来存放用 户 数据。第 14 个 block 是所 谓 的 double indirect block ,里面存放的全是 block 指 针 , 这 些 block 指 针 指向的 block 也被全部用来存放 block 指 针 ,而 这 些 block 指 针 指向的 block ,才被用来存放用 户 数据。第 15 个 block 是所 谓 的 triple indirect block ,比上面 说 的 double indirect block 又多了一 层 block 指 针 。作 为练习 , 读 者可以 计 算一下, 这样 的分 层结 构可以使一个 inode 中最多存放多少字 节 的用 户 数据。 ( 计 算所需的信息是否已 经 足 够 ? 还 缺少哪一个 关键 数据?)
一个 inode 里面 实际 有多少个 block , 这 是由 inode 字段 i_size 再通 过计 算得到的。i_size 记录 的是文件或者目 录 的 实际 大小,用它的 值 除以 block 的大小,就可以得出 这 个 inode 一共占有几个 block 。 注意上面的 i_blocks 字段,粗心的 读 者可能会以 为 是 这 一字段 记录 了一个 inode 中 实际 用到多少个 block ,其 实 不是的。那 么这 一字段是干什 么 用的呢, 读 者朋友 们 可以借 这 个机会,体 验 一下 阅读 Linux 内核源代 码 的 乐 趣。 ;-)
文件系 统 的目 录结 构
现 在我 们 已 经 可以 读 取 inode 的内容了,再往后,我 们 将要 读 取文件系 统 上文件和目 录 的内容。 读 取文件的内容,只要把相 应 的 inode 的内容全部 读 出来就行了;而目 录 只是一 种 固定格式的文件, 这 个文件按照固定的格式 记录 了目 录 中有哪些文件,以及它 们 的文件名,和 inode 号数等等。
struct ext3_dir_entry_2 {
__u32 inode; /* Inode 号数 */
__u16 rec_len; /* Directory entry length */
__u8 name_len; /* Name length */
__u8 file_type;
char name[EXT3_NAME_LEN]; /* File name */
};
上面用到的 EXT3_NAME_LEN 是 255 。注意,在硬 盘 分区上的 dir entry 不是固定 长 度的, 每 个 dir entry 的 长 度由上面的 rec_len 字段
简单代码:
#include<stdio.h>
#define __u32 unsigned long
#define __u16 unsigned short
#define __u8 unsigned char
struct ext3_super_block {
/*00*/ __u32 s_inodes_count; /* inodes 计 数 */
__u32 s_blocks_count; /* blocks 计 数 */
__u32 s_r_blocks_count; /* 保留的 blocks 计 数 */
__u32 s_free_blocks_count; /* 空 闲 的 blocks 计 数 */
/*10*/ __u32 s_free_inodes_count; /* 空 闲 的 inodes 计 数 */
__u32 s_first_data_block; /* 第一个数据 block */
__u32 s_log_block_size; /* block 的大小 */
// __s32 s_log_frag_size; /* 可以忽略 */
/*20*/ __u32 s_blocks_per_group; /* 每 block group 的 block 数量 */
__u32 s_frags_per_group; /* 可以忽略 */
__u32 s_inodes_per_group; /* 每 block group 的 inode 数量 */
__u32 s_mtime; /* Mount time */
/*30*/ __u32 s_wtime; /* Write time */
__u16 s_mnt_count; /* Mount count */
// __s16 s_max_mnt_count; /* Maximal mount count */
__u16 s_magic; /* Magic 签 名 */
__u16 s_state; /* File system state */
__u16 s_errors; /* Behaviour when detecting errors */
__u16 s_minor_rev_level; /* minor revision level */
/*40*/ __u32 s_lastcheck; /* time of last check */
__u32 s_checkinterval; /* max. time between checks */
__u32 s_creator_os; /* 可以忽略 */
__u32 s_rev_level; /* Revision level */
/*50*/ __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 */
/*60*/ __u32 s_feature_incompat; /* incompatible feature set */
__u32 s_feature_ro_compat; /* readonly-compatible feature set */
/*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */
/*78*/ char s_volume_name[16]; /* volume name */
/*88*/ char s_last_mounted[64]; /* directory where last mounted */
/*C8*/ __u32 s_algorithm_usage_bitmap; /* 可以忽略 */
__u8 s_prealloc_blocks; /* 可以忽略 */
__u8 s_prealloc_dir_blocks; /* 可以忽略 */
__u16 s_padding1; /* 可以忽略 */
/*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */
/*E0*/ __u32 s_journal_inum; /* 日志文件的 inode 号数 */
__u32 s_journal_dev; /* 日志文件的 设备 号 */
__u32 s_last_orphan; /* start of list of inodes to delete */
/*EC*/// __u32 s_reserved[197]; /* 可以忽略 */
}ext3_block;
void Initial()
{
FILE *fp;
fp=fopen("myImage.img","rb");
// 定位
fseek(fp,1024,0);
/*00*/ fread(&(ext3_block.s_inodes_count),4,1,fp); /* inodes 计 数 */
fread(&(ext3_block.s_blocks_count),4,1,fp); /* blocks 计 数 */
fread(&(ext3_block.s_r_blocks_count),4,1,fp); /* 保留的 blocks 计 数 */
fread(&(ext3_block.s_free_blocks_count),4,1,fp); /* 空 闲 的 blocks 计 数 */
/*10*/ fread(&(ext3_block.s_free_inodes_count),4,1,fp); /* 空 闲 的 inodes 计 数 */
fread(&(ext3_block.s_first_data_block),4,1,fp); /* 第一个数据 block */
fread(&(ext3_block.s_log_block_size),4,1,fp); /* block 的大小 */
fseek(fp,4,1); /* 忽略 s_log_frag_size */
/*20*/ fread(&(ext3_block.s_blocks_per_group),4,1,fp); /* 每 block group 的 block 数量 */
fread(&(ext3_block.s_frags_per_group),4,1,fp); /* 可以忽略 */
fread(&(ext3_block.s_inodes_per_group),4,1,fp); /* 每 block group 的 inode 数量 */
fread(&(ext3_block.s_mtime),4,1,fp); /* Mount time */
/*30*/ fread(&(ext3_block.s_wtime),4,1,fp); /* Write time */
fread(&(ext3_block.s_mnt_count),2,1,fp); /* Mount count */
fseek(fp,2,1); /* 忽略 s_max_mnt_count */
fread(&(ext3_block.s_magic),2,1,fp); /* Magic 签 名 */
fread(&(ext3_block.s_state),2,1,fp); /* File system state */
fread(&(ext3_block.s_errors),2,1,fp); /* Behaviour when detecting errors */
fread(&(ext3_block.s_minor_rev_level),2,1,fp); /* minor revision level */
/*40*/ fread(&(ext3_block.s_lastcheck),4,1,fp); /* time of last check */
fread(&(ext3_block.s_checkinterval),4,1,fp); /* max. time between checks */
fread(&(ext3_block.s_creator_os),4,1,fp); /* 可以忽略 */
fread(&(ext3_block.s_rev_level),4,1,fp); /* Revision level */
/*50*/ fread(&(ext3_block.s_def_resuid),2,1,fp); /* Default uid for reserved blocks */
fread(&(ext3_block.s_def_resgid),2,1,fp); /* Default gid for reserved blocks */
fread(&(ext3_block.s_first_ino),4,1,fp); /* First non-reserved inode */
fread(&(ext3_block.s_inode_size),2,1,fp); /* size of inode structure */
fread(&(ext3_block.s_block_group_nr),2,1,fp); /* block group # of this superblock */
fread(&(ext3_block.s_feature_compat),4,1,fp); /* compatible feature set */
/*60*/ fread(&(ext3_block.s_feature_incompat),4,1,fp); /* incompatible feature set */
fread(&(ext3_block.s_feature_ro_compat),4,1,fp); /* readonly-compatible feature set */
/*68*/ fread(&(ext3_block.s_uuid),1,16,fp); /* 128-bit uuid for volume */
fread(&(ext3_block.s_volume_name),1,16,fp); /* volume name */
fread(&(ext3_block.s_last_mounted),1,64,fp); /* directory where last mounted */
fread(&(ext3_block.s_algorithm_usage_bitmap),4,1,fp);
fread(&(ext3_block.s_prealloc_blocks),1,1,fp);
fread(&(ext3_block.s_prealloc_dir_blocks),1,1,fp);
fread(&(ext3_block.s_padding1),2,1,fp);
fread(&(ext3_block.s_journal_uuid),1,16,fp); /* uuid of journal superblock */
fread(&(ext3_block.s_journal_inum),4,1,fp); /* 日志文件的 inode 号数 */
fread(&(ext3_block.s_journal_dev),4,1,fp); /* 日志文件的 设备 号 */
fread(&(ext3_block.s_last_orphan),4,1,fp); /* start of list of inodes to delete */
printf("%20s : %-d/n","s_inodes_count",ext3_block.s_inodes_count);
printf("%20s : %-d/n","s_blocks_count",ext3_block.s_blocks_count);
printf("%20s : %-d/n","s_r_blocks_count",ext3_block.s_r_blocks_count);
printf("%20s : %-d/n","s_free_blocks_count",ext3_block.s_free_blocks_count);
printf("%20s : %-d/n","s_free_inodes_count",ext3_block.s_free_inodes_count);
printf("%20s : %-d/n","s_first_data_block",ext3_block.s_first_data_block);
printf("%20s : %-d/n","s_log_block_size",ext3_block.s_log_block_size);
printf("%20s : %-d/n","s_blocks_per_group",ext3_block.s_blocks_per_group);
printf("%20s : %-d/n","s_mtime",ext3_block.s_mtime);
printf("%20s : %-d/n","s_wtime",ext3_block.s_wtime);
printf("%20s : %-d/n","s_mnt_count",ext3_block.s_mnt_count);
printf("%20s : %-x/n","s_magic",ext3_block.s_magic);
int G = (ext3_block.s_blocks_count - ext3_block.s_first_data_block - 1) / ext3_block.s_blocks_per_group + 1;
printf("%20s : %-d/n","block group",G);
fclose(fp);
}
int main()
{
Initial();
return 0;
}
后面照葫芦画瓢,就不用教了吧。