APFS 文件系统探究

2023-11-16

本文的创作初衷是因为我发现从底层详解 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 部分如下:
请添加图片描述

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

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

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

GPT Header

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

请添加图片描述

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

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

GPT Partition Entry Array

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

请添加图片描述

部分 字节偏移量 字节长度 内容
分区类型 GUID 0 16 定义分区目标和类型的唯一ID。如果分区没有被使用,那么这部分为 0。上图中为:28 73 2a c1 1f f8 d2 11 ba 4b 00 a0 c9 3e c9 3b,关于这部分的每个比特背后的含义后面细说
唯一分区 GUID 16 16 每个分区实例唯一的 GUID。每个分区被创建时都会有这样一个唯一的 GUID,这个 GUID 也必须在 GPT 分区实例创建时分配值。上图中分配的为f8 56 1c 99 8d 6f 9e 4f bb fa 01 ca 52 57 cc 05
起始 LBA 32 8 这个实例中定义的分区起始 LBA
终点 LBA 40 8 这个实例中定义的分区终点 LBA
属性 48 8 这些属性位全部被 UEFI 保留,所以这里全部都是00 00 00 00 00 00 00 00
分区名称 56 72 一个包含人类可读名称的无终止符字符。由于这是一个 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》

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

希望能帮到有需要的人~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

APFS 文件系统探究 的相关文章

  • npm install 不起作用,抛出错误

    我正在尝试在 nodejs 中安装 yo 和其他一些软件包 但是我不断收到错误 我是节点新手 所以我有点迷失 我运行的是 Mac OS X 10 10 3 我正在使用的命令是 sudo npm install global yo 这样做会给
  • 如何在 Mac 上安装 Clang 9?

    这是我 Mac 上的内容 clang version Apple LLVM version 10 0 0 clang 1000 10 44 4 Target x86 64 apple darwin17 7 0 Thread model po
  • 如何从 Mac OS X 中完全删除 Eclipse(包括设置和插件)?

    我的 Eclipse 与 GAE 损坏并且工作异常 所以我从Application文件夹中删除了Eclipse 但是留下了垃圾 我重新下载了全新的 eclipse 但它以旧设置运行 并且损坏的 GAE 结构仍然存在 如何从 Mac 上完全删
  • 为具有多个目标和不同平台的项目编写 Podfile

    我正在准备一个支持 OS X 和 iOS 的 Pod 我的 pod 有一些自己的依赖项 这些依赖项在 podspec 文件中定义 因此我使用 Podfile 来管理我用来开发 pod 和运行测试的项目的依赖项 我正在使用 CocoaPods
  • 从 Java 执行 .app 文件夹?

    有没有一种合理的方法可以直接从 Java 执行 app 目录 而不是深入查找二进制文件 我有一个带有一些首选项的应用程序 其中包括用于打开各种内容的外部程序 如果在 OSX 上用户可以只选择 app 文件夹 那就太好了 我可以查找 app
  • 无法使 csshX 在 Mac OS Big Sur 上运行

    csshX不适用于 Mac Big Sur 未实现 POSIX tmpnam 在 System Library Perl 5 28 darwin thread multi 2level POSIX pm 第 185 行使用 File Tem
  • 在 MacOS 终端上运行 ffmpeg [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我对 MacOS 相当陌生 我发现使用终端来获取信息并不容易ffmpeg和我在 Window 上一样正常运行 我有 ffmpeg 二进制文件ffmpe
  • 如何在 swiftUI (macOS) 中检测按键按下和释放

    除了标题之外没什么可说的 我希望能够在按下按键和释放按键时 在 macOS 上 在 swiftUI 视图中执行操作 在 swiftUI 中是否有任何好的方法可以做到这一点 如果没有 有什么解决方法吗 不幸的是 键盘事件处理是其中一个令人痛苦
  • 在 XCode 7.0.1 中设置 VTK 6.1

    所以 我遇到了问题VTK 可视化工具包 http www vtk org在 Mac OSX 上工作 特别是让它在XCode https developer apple com xcode 我让它工作并将在下面发布这个问题的答案 截至 201
  • .profile 无法从 Mac 终端运行

    我有一个 profile 文件 我正在终端中读取并使用别名 但在某些时候 别名由于没有明确的原因而停止工作 其他命令仍在工作 为了快速修复 我删除了 rm 并在用户目录中重新创建了 profile 文件 我可以看到 至少在该目录中没有 ba
  • OSX 上的 locale.getlocale() 问题

    我需要获取系统区域设置来执行许多操作 最终我想使用 gettext 翻译我的应用程序 我打算在 Linux 和 OSX 上分发它 但我在 OSX Snow Leopard 上遇到了问题 python Python 2 5 2 r252 60
  • 无法连接到 macOS 上的 Docker 守护进程

    我通常更喜欢使用brew 来管理我的OSX 上的应用程序 我能够安装 docker docker compose 和 docker machine docker version Docker version 17 05 0 ce build
  • 所有平台上的java

    如果您想用 java 为 Windows Mac 和 Linux 编写桌面应用程序 那么所有这些代码都相同吗 您只需更改 GUI 即可使 Windows 应用程序更像 Windows 等等 如果不深入细节 它是如何工作的 Java 的卖点之
  • Mac 上的 Qt — 如何访问帮助菜单中的“搜索”

    我正在将我的 Qt 应用程序移植到 Mac OS X 在 Windows Linux 上 我使用 QLineEdit 在帮助菜单中提供搜索功能 In Mac OS X I saw something like this is built i
  • Codesign:什么是未密封内容?

    我刚刚升级到 XCode 6 并尝试构建我的开发者 ID 签名的 Mac 应用程序 但是 我现在收到以下协同设计错误 unsealed contents present in the root directory of an embedde
  • 使用 C 在 OS X 中获取其他进程的 argv

    我想获得其他进程的argv 例如ps 我使用的是在 Intel 或 PowerPC 上运行的 Mac OS X 10 4 11 首先 我阅读了 ps 和 man kvm 的代码 然后编写了一些 C 代码 include
  • 当所选选项是下拉列表中已选择的选项时如何接收事件?

    动机 我想动态加载一个select使用来自 AJAX 调用的值 并允许用户select加载后列表中的第一项after它获得焦点 现在 第一项是selected项目 当您单击下拉列表并单击第一项时 什么也没有发生 我无法添加任何无效选择的占位
  • Swift 中带圆角的 NSWindow

    我想要一个圆角的窗户 但我在每个角落都有一个白点 Code let effect NSVisualEffectView frame NSRect x 0 y 0 width 0 height 0 effect blendingMode be
  • 警告:找不到模板 /usr/local/git/share/git-core/templates

    我收到这个错误警告 找不到模板 usr local git share git core templates当我在本地存储库中克隆存储库时这个链接 https github com zikula modules Scribite issue
  • 使用 Swift(使用 SwiftJWT)和 REST API 连接到 Apple Store Connect - 失败并出现 401

    我正在尝试通过他们的 REST API 连接到 Apple Store Connect 虽然这在几天前有效 但我无法弄清楚为什么它停止工作 现在我无法通过身份验证 即我发出的服务器响应的每个请求都是 401 我是否遗漏了什么 我做什么 生成

随机推荐

  • 渗透测试-完整渗透流程(一.信息收集)

    信息收集 1 信息收集分为主动收集和被动收集 主动收集会被防守方发现 被动收集不会被发现 主动信息收集 通过直接访问 扫描网站 这种流量将流经网站 被动信息收集 利用第三方的服务对目标进行访问了解 比例 Google搜索 Shodan搜索等
  • 设计模式(狂神说)

    1p 12p设计模式概述 代码 创建型模式 结构型模式 将类或者对象按照某种布局组成更大的结构 行为型模式 描述类和对象之间相互协作 2p 12p OOP七大原则 开闭原则 对扩展开放 对修改关闭 里氏替换原则 继承必须确保超类所拥有的性质
  • JVM常见知识点

    目录 JVM主要组成部分及其作用 JVM主要包含两个子系统和两个组件 Java程序运行机制 双亲委派机制 类加载器 双亲委派模型 双亲委派机制存在的意义 举例 栈 堆 队列 堆栈区别 队列跟栈区别 Java垃圾回收 方法区是在堆里面吗 JV
  • 国务院建议探索区块链等技术缩短承兑期限

    摘要 产业动态 全球大学区块链能力排名 新加坡国立大学第一 清华第八 韩国记者协会与与PUBLISH合作 采用区块链技术改善新闻媒体生态系统 Ripple与卡塔尔国家银行达成合作 将为其推出新汇款服务 政策相关 国务院 建议探索以互联网和区
  • B站S11破亿直播在线稳定性保障秘籍——演讲实录

    英雄联盟 S11全球总决赛 决赛中国战队夺冠 赛事直播盛况空前 观赛人数破亿 B站作为英雄联盟2021全球总决赛直播独家版权方不仅在整个比赛过程中保证了直播整体总体运行的平稳 还抗住了超预期的流量 如此大型的直播活动 B站究竟是如何保障系统
  • HarmonyOS UI组件在线预览,程序员直呼“不要太方便~”

    原文 UI组件在线预览 程序员直呼 不要太方便 点击链接查看更多技术内容 一 介绍 以往大家如果想查看组件的使用效果 需要打开DevEco Studio构建工程 现在为了便于大家高效开发 文档上线了JS UI组件在线预览功能 无需本地构建工
  • MySQL分库分表 看完吊打面试官

    MySQL分库分表 看完吊打面试官 前言 一 业务场景介绍 二 水平分库分表方法 1 RANGE 2 HASH取模 3 一致性HASH 三 单元测试 总结 作者寄语 提示 下方有源代码地址 请自行拿取 前言 在互联网项目中比较常用到的关系型
  • linux命令详解及软件安装(全)

    环境搭建 环境搭建 Vmware 账号管理 开机关机 目录管理 文件管理 文件操作 touch cat tac more less grep wc vim 磁盘管理 iostat sar df du 内存管理 free CPU管理 top
  • 2023华为OD机试真题Java实现【士兵过河/动态规划】

    题目内容 一支N个士兵的军队正在趁夜色逃亡 途中遇到一条湍急的大河 敌军在T的时长后到达河面 没到过对岸的士兵都会被消灭 现在军队只找到了1只小船 这船最多能同时坐上2个士兵 1 当1个士兵划船过河 用时为 a i 0 lt i lt N
  • 记录vue js-table2excel 导出带有多张图片到Excel

    新建js table2excel js文件 eslint disable let idTmr const getExplorer gt let explorer window navigator userAgent ie if explor
  • Springmvc拦截器三个方法的执行时机

    一 拦截器三个方法分别是 1 1 preHandle 预处理回调方法 实现处理器的预处理 如登录检查 第三个参数为响应的处理器 如具体的Controller实现 返回值 true表示继续流程 如调用下一个拦截器或处理器 false表示流程中
  • 微信小程序与应用服务的关系和“代码安全“

    今天给客户回答了下小程序项目的代码安全问题 他担心源代码提交以及发布系统后被第三方知晓源代码 导致代码泄露 虽然作为程序员来说 这个问题不用考虑 但是非技术人员似懂非懂 所以我还是做了一个解释 一般做微信小程序开发 需要知道微信小程序只是纯
  • 记录PaddleOcr的使用2 -- GPU

    项目场景 之前使用了cpu 但是效率感人 所以想尝试一下GPU的版本 安装环境 windows下使用的 别问 问就是没有有GPU的服务器 1 python 3 7 如果是linux建议3 8 2 pip 版本 20 2 2或更高版本 64
  • LALR(1)语法自动分析生成器Mathew

    首次写博客 文采不好大家不要见笑额 简介 Mathew 马修 马修名字源于 魔力女管家 里的星神马修 马修是一个LALR 1 型活动板房式的语法自动分析生成器 马修继承了Lemon 也许大家对LEX和YACC比较熟悉 这两个工具配合使用可以
  • 记录Chrome截屏整个页面的命令

    F12 右键检查 进入开发者工具 调出命令 MAC command shift P Window ctrl shift P 输入命令 capture full size screenshot
  • C/C++如何输入包含空格的字符串

    对于C 字符串的输入我们看一下下面这段代码 string s 定义空字符串 cin gt gt s 输入字符串 cout lt lt s 打印 但我们会发现如果我们输入了还有空格的字符串 s里读入的字符串遇到空格 回车 tab都会结束 比如
  • 目前 AIGC 工具到底能帮我们做什么?

    最近直播超级多 预约保你有收获 今天腾讯发布了混元大模型 大模型赛道越来越内卷了 今天咱们来聊聊目前的 AIGC 工具能帮助我们做什么 AIGC 的本质是由 AI 来生产内容 通过自然语言交互的方式 让 AIGC 工具输出内容 AIGC 工
  • 20-文件下载及读取漏洞

    WEB 漏洞 文件操作之文件下载读取全解 思维导图 1 文件被解析 则是文件解析漏洞 2 显示源代码 则是文件读取漏洞 3 提示文件下载 则是文件下载漏洞 文件下载漏洞 利用条件 1 存在读文件的函数和操作 2 读取文件的路径用户可控且未校
  • Android 保存资源图片到相册最新写法适用于Android10.0及以上

    博主前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住也分享一下给大家 点击跳转到网站 一 首先在AndroidManifest xml中加入权限
  • APFS 文件系统探究

    本文的创作初衷是因为我发现从底层详解 APFS 的资料很少 所以自己来进行了一些探究和整理 一点说明 如果你在看 APFS 的文档或者其他内容 不要把高层级的分区理解成 Windows 中的分区 因为 APFS 里卷 Volume 才是显示