编录文件是HFS+文件系统中非常重要的一个元文件,该文件中包含着许多信息,HFS+文件系统利用这些信息维系着宗卷中的文件和目录间的层次关系。
编录文件采用B−树结构组织数据,文件中包括头节点、索引节点、叶节点。如果B−树中节点数很多,也会用到位图节点。
编录文件的基本特性如下:
①编录文件的起始地址,也就是其第一个盘区,由卷头中的“编录文件信息”描述,这也是文件的头节点所在位置。
②从编录文件的头节点中可以得到其B−树根节点的节点号,通过根节点又能找到孩子节点(索引节点或叶节点),最后访问到需要的文件。
③编录文件中记录的每个文件和文件夹都被分配一个编录节点ID,即CNID。对于文件夹来说,其CNID被称为“文件夹ID”或者“目录ID”;而对于文件,其CNID被称为“文件ID”。
④对于任何一个文件或文件夹,其父ID就是指它的上一级文件夹的CNID,也即文件夹ID,所以通过CNID就能够找到文件或文件夹的上级目录了。
⑤编录文件的节点大小被定义了下限,其最小取值为4096字节。
CNID的取值是按照阿拉伯数字顺序排列的,从1开始取值,0号CNID不被使用,其中前16个CNID被Apple电脑保留下来有专门的用途,其标准的分配情况见表6-27。
表6-27 保留CNID的标准分配
CNID值(十进制) | 定义 | CNID值(十进制) | 定义 |
---|---|---|---|
1 | 根目录的父ID | 7 | 启动文件ID(HFS+文件系统引入) |
2 | 根目录ID | 8 | 属性文件ID(HFS+文件系统引入) |
3 | 盘区溢出文件ID | 14 | 修复编录文件ID(在fsck_hfs重建编录文件时临时使用) |
4 | 编录文件ID | 15 | 伪盘区文件ID(在交换文件运行时临时使用) |
5 | 坏块文件ID | 16 | 用户文件第一可用ID |
6 | 分配文件ID(HFS+文件系统引入) |
从表6-27可以看出,16号CNID是提供给用户使用的第一个CNID。如果一个HFS+宗卷是新创建的,那么这个宗卷中没有任何用户文件,这时卷头中的“下一目录ID”参数的值就是16,也就是分配给用户使用的第一个CNID。
在2000年1月18日之前的HFS+文件系统中,要求卷头中“下一目录ID”参数的值大于宗卷中已被使用的最大CNID值,以便于系统利用“下一目录ID”的值给新创建的文件分配CNID。
然而,CNID的这种分配方式可能会给宗卷带来一个麻烦,在文件或目录创建频率很高的情况下(比如服务器中),CNID值可能会被用尽。所以Apple做了改进,现在的HFS+文件系统中的CNID可以循环再利用,只要在卷头中将“属性”参数的12位进行设置,CNID就可以循环再利用,这时就不再要求卷头中“下一目录ID”参数的值大于宗卷中已被使用的最大CNID值。
当卷头中“属性”参数的12位进行设置后,“下一目录ID”的值依然起作用,它作为创建新文件或目录时分配CNID的一个指示,但系统在分配CNID时需要核实待分配的CNID不在使用中,如果发现该CNID在使用中,系统会增大“下一目录ID”的值,直到发现未用的CNID。
如果“下一目录ID”的值溢出成为0,“用户文件第一可用ID”必须被设置,并且要把“下一目录ID”设置为“用户文件第一可用ID”的值,以避免系统使用保留的CNID值。
编录文件采用B−树组织数据,所以它继承了B−树所定义的基本结构,但要想掌握编录文件管理数据的方法,除了B−树所定义的基本结构以外,还需要理解两大类结构:
①用于索引节点和叶节点中的关键字结构;
②叶节点中数据记录的结构,包括文件记录的数据结构、文件夹记录的数据结构、链接记录的数据结构。
本节将一一揭开这些结构的谜底。
在6.3.7节的叶节点分析中,介绍了叶节点的数据记录中包含关键字长度、关键字、关键字的数据三部分结构。本节将重点讲解数据记录的第二部分,即关键字的结构。
关键字的长度最大为516字节,最小为6字节,其实际字节数由它前面的参数“关键字长度”定义。关键字中主要包含其父目录的CNID及其节点名两部分:在文件夹记录中,节点名就是文件夹名;在文件记录中,节点名就是文件名。关键字的具体结构见表6-28。
表6-28 关键字的结构
字节偏移(相对偏移) | 字段长度(字节) | 字段名和定义 |
---|---|---|
0x00~0x03 | 4 | 父目录ID |
0x04~0x05 | 2 | 节点名的字符数(N) |
0x05~ | 2N | 节点名 |
关键字中的节点名部分用Unicode字符集,每个字符占用两个字节。
来看一个具体的实例,如图6-40所示。
图6-40中的内容是一个叶节点前部的截图,其节点描述符08H偏移处的值为“FFH”,换算为十进制等于“−1”,可以说明它是叶节点。该叶节点的第一个数据记录起始于0EH偏移处,数据记录中的前两个字节描述关键字的长度,当前值为“0012H”,说明关键字占用12H个字节,所以随后的12H个字节就是关键字了。
图6-40中关键字的结构及实际数值见表6-29。
表6-29 图6-40中关键字的结构及数值
字节偏移(相对偏移) | 字段长度(字节) | 字段名和定义 | 当前值 |
---|---|---|---|
0x00~0x03 | 4 | 父目录ID | 1 |
0x04~0x05 | 2 | 节点名的字符数(N) | 6(说明文件名占12个字节) |
0x05~ | 2N | 节点名 | Mac OS |
叶节点的数据记录中,跟在关键字之后的就是关键字的数据了。编录文件中的关键字数据可以分为四种类型,它们是文件夹数据、文件数据、文件夹链接数据、文件链接数据。按照Apple官方给出的定义,它们分别被称为文件夹记录、文件记录、文件夹链接记录、文件链接记录。
这四种类型的记录在关键字的数据中会用两个字节进行定义,定义的方式见表6-30。
表6-30 记录类型的定义
类型值 | 记录类型 | 类型值 | 记录类型 |
---|---|---|---|
0x0001 | 文件夹记录 | 0x0003 | 文件夹链接记录 |
0x0002 | 文件记录 | 0x0004 | 文件链接记录 |
首先分析文件夹记录的结构。
文件夹记录的作用是在编录文件中描述文件夹的信息,它的数据部分占用88个字节,具体结构见表6-31。
表6-31 文件夹记录的结构
下面对各参数进一步解释:
①0x00~0x01:记录类型。用以说明数据记录的类型,对于文件夹记录,此值为“0001H”。
②0x02~0x03:标志。此处包含有关文件夹的标志位,当前并没有给文件夹记录定义标志位,所以系统必须保留此位。
③0x04~0x07:文件夹中的文件及目录数。用来表示该文件夹中包含的文件和文件夹的数量,也就是所有父目录ID号等于这个文件夹ID号的文件和文件夹的数量。
④0x08~0x0B:文件夹的CNID。描述当前文件夹的CNID。
文件夹记录的关键字中所描述的CNID是它的父目录的CNID,而并不是它自身的CNID,此处记录的才是文件夹自身的CNID。
⑤0x0C~0x0F:文件夹创建时间。此处记录文件夹的创建时间。
这里的时间使用GMT(格林威治时间)格式,而不是像卷头中那样使用本地时间。
⑥0x10~013:文件夹修改时间。此处记录文件夹的内容最后被修改的时间和日期,包括最后一次在文件夹内新建文件或文件夹、删除文件或文件夹、从其他位置移动文件或文件夹至本文件夹内、将文件或文件夹从本文件夹内移动至文件夹外的其他位置等操作的时间和日期。这里也使用GMT格式。
⑦0x14~0x17:属性修改时间。该参数是指数据记录最后的变化时间,但大部分系统会将此处视为保留。
⑧0x18~0x1B:最后访问时间。文件夹的内容最后被访问的时间和日期,对于新建的文件夹,该时间设置为0。
⑨0x1C~0x1F:最后备份时间。用以记录最后一次备份该文件夹中数据的时间。
⑩0x20~0x2F:文件夹许可权限。该参数内包含文件夹的许可权限,类似于POSIX中的定义,但传统的Mac OS并不使用该参数,所以传统的Mac OS创建的文件夹此处设置为0。
从Mac OS X系统开始使用该权限,并被命名为HFS+的BSD信息。该权限的定义见表6-32。
表6-32 文件夹(或文件)权限的定义
⑪0x30~0x3F:用户信息。此处包含系统引导(Finder)相关的信息,但并不是HFS+文件系统技术规范中的组成部分。
⑫0x40~0x4F:系统引导信息(FinderInfo)。此处也包含系统引导(Finder)相关的信息,同样不是HFS+文件系统技术规范中的组成部分。
⑬0x50~0x53:文档命名编码。这是一个关于文件夹名称由来的文本编码线索。
⑭0x54~0x57:保留。
下面看一个文件夹记录的实例,如图6-41所示。
图6-41中“关键字的数据”部分就是一个文件夹记录结构,这一点从该记录中前两个字节的“记录类型”值为“01H”就可以看出。
该文件夹记录的结构参数及其数值如图6-42所示。
文件记录的作用是在编录文件中描述文件的信息,它的数据部分占用248个字节,具体结构见表6-33。
表6-33 文件记录的结构
下面对各参数进一步解释:
①0x00~0x01:记录类型。用以说明数据记录的类型。对于文件记录,此值为“0002H”。
②0x02~0x03:标志。此处包含有关文件的标志位。此参数定义了两种标志,具体见表6-34。
③0x04~0x07:保留。这四个字节保留未用。
④0x08~0x0B:文件的CNID。描述当前文件的CNID。
表6-34 文件标志位的定义
属性位 | 属性定义 | 含义 |
---|---|---|
0位 | 文件锁 | 如果该位被设置,所有分支都不能被扩充、删减、写入,只能够打开读取,但编录信息可以改变,如用户信息和系统引导信息(FinderInfo) |
1位 | 存在链接 | 该位被设置表示文件具有链接记录,因为HFS+文件系统中的文件都有链接记录,所以这一位必须设置 |
2~15位 | 未定义 | 保留 |
⑤0x0C~0x0F:文件创建时间。此处记录文件的创建时间,使用GMT(格林威治时间)格式。
⑥0x10~013:文件修改时间。此处记录文件的内容最后被修改的时间和日期,使用GMT格式。
⑦0x14~0x17:属性修改时间。该参数是指数据记录最后的变化时间,但大部分系统会将此处视为保留。
⑧0x18~0x1B:最后访问时间。文件的内容最后被访问的时间和日期。对于新建的文件,该时间设置为0。
⑨0x1C~0x1F:最后备份时间。用以记录最后一次备份该文件的时间。
⑩0x20~0x2F:文件许可。该参数内包含文件的许可权限,类似于POSIX中的定义,但传统的Mac OS并不使用该参数,所以传统的Mac OS创建的文件此处设置为0。
⑪0x30~0x3F:用户信息。此处包含系统引导(Finder)相关的信息,但并不是HFS+文件系统技术规范中的组成部分。
⑫0x40~0x4F:系统引导信息(FinderInfo)。此处也包含系统引导(Finder)相关的信息,同样不是HFS+文件系统技术规范中的组成部分。
⑬0x50~0x53:文档命名编码。这是一个关于文件名称由来的文本编码线索。
⑭0x54~0x57:保留。此处两个字节保留不用。
⑮0x58~0xA7:数据分支信息。此处用80个字节描述数据分支的大小及地址,具体结构见表6-35。
表6-35 数据分支的结构
⑯0xA8~0xF7:资源分支信息。此处用80个字节描述资源分支的大小及地址,具体结构见表6-36。
表6-36 资源分支的结构
下面看一个文件记录的实例,如图6-43所示。
图6-43中“关键字的数据”部分就是一个文件记录结构,这一点从该记录中前两个字节的“记录类型”值为“02H”就可以看出。
该文件记录的结构参数及其数值如图6-44所示。
该文件记录的数据分支参数及其数值如图6-45所示。
该文件记录的资源分支参数及其数值如图6-46所示。
链接记录分为文件夹链接记录和文件链接记录。为节省篇幅我们将统一分析,就不将它们二者分别讲解了。
为了能够将宗卷中的文件夹及文件的上下关系串联起来,HFS+在叶节点中采用了链接记录的数据结构。链接记录的关键字结构跟文件夹记录及文件记录的关键字结构是有区别的。下面首先分析链接记录的关键字结构。
注意:链接记录的关键字中记录的CNID是它所描述的文件夹或文件的CNID,而不是这个文件夹或文件的父目录ID,弄明白这一点很重要。
链接记录的关键字总是占用6个字节,其结构见表6-37。
表6-37 链接记录的关键字结构
字节偏移(相对偏移) | 字段长度(字节) | 字段名和定义 |
---|---|---|
0x00~0x03 | 4 | 当前文件夹(或文件)的CNID |
0x04~0x05 | 2 | 节点名的字符数(始终为0) |
下面用一个实例进行分析,如图6-47所示。
从“关键字长度”参数的数值为“0006H”可以知道该关键字为6个字节,这6个字节的结构及数值见表6-38。
表6-38 图6-47中关键字的结构及数值
字节偏移(相对偏移) | 字段长度(字节) | 字段名和定义 | 实际值 |
---|---|---|---|
0x00~0x03 | 4 | 当前文件夹(或文件)的CNID | 17,说明当前描述的是17号CNID的文件夹或文件 |
0x04~0x05 | 2 | 节点名的字符数 | 0(始终为0) |
关键字后面紧跟着就是链接记录关键字的数据了,其中包含节点名,所以它不是固定长度,而是随着节点名长度的变化而变化,其结构见表6-39。
表6-39 链接记录的结构
字节偏移(相对偏移) | 字段长度(字节) | 字段名和定义 |
---|---|---|
0x00~0x01 | 2 | 记录类型,0003H为文件夹链接记录;0004H为文件链接记录 |
0x02~0x03 | 2 | 保留 |
0x04~0x07 | 4 | 父目录ID |
0x08~0x09 | 2 | 节点名字符数(N) |
0x0A~ | 2N | 节点名 |
下面看一个链接记录的实例,如图6-48所示。
图6-48中“关键字的数据”部分就是一个链接记录结构。这一点从该记录中前两个字节的“记录类型”值为“03H”就可以看出,它是一个文件夹链接记录。
该链接记录的结构参数及其数值如图6-49所示。