i-节点介绍
UFS文件系统的i-节点用来存储与文件相关的除文件名以外的所有信息,包括指向文件的硬链接数、文件大小、文件的时间信息、文件属主的用户ID、文件所属的组ID、文件内容存放地址的块指针等重要信息。这些重要信息也被称为元数据。
UFS文件系统的每个柱面组中都有一个自己的i-节点表。i-节点表由很多i-节点组成,每个文件或者目录使用一个i-节点。UFS1的i-节点在文件系统创建时即被初始化,而UFS2的i-节点则在需要时才被初始化,所以当文件系统中的数据块不够使用时,UFS2能够使用i-节点表中的空闲空间存放数据。
UFS文件系统的i-节点中用块指针描述文件内容的存放地址。每个i-节点中有15个块指针,包括12个直接块指针、1个间接块指针、1个二级间接块指针和1个三级间接块指针。12个直接块指针指向文件内容的前12个数据块地址。如果文件大于12个块,则第13个块指针是一个间接块指针,它指向的块包含直接块指针而不是文件内容。第14个块指针是二级间接块指针,它指向的块包含一级间接块指针而不是文件内容。第15个块指针是三级间接块指针,它指向的块包含二级间接块指针而不是文件内容。
i-节点中块指针的关系如图5-45所示。
图5-45 i-节点中块指针的关系
所有的块指针中,除了最后一个指针外,每个块指针指向一个块地址,而最后一个指针可能会指向一个或几个段。i-节点中记录的文件大小可以说明该文件占用了多少个段。块指针在UFS1中是一个32位的值,在UFS2中是一个64位的值。
UFS文件系统的i-节点中还会描述文件的修改时间、访问时间等时间信息。
这些时间信息是从1970年1月1日0时算起,并且使用格林威治标准时间,具体时间可以精确到纳秒,即十亿分之一秒。
i-节点表中的每一个i-节点都有一个编号。这个编号从0开始编排,但0号i-节点保留不用,1号i-节点用于描述坏块,2号i-节点用于描述根目录。
在每个柱面组的组描述符中都有一个i-节点位图,用来管理i-节点表中的i-节点使用和分配情况。如果要确定一个i-节点属于哪个柱面组,可以用当前i-节点号对每柱面组的i-节点数做取整运算得到,而每柱面组的i-节点数在超级块和柱面组描述符中都有记录。
UFS1的i-节点分析
UFS1的i-节点表起始地址由超级块10H~13H偏移处描述。这4个字节描述i-节点表相对于柱面组参考位置的偏移量。假设该值为32,那么每个柱面组中的i-节点表起始地址,就是以当前柱面组的参考位置为起点,向后偏移到32段。
需要注意的是,在UFS1中柱面组的参考位置是不同的,在每个柱面组中都会发生偏转。柱面组参考位置的具体偏转增量记录在超级块的18H~1BH偏移处。假设该值为128,则每个柱面组的参考位置以128个段为偏转增量,即0号柱面组的参考位置为0号段,1号柱面组的参考位置为128号段,以此类推。
在超级块的1CH~1FH偏移处还记录了柱面组偏转周期的计算掩码。通过这个掩码可以计算出柱面组参考位置的偏转周期。假设偏转周期为8,那么每经过8个柱面组,柱面组的参考位置就又回到0号段处。
UFS1的i-节点数记录在超级块的B8H~BBH偏移处。这4个字节描述了每个柱面组的i-节点数。UFS1的每个i-节点占用128个字节,具体结构见表5-35。
表5-35 UFS1的i-节点结构
i-节点的前两个字节用来描述“文件模式”。这两个字节按照其对应的16位二进制分成三组:第一组为0~8位,描述权限标志;第二组为9~11位,用来定义可执行文件和目录;第三组为12~15位,描述文件类型,下面详细说明:
权限标志
16位的文件模式中0~8位用来描述用户的权限。UNIX的用户被分成三类,即属主、同组用户、其他用户。属主是指i-节点中记录的用户ID的所有者;组用户以i-节点中的组ID进行区分;其他用户为除属主、同组用户以外的所有用户。用户的权限分为读、写和执行三种,权限标志中每个位代表的含义见表5-36。
表5-36 权限标志中每个位代表的含义
权限值(二进制) | 权限的含义 | 权限值(二进制) | 权限的含义 |
0000 0000 0000 0001 | 其他用户可执行 | 0000 0000 0010 0000 | 同组用户可读 |
0000 0000 0000 0010 | 其他用户可写 | 0000 0000 0100 0000 | 属主可执行 |
0000 0000 0000 0100 | 其他用户可读 | 0000 0000 1000 0000 | 属主可写 |
0000 0000 0000 1000 | 同组用户可执行 | 0000 0001 0000 0000 | 属主可读 |
0000 0000 0001 0000 | 同组用户可写 |
定义可执行文件和目录
16位的文件模式中9~11位用来定义可执行文件和目录。这三位设置的值不同:如果是可执行文件,其执行方式就会有所不同;如果是目录,则该目录中的文件会具有特定的属性。具体定义方式见表5-37。
表5-37 可执行文件和目录的定义方式
定义值(二进制) | 定义的含义 |
0000 0010 0000 0000 | 驻留位 |
0000 0100 0000 0000 | SGID(Set Group ID-设置组ID) |
0000 1000 0000 0000 | SUID(Set User ID-设置用户ID) |
如果一个可执行文件的“驻留位”设置为“1”,那么该程序关闭后其代码仍然驻留在内存中。
如果一个目录的“驻留位”设置为“1”,那么只有文件的属主才能删除该目录中的文件。
如果一个可执行文件的“SGID”位和“SUID”位设置为“1”,那么该文件的进程就根据组标识和用户标识来决定是否启动,而不由用户决定。
文件类型
16位的文件模式中12~15位用来定义文件类型。文件类型的各种值只能单独使用,不能同时将几个值组合起来使用。文件类型的取值及含义见表5-38。
表5-38 文件类型的取值及含义
类型值(二进制) | 类型的含义 | 类型值(二进制) | 类型的含义 |
0001 0000 0000 0000 | 先进先出(FIFO) | 1000 0000 0000 0000 | 正常文件 |
0010 0000 0000 0000 | 字符设备 | 1010 0000 0000 0000 | 动态链接 |
0100 0000 0000 0000 | 目录 | 1100 0000 0000 0000 | 套接字 |
0110 0000 0000 0000 | 块设备 |
“先进先出”也称为管道,用于两个进程间的数据传送。一个进程可以打开文件接收信息,但这些信息必须是由另一个进程写入的。在这个过程中数据存储在内存中而不是在磁盘上。
“字符设备”也称为裸设备,用于不需要一次读取一个数据块的设备,如键盘。也可以给块设备设置字符设备属性,但在不以块大小为读取和写入单位时会产生错误。i-节点通常会保存某些信息用以说明哪些块已经分配给记录设备标识符的文件。
“块设备”用于只能以块大小为单位进行读取操作的设备,如硬盘。从硬盘读取数据时,一次至少要读取512个字节,即1个扇区。如果程序要从块设备中读取少于1个扇区的数据,操作系统也需要读取1个扇区,然后只把需要的数据返回给程序。
“动态链接”是一种指向其他文件或目录的特殊文件,其“内容”是所指向的目标文件的内容。动态链接其实就是文件或目录的快捷方式。
“套接字”用于进程间的双向通信,如命名管道,这些数据并不写入磁盘。
下面以一个具体实例进行说明。在一个Sparc Solaris的切片中,文件系统的超级块描述了以下信息:
- 每个段的扇区数为2;
- i-节点表相对于柱面组参考位置的偏移量为32段;
- 柱面组参考位置的偏转增量为128段;
- 柱面组偏转周期为16;
- 每个柱面组包含的段数为53 040。
我们利用以上数据计算出6号柱面组中的i-节点表起始扇区号。
第1步 计算6号柱面组起始扇区号。
具体算法:每柱面组段数×每段扇区数×柱面组号=53040×2×6=636480
第2步 计算6号柱面组参考位置所在扇区。
具体算法:6号柱面组起始扇区号+柱面组参考位置的偏转增量×柱面组号×每段扇区数=636480+128×6×2=638016
第3步 计算6号柱面中的i-节点表起始扇区号。
具体算法:6号柱面组参考位置所在扇区号+柱面组描述符相对于柱面组参考位置的偏移量×每段扇区数=638016+32×2=638080
最终计算出6号柱面中的i-节点表起始于638 080号扇区。用WinHex跳转到638 080扇区,其部分内容如图5-46所示。
图5-46 638 080扇区的i-节点表
图5-46中i-节点表的第一个i-节点的具体信息及数值可以通过WinHex模板查看,如图5-47所示。
图5-47 WinHex模板显示的UFS1的i-节点参数(Big-Endian)
下面再看一下上例中第一个柱面组中的i-节点表,其部分内容如图5-48所示。
图5-48 第一个柱面组中的i-节点表
图5-48中的第一个i-节点(0号i-节点)是保留的;1号i-节点为坏块i-节点,目前没有使用;2号i-节点是根目录的i-节点。
UFS2的i-节点分析
UFS2的i-节点表起始地址由文件系统的超级块10H~13H偏移处描述。这4个字节描述i-节点表相对于柱面组参考位置的偏移量。假设该值为56,那么每个柱面组中的i-节点表起始地址,就是以当前柱面组的参考位置为起点,向后偏移到56段。
在UFS2文件系统中已经取消了柱面组的偏转增量和偏转周期,所以在计算每个柱面组中的i-节点表起始位置时就不用再考虑偏转增量的问题了。
UFS2的i-节点数记录在超级块的B8H~BBH偏移处。这4个字节描述了每个柱面组的i-节点数。
UFS2的每个i-节点占用256个字节,具体结构见表5-39。
表5-39 UFS2的i-节点结构
下面看一个UFS2的i-节点实例。这是一个Free BSD系统,其i-节点表中的一个i-节点内容如图5-49所示。
图5-49 UFS2的i-节点表中的一个i-节点
图5-49中UFS2的i-节点具体信息及数值可以通过WinHex的模板查看,如图5-50所示。
图5-50 WinHex模板显示的UFS2的i-节点参数(Little-Endian)
UFS2的i-节点中提到了一个“扩展属性”的概念。这是UFS2文件系统中新增加的一种概念,用以存储文件和目录的附加描述信息。扩展属性是一对命名值,通常有两种类型:用户命名空间和系统命名空间。任何可以访问文件内容的用户都可以访问用户命名空间属性,但只有拥有特权的用户才能够访问文件的系统命名空间属性。
在UFS2的i-节点中描述了扩展属性的大小,还描述了存储扩展属性的两个直接块指针。这两个直接块指针所指向的块中存放着由属性头和属性体组成的属性,它的长度可变。
扩展属性的数据结构见表5-40。
表5-40 扩展属性的数据结构
字节偏移 | 字段长度(字节) | 字段名和定义 |
0x00~0x03 | 4 | 记录长度 |
0x04~0x04 | 1 | 命名空间:01H表示用户命名空间;02H表示系统命名空间 |
0x05~0x05 | 1 | 内容填充长度 |
0x06~0x06 | 1 | 名字 |
0x07~(名字长度+7) | 变长 | 名字长度 |
名字结束~8字节边界 | 变长 | 填充至8字节的倍数 |