首页
社区
课程
招聘
[原创]Apple HFS+文件系统可视化分析
2024-6-15 11:52 1407

[原创]Apple HFS+文件系统可视化分析

2024-6-15 11:52
1407

起因

为了编译和调试XNU内核,需要修改安装镜像文件BaseSystem.img。然而,OpenCore对HFS+的支持存在问题,导致在修改镜像后无法读取BootKernelExtensions.kc文件。因此,需要深入了解HFS+文件系统,才能解决OpenCore的相关问题。

HFS+是一个较老的文件系统,目前macOS默认使用的是APFS,但由于HFS+结构简单且轻量,仍被保留在系统安装盘中。HFS+有官方开源项目,但由于其为内核模块且代码较为复杂,直接从源码分析并不容易,最好编写一些demo程序进行辅助理解。
注意:HFS+由于历史上支持PowerPC架构,使用的是大端序(Big-endian),文件名也是大端序的Unicode格式。
*HFS+是为机械硬盘设计的文件系统,APFS 是苹果为SSD和现代存储设备设计的文件系统,HFS+在械硬盘上还是不错的选择(磁道上顺序读写更快).

环境

  • macOS
  • 010 Editor + Drive Template
  • HFS源码
  • ChatGPT/GitHub Copilot/阿里云通义

磁盘镜像

  1. 下载macOS安装镜像BaseSystem.dmg转BaseSystem.img
  2. 使用磁盘管理创建一个dmg

GPT分区和HFS分区头结构

镜像是一个GPT分区, 比较简单,可以通过找到HFS+的FirstLBA来定位和解析HFS+分区。可以利用ChatGPT直接生成解析代码。

GPT分区

HFS+分区头:源码

以上结构先不需要详细了解,可以先看以下图表后续再理解。

BTree索引结构

需要理解的专业名词

  • Tree和BTree
  • 二分查找 (Binary Search)
  • 复合索引 (Composite Index)

结构简介

首先需要了解BTree的索引结构,所有的文件和目录查找都通过BTree进行。BTree的高度是动态调整的,文件越多,BTree树越高。同一层高度的节点(Node)也是相互前后链接的。

BTree结构1
BTree结构2

文件检索

检索是通过文件和目录的父层ID和文件名进行的(复合索引[parentId, Name])。每个Index Node都有子层的最开始的目录ID和最小的文件名(子层可以是末端叶节点(Leaf),也可以是子Index)。目录ID和文件名都按从小到大的顺序存放。

文件检索

如果一个Index Node下仍然是另一个Index Node,它包含的是子Index的最小父目录ID和最小文件名。对于较大的目录,子Index可能有多个相同的父目录ID,所以需要文件名且按顺序排列。通过从根节点到叶节点的逐层二分查找,最终找到目标文件。

二分查找

Node结构

Index和Leaf Node的结构是统一的,HFS+尽量复用和统一结构。Record的结构由Descriptor中的Kind确定,每个Record的起始位置由索引决定(注意:由于文件名长度不一,每个Record的大小不固定。如果文件名固定最大长度为255,会浪费较多空间)。

Node结构

Index和Leaf Node使用时不是先用满一个Node再使用下一个,而是先使用大概20%的容量,以便在添加和删除记录时尽量不需要修改多个Node。本文章只大概介绍结构,修改的逻辑涉及更深的算法,仅略微带过。

Node使用

文件结构

每个文件都有一个ForkData,每个ForkData包含8个Extent。每个Extent指向具体的块(startBlock)和块的数量(blockCount)。如果分区碎片化严重,超过8个Extent时需要在Extents BTree中检索相应的ForkData。

文件结构

文件系统的碎片化问题是所有文件系统都无法避免的,HFS+碎片化严重时需要更多的扩展ForkData,导致读取文件效率下降。HFS+的设计理念似乎是优先使用前面的空闲块,这个设计不太合理。欢迎有了解的朋友交流讨论。

碎片化问题

OpenCore OpenHfsPlus模块问题

要解决最开始提到的OpenCore的OpenHfsPlus模块的问题,实际并不是问题,而是作者没有实现读取超过默认8个Extent(作者称其为分片fragments)。作者在注释中提到未实现此功能。相关代码:

1
2
3
4
5
6
7
8
9
10
11
static fsw_status_t
fsw_hfsplus_get_ext(struct fsw_hfsplus_volume *v, struct fsw_hfsplus_dnode *d,
                    struct fsw_extent *e)
{
    // ...
 
    // FIXME: more than 8 fragments not yet supported!
    FSW_MSG_ASSERT((FSW_MSGSTR("FswHfsPlus: get_ext: got_here\n")));
 
    return FSW_UNSUPPORTED;
}

深入了解

要全面了解HFS+,需要完整阅读HFS源码,并理解XNU系统,因为HFS+只是内核驱动的一部分,需要依赖内核的缓存系统、线程锁系统等。HFS+的管理逻辑还涉及插入删除时索引的重建、BTree高度调整等,以及确保多线程下文件ID的唯一性等。
~
黑苹果, XNU内核交流可QQ: 3=1=0=4=1=9=0=6=2 (倒序)
~


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2024-6-17 13:55 被alice编辑 ,原因:
收藏
免费 0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回