APFS 文件系统探究

2023-10-22 13:50
文章标签 文件系统 探究 apfs

本文主要是介绍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》。

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

希望能帮到有需要的人~

这篇关于APFS 文件系统探究的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/261856

相关文章

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

使用jetty和mongodb做个简易文件系统

使用jetty和mongodb做个简易文件系统 - ciaos 时间 2014-03-09 21:21:00   博客园-所有随笔区 原文   http://www.cnblogs.com/ciaos/p/3590662.html 主题  MongoDB  Jetty  文件系统 依赖库: 1,jetty(提供http方式接口) 2,mongodb的java驱动(访问mo

Kubernetes集群安装、配置glusterfs文件系统

环境介绍: 3台Centos 7.4系统节点,已经部署好Kubernetes,同时复用这3台机器作为gluster存储节点: hostIPK8s roleg1-nasp12.12.10.11master + nodeg3-nasp12.12.10.13nodeg4-nasp12.12.10.14node 安装、配置glusterfs: 在物理主机上采用yum安装的方式,步骤如下: 1

Ubuntu构建只读文件系统

本文介绍Ubuntu构建只读文件系统。 嵌入式系统使用过程中,有时会涉及到非法关机(比如直接关机,或意外断电),这可能造成文件系统损坏,为了提高系统的可靠性,通常将根文件系统设置为只读,将其他需要读写的数据放置在另外开辟的一个磁盘分区,本文针对嵌入式系统常用的Ubuntu操作系统构建只读文件系统。 1.基本原理 1)OverlayFS简介 OverlayFS(Overlay File Sy

探究零工市场小程序如何改变传统兼职模式

近年来,零工市场小程序正逐渐改变传统的兼职模式,为求职者和雇主提供了一个更为高效、便捷的平台。本文将深入探讨零工市场小程序如何影响传统兼职模式,以及它带来的优势和挑战。 一、背景与挑战 传统的兼职市场往往存在信息不对称的问题,求职者难以快速找到合适的工作,而雇主也难以找到匹配的劳动力。此外,兼职工作的不稳定性和安全性也是求职者关注的焦点。零工市场小程序的兴起,旨在解决这些问题,通过数字化手

apk中签名文件探究(*.SF, *.MF,*.RSA)

文章来源: 作者:嘟嘟小灰 链接:https://www.jianshu.com/p/e07da93acf98 来源:简书 1、取一个apk,然后进行不同签名,生成1.apk、2.apk,并提取META-INF里面的文件进行比对 def calc_sha1(data):sha1obj = hashlib.sha1()if not isinstance(data, (bytear

TRIZ在充电桩安全中的应用探究

在当今电动汽车日益普及的时代,充电桩的安全问题至关重要。TRIZ(发明问题解决理论)可以为提升充电桩的安全性提供强大助力。具体步骤如深圳天行健企业管理咨询公司下文所述: 一、充电桩安全面临的问题 1.电气安全风险:包括过压、过流、短路等电气故障,可能导致设备损坏、火灾甚至人员伤亡。 2.机械安全风险:如充电桩外壳的坚固程度、充电插头的插拔可靠性等,可能影响用户的使用安全。 3.环境安全

Flink on YARN模式下TaskManager的内存分配探究

点击上方蓝色字体,选择“设为星标” 回复”资源“获取更多资源 我们使用如下的参数提交了Flink on YARN作业(per-job模式)。 /opt/flink-1.9.0/bin/flink run \--detached \--jobmanager yarn-cluster \--yarnname "x.y.z" \--yarnjobManagerMemory 2048 \--

BBR 与 AIMD 共存公平性探究

一个古已有之的结论: deep buffer 场景,bbr 相对 reno/cubic 等 aimd 有优势,侵占性强;shallow buffer 场景,aimd 有优势,bbr 带宽被挤占。 本文用实例分析 why 并给出 how。 先看 deep buffer 场景 bbr 单挑 aimd 双流的效果,下图是标准 bbr,被虐成经理: 下图是用 max(bw/delay) 替代 ma