20201220蔡笃俊《信息安全系统设计与实现》第十一章学习笔记

ext2文件系统

一、任务内容

  • 自学教材第11章,提交学习笔记(10分)
  • 知识点归纳以及自己最有收获的内容 (3分)
  • 问题与解决思路(2分)
  • 实践内容与截图,代码链接(3分)
  • ...(知识的结构化,知识的完整性等,提交markdown文档,使用openeuler系统等)(2分)

二、知识点归纳以及自己最有收获的内容

(一)知识点归纳

在上一次的学习笔记中,我们在7.4这一小节对EXT2文件系统有了初步的了解:https://www.cnblogs.com/acacacaac/p/16727405.html
这一章对其进行了深入的展开,废话不多说,我们进入正题。

11.1 EXT2文件系统简介

多年来,Linux一直使用EXT2(Card等1995)作为默认文件系统。EXT3(EXT3,2014)是EXT2的扩展。EXT3中增加的主要内容是一个日志文件,它将文件系统的变更记录在日志中。日志可在文件系统崩溃时更快地从错误中恢复。没有错误的EXT3文件系统与EXT2文件系统相同。EXT3的最新扩展是EXT4(Cao等2007)。EXT4的主要变化是磁盘块的分配。在EXT4中,块编号为48位。EXT4不是分配不连续的磁盘块,而是分配连续的磁盘块区,称为区段。除了这些细微的更改之外,文件系统结构和文件操作保持不变。

11.2 EXT2文件系统数据结构

在对第七章的学习中,我们也了解了简单的EXT2文件系统布局中的磁盘块的内容,这一章我们来进行更加深入的了解。

11.2.1 通过mkfs创建虚拟磁盘

在Linux下,命令mke2fs [-b blkesize -N ninodes] device nblocks可以在设备上创建一个带有nblocks个块(每个块大小为blksize字节)和ninodes个索引节点的EXT2文件系统。设备可以是真实设备,也可以是虚拟磁盘文件。如果未指定blksize,则默认块大小为1KB。如果未指定ninoides,mke2fs将根据 nblocks 计算一个默认的ninodes数。得到的EXT2文件系统可在Linux中使用。
我们可以在一个名为vdisk的虚拟磁盘文件上创建一个有1440个大小为1kb的块的EXT2文件系统:

11.2.2 虚拟磁盘布局

上述的EXT2文件系统的简单布局如下图:

11.2.3 Block#1:超级块

Block#1:超级块(在硬盘分区中字节偏移量为1024)是用于容纳关于整个文件系统的信息的。以下是超级块结构中的一些重要字段:

struct ext2_super_block
{
    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
    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
    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
    u32 s_wtime;              // Write time
    u32 s_mnt_count;          // Mount count
    u16 s_max_mnt_count;      // Maximal mount count
    u16 s_magic;              // Magic signature
    // more non-essential fields
    u16 s_inode_size; // size of inode structure
};

11.2.4 Block#2:块组描述符

Block#2:块组描述块(硬盘上的s_first_data_blocks-1) EXT2将磁盘块分成几个组。每个组有8192个块(硬盘上的大小为32K)。每组用一个块组描述符结构体描述:

struct ext2_group_desc
{

    u32 bg_block_bitmap; // Bmap block number

    u32 bg_inode_bitmap; // Imap block number

    u32 bg_inode_table; // Inodes begin block number

    u16 bg_free_blocks_count; // THESE are OBVIOUS

    u16 bg_free_inodes_count;

    ul6 bg_used_dirs_count;

    u16 bg_pad; // ignore these

    u32 bg_reserved[3];

};

需要注意的是,由于一个虚拟软盘(FD)只有1440个块,而B2就只包含一个块组描述符。其中重要的字段是bg_block_bitmap、bg_inode_bitmap和bg_inode_table,他们分别指向块组的块位图、索引节点位图和索引节点起始块,而对于Linux格式的EXT2文件系统,保留了块3和7,所以它们分别为8,9,10。

11.2.5 Block#8和9:块和索引节点位图

  • Block#8:块位图是用来表示某种项的位序列,例如:磁盘块或索引节点。0表示处于FREE的状态,而1表示为IN_USE状态。一个软盘有1440个块,但是B0是引导块,不会被使用,所以位图只有1439个有效位,无效位被视为IN_USE并置1.
  • Block#9:索引节点位图,一个索引节点就是用来代表一个文件的数据结构。在EXT2 FS中,前10个索引节点是预留的。所以,空EXT2 FS的Imap以10个1开头,然后是0。无效位再次设置为1。

11.2.6 Block#10:索引(开始)节点块

Block#10:索引(开始)节点块,每个文件都用一个128节点的独特索引节点结构体表示。下面是主要索引节点字段:

struct ext2_inode
{

    u16 i_mode; // 16 bits=|tttt |ugs|rwx|rwx|rwxl

    ul6 i_uid; // owner uid

    u32 i_size; // file size in bytes

    u32 i_atime; // time fields in seconds

    u32 1_ctime; // since 00:00:00,1-1-1970

    u32 i_mtime;

    u32 i_dtime;

    i_gid; // group ID 

    u16 i_links_count; // hard-link count

    u32 i_blocks; // number of 512-byte sectors

    u32 i_flags; // IGNORE 

    u32 i_reservedl; // IGNORE 

    u32 i_block[15]; // See details below

    u32 i_pad[7]; // for inode size = 128 bytes

}

其中i_block[15]数组包括指向文件磁盘块的指针,这些磁盘块有。

  • 直接块:0-11指向直接磁盘块;
  • 间接块:12指向一个包含256个块编号的磁盘块,每个块编号指向一个磁盘块;
  • 双重间接块:13指向一个指向256个的块,每个块指向256个磁盘块;
  • 三重间接块:14是三重间接块,对于小型的“EXT2”文件系统,可以忽略这个块。

索引节点大小(128或256)用于平均分割块大小(1KB或4KB),所以,每个索引节点块都包含整数个索引节点。在简单的EXT2文件系统中,索引节点的数量是184个(Linux默认值)。索引节点块数等于184/8=23个。因此,索引节点块为B10至B32。每个索引节点都有一个唯一的索引节点编号,即索引节点在索引节点块上的位置+1。注意,索引节点位置从0开始计数,而索引节点编号从1开始计数。0索引节点编号表示没有索引节点。根目录的索引节点编号为2。同样,磁盘块编号也从1开始计数,因为文件系统从未使用块0。块编号0表示没有磁盘块。

11.2.7 数据块

紧跟在索引节点块后面的是文件存储块。

11.2.8 目录条目

目录包含dir_entry结构,即

struct ext2_dir_entry_2{
  u32 inode;
// inode number; count Erom 1,NOT 0 
  
ul6 rec_len;
// this entry's length in bytes 
  u8 name_len; // name length in bytes 
  u8 file_type;// not used
  
char name[EXT2_NAME_LEN];//name:1-255 chars,no ending NULL
}
;

11.3 邮差算法

学过数据结构的话,这部分其实很简单,算法结构如下:
LA <=> BA:

LA = info

BA = (blcok, inode)

INODES_PER_BLCOK = BLCOK_SIZE/sizeof(INODE)

blcok = (info - 1) * INODES_PER_BLCOK + inode_table;

inode = (info - 1) % INODES_PER_BLCOK

教材上11.4给出了算法的具体实现,可以参考。

11.5 遍历EXT2文件系统树

遍历算法

  1. 读取超级块。检查幻数s magic(0xEF53),验证它确实是 EXT2 FS。
  2. 读取块组描述符块(1+s first data block),以访问组0描述符。从块组描述符的bg_ inode_table条目中找到索引节点的起始块编号,并将其称为InodesBeginBlock。
  3. 读取InodeBeginBlock,获取/的索引节点,即INODE #2。
  4. 将路径名标记为组件字符串,假设组件数量为 n。例如,如果路径名=/a/b/c,则组件字符串是"a""b""c",其中n=3。用name【0】,name【1】,…,name【n-1】来表示组件。
  5. 从3.中的根索引节点开始,在其数据块中搜索 name【0】。为简单起见,我们可以假设某个目录中的条目数量很少,因此一个目录索引节点只有12个直接数据块。有了这个假设,就可以在12个(非零)直接块中搜索 name【0】。目录索引节点的每个数据块都包含以下形式的 dir_entry结构体:
    [ino rec_len name_len NAME] [ino rec_len name_len NAME]
  6. 使用索引节点号ino 来定位相应的索引节点。回想前面的内容,ino 从1开始计数。使用邮差算法计算包含索引节点的磁盘块及其在该块中的偏移量
blk = (ino - 1) * INODES_PER_BLOCK + InodesBeginBlock;
offset = (ino - 1) % INODES_PER_BLOCK;

然后在索引节点中读取/a,从中确定它是否是一个目录(DIR)。如果/a不是目录,则不能有/a/b,因此搜索失败。如果它是目录,并且有更多需要搜索的组件,那么继续搜索 下一个组件name【1】。现在的问题是:在索引节点中搜索/a的name【1】,与第5步相同。
可以编写一个搜索函数方便5~6步的循环。

11.6 EXT2文件系统的实现

EXT2文件系统数据结构:

  • (1)是当前运行进程的PROC结构体。在实际系统中,每个文件操作都是由当前执行的进程决定的。每个进程都有一个cwd,指向进程当前工作目录(CWD)的内存索引节点。它还有一个文件描述符数组 fd[],指向打开的文件实例。
  • (2)是文件系统的根指针。它指向内存中的根索引节点。当系统启动时,选择其中一个设备作为根设备,它必须是有效的EXT2.文件系统。根设备的根索引节点(inode #2)作为文件系统的根(/)加载到内存中。该操作称为"挂载根文件系统"。
  • (3)是一个openTable条目。当某个进程打开文件时,进程fd数组的某个条目会指向openTable,openTable指向打开文件的内存索引节点。
  • (4)是内存索引节点。当需要某个文件时,会把它的索引节点加载到 minode 槽中以供使用。因为索引节点是唯一的,所以在任何时候每个索引节点在内存中都只能有一个副本。在minode中,(dev, ino)会确定索引节点的来源,以便将修改后的索引节点写回磁盘。refCount字段会记录使用minode的进程数。
    dirty字段表示索引节点是否已被修改。挂载标志表示索引节点是否已被挂载,如果已被挂载,mntabPtr将指向挂载文件系统的挂载表条目。lock字段用于确保内存索引节点一次只能由一个进程访间,例如在修改索引节点时,或者在读/写操作过程中。
  • (5)是已挂载的文件系统表。对于每个挂载的文件系统,挂载表中的条目用于记录挂载的文件系统信息,例如挂载的文件系统设备号。在挂载点的内存索引节点中,挂载标志打开,mntabPtr指向挂载表条目。在挂载表条目中,mntPointPtr指向挂载点的内存索引节点。

文件系统的实现分为三个级别。每个级别处理文件系统的不同部分。这使得实现过程模块化,更容易理解。在文件系统的实现过程中,FS目录包含实现EXT2文件系统的文件。文件结构如下:

---------------------------------- Common files of FS ----------------------------------
type.h : EXT2 data structure.typesglobal.c: global variables of FS
util.c : common utility functions: getino(), iget (), iput (), search(), etc.
allocate_deallocate.c : inodes/blocks management functions

第1级别实现了基本文件系统树。它包含以下文件,实现了指定函数:

点我查看第1级别
---------------------------------- Level-1 of Fs ---------------------------------------
mkdir_creat.c      : make directory, create regular file
ls_cd_pwd.c        : list directory, change directory, get CWD path
rmdir.c            : remove directory
link_unlink.c      : hard link and unlink files
symlink_readlink.c : symbolic link files
stat.c             : return file information
misc1.c            : access,chmod, chown, utime, etc.
----------------------------------------------------------------------------------------

使用第1级别FS 函数的用户命令程序有mkdir、creat.mknod. rmdir.link.unlink.symlink, rm、ls、cd和 pwd等。

第2级别实现了文件内容读/写函数:

点我查看第2级别
---------------------------------- Level-2 of FS ---------------------------------------
open_close_lseek.c :  open file for RBAD | WRITE|APPEND,close file and lseek
read.c             :  read from file descriptor of an opened regular file
write.c            :  write to file descriptor of an opened regular file
opendir_readdir.c  :  open and read directory

第3级别实现了文件系统的挂载、卸载和文件保护。

点我查看第3级别
---------------------------------- Level-3 of FS ---------------------------------------
mount__umount.c    : mount/umount file systems
file_protection    : access permission checking
file-locking       : lock/unlock files
----------------------------------------------------------------------------------------

11.7 基本文件系统

  1. typh.h文件
    这类文件包含EXT2文件系统的数据结构类型,比如超块、组描述符、索引节点和目录条目结构。此外,它还包含打开文件表、挂载表、PROC结构体和文件系统常数。
  2. global.c文件
    这类文件包含文件系统的全局变量。
    当文件系统启动时,我们初始化所有全局数据结构,并让运行点位于PROC[0],即超级用户的进程P0(uid = 0)。在实际系统中,每个操作都是由当前运行的进程决定的。我们从超级用户进程开始,因为它不需要任何文件保护。通过权限检查以保护文件将在第3级别的FS实现中执行。
    文件系统操作过程中,全局数据结构被视为系统资源,可灵活使用和释放。每一组资源都由一对分配和释放函数管理。例如,mialloc()分配一个空闲的minode供使用,而midalloc()则释放一个使用过的minode。其他资源管理函数与此类似。
  3. mount-root
    mount_root.c文件:该文件包含mount_root()函数,在系统初始化期间调用该函数来挂载根文件系统。它读取根设备的超级块,以验证该设备是否为有效的EXT2文件系统。然后,它将根设备的根INODE (ino =2)加载到minode中,并将根指针设置为根minode。它还将所有进程的当前工作目录设置为根minode。分配一个挂载表条目来记录挂载的根文件系统。根设备的一些关键信息,如inode和块的数量、位图的起始块和 inode,表,也记录在挂载表中,以便快速访问。
    执行ls:ls [pathname] 列出了目录或文件的信息,其工作原理如下文所示。
  • ls_dir(dirname):使用opendir()和 readdir()获取目录中的文件名。对于每个文件名,调用1s_file(filename)。
  • ls_file(filename) : stat文件名,以在STAT结构体中获取文件信息。然后,列出STAT信息。
    由于stat系统调用实质上返回的是minode的相同信息,所以我们可以通过直接使用minode来修改原始的ls算法。

三、问题与解决思路

这一章以介绍为主,实践上并没有出现什么问题。唯一有点疑惑的就是在安装头文件时出现的error:

参考博客https://blog.csdn.net/qq_32693119/article/details/88682028的方法成功解决。

posted @ 2022-09-28 22:40  acacacac  阅读(69)  评论(0编辑  收藏  举报