APFS 文件系统探究

本文的创作初衷是因为我发现从底层详解 APFS 的资料很少,所以自己来进行了一些探究和整理。

一点说明

如果你在看 APFS 的文档或者其他内容,不要把高层级的分区理解成 Windows 中的分区。因为 APFS 里卷(Volume)才是显示在“访达”中的,在硬盘和卷之间还有一个容器的概念,一个容器可以包含多个卷,这不好和 Windows 中的分区概念对应。

APFS大致结构

APFS 内部结构大致如下:

APFS大致结构

上图只有一个卷,然后描述了这个卷中的各部分信息。其中“Storage for objects and file data”中的“objects”就包含了我们在访达中看到的那个存储硬盘,也就是一个卷。

“GUID partition table”的缩写便是很多人在 Windows 上熟知的 GPT(不是那个聊天机器人),而 GPT 分区则是 EFI 技术的一部分(EFI 又名为 UEFI,是 Intel 发明的)。

APFS 的每个容器是按照顺序排列在硬盘里的,并不会有空隙,这与 Windows 的 GPT 分区不一样。

APFS 的空闲空间是在各个卷之间共同分享的,所以扩展起来很容易

这也是为什么 Windows 上你只能扩展或调整最后一个分区的大小,而不能调整前面的盘(APFS 的空闲空间是在各个卷之间共同分享的,所以扩展起来很容易,如下图)。以及为什么 macOS 上新建 APFS 分区的时候需要很久很久(因为要把其他分区的文件挪到合适的地方)。

但系统是怎么知道硬盘上有这个容器的呢?顺序读取的话,第一个容器按顺序读下去就行了,但是第二个呢?

首先,系统不是通过顺序读取来发现容器的。而这些工作是硬盘最开始的 GUID partition table 的任务了,这部分会包含各个分区的起始和终止地址,用的时候跳转就行了,是一种目录式的结构。如下图(源自官方标准《GUID Partition Table (GPT) Disk Layout》):
https://uefi.org/specs/UEFI/2.10/05_GUID_Partition_Table_Format.html

可以看到通过主要分区表或者备用分区表划分分区以及进行跳转。

如果你查看 APFS 格式硬盘的十六进制的话,就可以看到如下情况(需要注意“GPT Header”部分是从200那行开始的):

请添加图片描述

可以看到内部开头的结构与其他 UEFI 格式的差不多。

Protective MBR

APFS 与其他一些 GPT 分区的文件系统不同的是:不论是不是启动盘,都会有 Protective MBR 部分。

Protective MBR 必须是使用 GPT 分区的硬盘上第一个逻辑块。这个分区的存在使得计算机认为这个硬盘是可以使用的,并且已被使用,就不会弹出弹窗问你需不需要进行分区、格式化等操作,EFI 本身是不会使用这个块的。

Protective MBR 部分如下:
请添加图片描述

各部分内容含义如下(偏移量是从这部分开头开始算,而且也是十六进制的):

部分字节偏移量字节长度内容
启动码0440EFI不会使用这部分,440的十六进制就是1b8,所以可以看到上图中1b8和之前的部分全部是00
唯一MBR硬盘签名4404没有被使用,设置为0
未知4442没有被使用,设置为0
分区记录44616*4四个MBR分区记录的数组。MBR最多就 4 个分区。
签名5102设置为0xAA55,也就是图中的1f0那行最后的55 aa
保留块512逻辑块大小-512逻辑块的剩余保留部分,设置为0

如果你对上面左侧的序号有疑问,需要记住这是十六进制的。比如说,最后的512的十六进制便是200

GPT Header

GPT Header 是 UEFI 技术和 GPT 分区的核心部分,这部分存储了很多信息。GPT Header 各部分如下:

请添加图片描述

各部分内容含义如下(偏移量是从这部分开头开始算):

部分字节偏移量字节长度内容
签名08这部分是 ASCII 格式的字符串“EFI PART”,用 64 位编码,也就是上图中的45 46 49 20 50 41 52 54
修正版本84GPT Header 的修正版本数,这个版本不等于 UEFI 指定版本。上文中的00 00 01 00表示是版本 1.0
Header 尺寸124GPT Header 的尺寸,单位是字节。这部分必须大于等于 92,小于等于逻辑块大小。上面的5C 00 00 00表示 92 个字节,也就是最小尺寸。上图只有 60 个字节,是因为省略了最后的几个空行
Header的CRC32164GPT Header 结构的 CRC32 校验和。先将这个值设置为 0,然后计算 GPT Header 结构的 32 位 CRC32 校验和,这里的校验和是15 51 0f ff
保留部分204这部分必须全部为 0
MyLBA部分248这个 LBA(逻辑块地址)包含数据结构,验证 GPT 的时候会检查 MyLBA 实例指向的 GUID Partition Table 中的 LBA,上图中为01 00 00 00 00 00 00 00
AlternateLBA328备用 GPT Header 的 LBA 地址,上图中为ff ff bf 46 07 00 00 00
第一个可使用LBA408GUID Partition Entry描述的一个分区的第一个被使用的可使用逻辑块,上图中为22 00 00 00 00 00 00 00
最后一个可使用488GUID Partition Entry描述的一个分区的最后一个被使用的可使用逻辑块,上图中为de ff bf 46 07 00 00 00
硬盘GUID5616标识硬盘的 GUID,上图中为84 ec 00 4a 8e 8c fd 47 8a 78 25 48 bf a4 90 99
分区实例 LBA728GUID分区实例数组的开始 LBA,上图中为02 00 00 00 00 00 00 00
分区实例的数量804GUID分区实例数组中分区实例的数量,上图中为80 00 00 00,也就是 8 个
分区实例的尺寸844GUID分区实例数组中GUID分区实例结构体的尺寸,这部分应该设置成128 x 2n的大小,n是大于等于0的整数,这部分一般是 128、256 等,但是早期的版本允许8的任意倍数。上图中的80 00 00 00实际上就是十六进制的80,也就是 128 个字节
分区实例数组的CRC32884GUID分区实例数组的 CRC32
保留92剩下所有保留块,全部为 0

GPT Partition Entry Array

GPT 分区实例数组(GPT Partition Entry Array)包含一个数组,这个数组存储了 GPT 分区实例。依旧先说明每个部分是什么,下面是 GPT 分区实例数组中的第一个实例:

请添加图片描述

部分字节偏移量字节长度内容
分区类型 GUID016定义分区目标和类型的唯一ID。如果分区没有被使用,那么这部分为 0。上图中为:28 73 2a c1 1f f8 d2 11 ba 4b 00 a0 c9 3e c9 3b,关于这部分的每个比特背后的含义后面细说
唯一分区 GUID1616每个分区实例唯一的 GUID。每个分区被创建时都会有这样一个唯一的 GUID,这个 GUID 也必须在 GPT 分区实例创建时分配值。上图中分配的为f8 56 1c 99 8d 6f 9e 4f bb fa 01 ca 52 57 cc 05
起始 LBA328这个实例中定义的分区起始 LBA
终点 LBA408这个实例中定义的分区终点 LBA
属性488这些属性位全部被 UEFI 保留,所以这里全部都是00 00 00 00 00 00 00 00
分区名称5672一个包含人类可读名称的无终止符字符。由于这是一个 EFI 分区,所以显示的是EFI System Partition
保留区域128之前设置的大小 ~ 128这部分必须为 0

根据操作系统的不同、分区的不同,分区类型 GUID 的值也是不同的。比如说上面的这个 EFI 系统分区的 GUID 值就是28 73 2a c1 1f f8 d2 11 ba 4b 00 a0 c9 3e c9 3b。有时你在其他资料里会看到是这样的:C12A7328-F81F-11D2-BA4B-00A0C93EC93B,这里每个-分隔开每个部分,加之上图中的值为小端数,你可以对应看看是一样的。

而 APFS 分区的分区类型 GUID 是ef 57 34 7c 00 00 aa 11 aa 11 00 30 65 43 ec ac,或者说7C3457EF-0000-11AA-AA11-00306543ECAC

上面“属性”中每部分的含义如下:

名称含义
0请求分区如果设置了这一位,那么必须有这个分区才能使平台运行,删除或修改这个分区的内容可能会导致平台功能丢失、无法启动或运行。所以除非操作系统、软件或固件能识别这个分区,否则不应该删除或修改这个分区。
1没有块IO传输协议如果设置了此位,那么固件不能为此分区生成EFI_BLOCK_IO_PROTOCOL部分,不设置这部分,那么就不会在 UEFI 中为该分区创建文件系统的映射
2传统 BIOS 可启动这位留给具有传统 PC-AT BIOS 固件的系统实现通知特定受限的、特殊目标的软件运行在一个可用 GPT 分区启动的系统上
3~47未定义,必须为 0,保留给未来的 UEFI 规范的扩展
48~63保留给 GUID 特定用途使用。这些位的使用根据分区类型 GUID 而设定。如果修改了 0~47 位中的任何一位,那么都必须保留这些位

可以看到,在 GPT 分区实例数组中的每个实例中,都标出了起始和终止点,于是就通过这些部分进行跳转和获取。

参考资料和扩展阅读

如果你想尝试查看上面的内容,那么可以按照我的这篇博客进行操作:《如何在Mac终端上,用十六进制查看某个硬盘(使用dd和hexdump,所以其他系统也可以使用这个方法)》

关于 APFS 格式的实现细节可以参阅苹果对这篇文档:《Apple File System Reference》(“Apple File System”就是 APFS 的全称)。

UEFI 官方文档为:《GUID Partition Table (GPT) Disk Layout》

《数据恢复技术深度揭秘(第二版)》刘伟编著。

希望能帮到有需要的人~

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果一个Mac系统只有APFS分区,那么重装Mac系统需要采取以下步骤: 1. 备份数据:在重装系统之前,务必先备份重要的数据。这可以通过将文件复制到外部存储设备、使用Time Machine备份程序或通过iCloud等云存储服务进行备份。 2. 创建引导盘:创建一个可引导的安装介质,用于重装Mac系统。可以通过在Mac App Store下载最新版本的macOS(如果之前下载过),然后使用Disk Utility工具将其制作成可引导的USB驱动器或光盘。 3. 重新启动Mac:将引导盘插入您的Mac,然后重新启动系统。在启动过程中,按住"Option"键,直到出现启动菜单。 4. 选择安装介质:在启动菜单中,选择您创建的可引导安装介质。系统将加载安装界面。 5. 格式化APFS分区:在安装界面中,选择"磁盘工具(Disk Utility)",然后找到您的APFS分区。点击"抹掉(Erase)"选项,选择APFS格式,并为分区命名。请注意确保已备份重要数据,因为此操作将清除分区。 6. 安装系统:关闭磁盘工具,返回安装界面,并选择"安装 macOS"。然后按照屏幕上的指示进行操作,选择安装目标为刚刚格式化的APFS分区,并完成安装过程。 7. 恢复数据:安装完成后,您可以选择从之前备份的数据中恢复个人文件和设置。可以通过迁移助理、Time Machine恢复、手动复制文件等方式进行恢复。 总之,通过备份数据,制作引导盘,格式化分区,安装系统和恢复数据这些步骤,可以重新安装只有APFS分区的Mac系统。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值