Fork me on GitHub

EXT2文件系统

数据结构和遍历

  • Block#0 是引导块,文件系统不会使用它,它用于容纳从磁盘引导操作系统的引导程序

  • Block#1 是超级块,用于容纳关于整个文件系统的信息

  • Block#2 是块组描述符,EXT2将磁盘块分成几个组,每组有8192个块,每组用一个块组描述符结构体描述

  • Block#8 是块位图,用于表示某种项的位序列,例如磁盘块或索引节点,位图用于分配和回收项。

  • Block#9 是索引节点位图,索引节点用于代表一个文件的数据结构

  • Block#10 是索引(开始)节点块,索引节点大小用于平均分割块大小,所以每个索引节点块都包含整数个索引节点。

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

  • 邮差算法:类似二维数组的存储和访问

    遍历算法:

    (1)读取超级块。检查幻数s_magic ( OxEF53),验证它确实是EXT2FS。

    (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 NANE] [ino rec_len name_len NAME]
    其中NAME是一系列nlen字符,不含终止NULL。
    对于每个数据块,将该块读入内存并使用dir_entry *dp指向加载的数据块。
    然后使用name_len将NAME提取为字符串,并与name[0]进行比较。如果它们不匹配,则通过以下代码转到下一个dir_entry:
    dp = (dir_entry *) ((char *)dp + dp->rec_len);
    继续搜索。如果存在name[0],则可以找到它的dir_entry,从而找到它的索引节点号。

    (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)步完全相同。

    (7)
    由于(5)~(6)步将会重复n次,所以最好编写一个搜索函数:
    u32 search ( INODE*inodePtr, char *name)
    然后只需调用n次search函数
    如果搜索循环成功结束,ip必须指向路径名的索引节点。

支持Linux所有文件操作的EXT2文件系统

通过虚拟磁盘mount_root构建基本文件系统

  • mount_root.c文件。包含mount_root函数。
  • 基本文件系统树
    • type.h文件。包含ext2文件系统的数据结构类型,还包含打开文件表、挂载表、PROC结构体和文件系统常数。
    • global.c文件。包含文件系统的全局变量。
    • 实用程序函数util.c文件。包含文件系统常用的实用程序函数。
      • get_block/put_block
      • iget(dev,ino)
      • the input(INDODE *mip)
      • getino()/iget()/iput
  • 文件内容读/写函数
  • 文件系统的挂载、卸载和文件保护

三个级别

  • 1级文件系统函数
    • mkdir
    • create
    • rmdir
    • link
    • unlink
    • symlink
    • readlink
  • 2级文件系统函数
    • open
    • Iseek
    • close
    • read
    • write
    • opendir
    • readdir
  • 3级文件系统函数
    • 挂载算法
    • 卸载算法
    • 交叉挂载点
    • 文件保护
    • 实际uid和有效uid
    • 文件锁定

时间戳转换为任意可读的日期格式

unix时间戳的数据类型,是32位(4字节)的无符号数,可以表示的大致时间范围是1970-2038

为了避免"时间回归"bug,有的地方已经开始用64位(8字节)的无符号数,来表示系统时间

<time.h>

time_t

通过sizeof,在本人电脑上是8字节,long是4字节,long long 是8字节。

获取unix时间戳
time_t time(time_t *seconds)

time_t curtime;
curtime = time(NULL);
or
time(curtime)
printf("%ld\n",curtime);

char *ctime(const time_t *timer)
该函数返回一个字符串,包含了可读格式的日期和时间信息。
注意传入参数是指针。
格式固定,英文输出,星期,月份,日期,时:分:秒,年份
字符串结尾自带 '\n' ,不够灵活


struct tm *localtime(const time_t *timer)
传入指针,返回结构体指针

struct tm {
   int tm_sec;         /* 秒,范围从 0 到 59                */
   int tm_min;         /* 分,范围从 0 到 59                */
   int tm_hour;        /* 小时,范围从 0 到 23                */
   int tm_mday;        /* 一月中的第几天,范围从 1 到 31                    */
   int tm_mon;         /* 月份,范围从 0 到 11                */
   int tm_year;        /* 自 1900 起的年数                */
   int tm_wday;        /* 一周中的第几天,范围从 0 到 6                */
   int tm_yday;        /* 一年中的第几天,范围从 0 到 365                    */
   int tm_isdst;       /* 夏令时                        */    
};

虽然可以自行输出结构体里的成员,达到灵活输出日期的效果,但是time.h还有个格式化输出神器。


size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr)
format如下:它们是区分大小写的
%a 星期几的简写
%A 星期几的全称
%b 月分的简写
%B 月份的全称
%c 标准的日期的时间串
%C 年份的后两位数字
%d 十进制表示的每月的第几天
%D 月/天/年
%e 在两字符域中,十进制表示的每月的第几天
%F 年-月-日
%g 年份的后两位数字,使用基于周的年
%G 年分,使用基于周的年
%h 简写的月份名
%H 24小时制的小时
%I 12小时制的小时
%j 十进制表示的每年的第几天
%m 十进制表示的月份
%M 十时制表示的分钟数
%n 新行符
%p 本地的AM或PM的等价显示
%r 12小时的时间
%R 显示小时和分钟:hh:mm
%S 十进制的秒数
%t 水平制表符
%T 显示时分秒:hh:mm:ss
%u 每周的第几天,星期一为第一天 (值从0到6,星期一为0)
%U 第年的第几周,把星期日做为第一天(值从0到53)
%V 每年的第几周,使用基于周的年
%w 十进制表示的星期几(值从0到6,星期天为0)
%W 每年的第几周,把星期一做为第一天(值从0到53)
%x 标准的日期串
%X 标准的时间串
%y 不带世纪的十进制年份(值从0到99)
%Y 带世纪部分的十进制年份
%z,%Z 时区名称,如果不能得到时区名称则返回空字符。
%% 百分号

void format_time(time_t arg){
    char buf[64];
    struct tm *ptm = localtime(&arg);
    strftime(buf,64,"%F %T",ptm);
    printf("%s\n",buf);
  }
想要灵活输出,修改format即可
"%F %R" 2021-10-17 17:15
"%F %T" 2021-10-17 17:15:10
"%Y年%m月%e日 %H:%M:%S" 2021年10月17日 17:15:10
posted @ 2022-10-02 16:53  郭幸坤  阅读(213)  评论(0编辑  收藏  举报
1