如何将 Mac OS X 上卷的 UUID 更改为指定值?

如何将 Mac OS X 上卷的 UUID 更改为指定值?

这与这里提出的问题类似:

如何在 Mac OS X 10.6 上更改卷的 UUID?

唯一的区别是我想将其更改为特定值,而不是随机值。hfs.util 似乎只能执行随机操作。

我考虑修改hfs.util 源允许我指定值。当我在代码中寻找从哪里开始更改时,我想起为什么 C不是我最喜欢的语言。几次编译错误和段错误之后,我失去了尝试修改此工具的热情。我愿意在休息后再次尝试,但我认为一定有一种更简单的方法来更改卷的 UUID,而我只是不知道。

因此,在我浪费更多时间之前,有谁知道有什么简单的方法可以做到这一点?或者有没有 C 专家愿意加入我的努力,让 hfs.util 将 UUID 更改为指定值?

以下是我为了能够从源 OS X 10.6.8 编译该工具所做的更改:

hfsutil_jnl.c:(代码如下:

47: #include <hfs_fsctl.h>

hfsutil_main.c:

80: #include <uuid/uuid.h>
81: /* REMOVED */

而且,正如本文,添加了以下内容fs.c 中的第 166 行到 hfsutil_main.c (因为 namespace.h 不在系统中的任何地方):

static unsigned char kFSUUIDNamespaceSHA1[] = {0xB3,0xE2,0x0F,0x39,0xF2,0x92,0x11,0xD6,0x97,0xA4,0x00,0x30,0x65,0x43,0xEC,0xAC};

最后,我抓取了这个文件并将其添加到工作目录中http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/hfs/hfs_fsctl.h

答案1

我还没有研究过 hfs.util 的源代码,可能对你来说太晚了,但我想我可以贡献一些有用的东西。

用于 HFS+ 卷的 UUID 似乎都是 UUID 规范所涵盖的变体,并且属于版本 3 类型,即通过 MD5 转换为 UUID 的命名空间和名称(请参阅维基百科上的详细信息)。

实际的磁盘标识符(代替规范中的名称)似乎只有 64 位,根据规范转换为 128 位 UUID,方法是在前面添加 Apple 用于卷标识符的命名空间的 UUID,然后应用 MD5 哈希。

这不涉及计算机组件值、当前时间等。这些用于其他类型的 UUID。但它确实涉及“命名空间”UUID(用于识别我们正在“命名”磁盘卷的事实)以及“名称”(磁盘的实际标识符)。

让我这么想的一件事不仅是@chriv 的声明,即代码似乎只使用 64 位,而且还有 SuperDuper 附带的“秘密”实用程序处理 UUID 的方式!

SuperDuper! Mac OS X 备份实用程序有一个“隐藏”的命令行工具,可让您检索和设置卷 UUID。但它会将其检索和设置为 64 位序列(以十六进制表示)。而且这些位似乎与 Apple 磁盘实用程序报告的实际值有很大不同。

更多信息请参阅:

http://www.shirt-pocket.com/forums/archive/index.php/t-1186.html

http://www.shirt-pocket.com/forums/archive/index.php/t-6173.html

注意:请通读这些支持讨论,因为其中似乎存在一些陷阱,例如有时需要重新启动。


更新

我浏览了 Apple 的资料。我确认了上面写的内容。磁盘上保存的是卷的 64 位标识符(它是通过获取一组伪随机数据位的 SHA1 哈希的前 64 位随机生成的:正常运行时间、启动时间、主机 ID、主机名、内核发布字符串、内核版本字符串、平均负载、VM 统计信息和当前时间)。

在版本 3 UUID 术语中,这是一个“名称”。因此,磁盘上保存的是卷的 64 位“名称”,而不是 UUID。

该工具报告的 128 位 UUID 是不是保存后,每次为了显示目的,都会从“名称”和“命名空间”进行计算(命名空间是固定的,并且是 OP 必须手动添加到源的 kFSUUIDNamespaceSHA1 常量,因为缺少包含它的标题:它代表卷“名称”的“命名空间”,这些卷“名称”是实际保存在卷上以识别它们的 64 位内容)。

从“名称”转到 UUID 很容易(基本上,您应用版本 3 UUID 的标准算法),但从 UUID 回到“名称”基本上是不可能的。换句话说,对 OP 的回答是:如果您知道卷的“名称”(例如,如果您想将备份还原到新磁盘,并且您已保存了它的名称以及数据),这是可能的,但如果您只知道 UUID,则不可能。正确设置名称将要导致预期的 UUID,但您需要名称并且无法从 UUID 计算它。


Apple 代码注释(阅读这些并查看代码,一切都变得清晰):

正如我所写,磁盘上只有“名称”。UUID 仅用于可视化,使用版本 3 算法(“命名空间”中“名称”的 UUID)。

  • kFSUUIDNamespaceSHA1是“命名空间”常量,如上所述。
  • uuid_create_md5_from_name是版本 3 UUID 算法,它根据给定的“命名空间”和“名称”计算版本 3 UUID。
  • 生成卷UUID生成一个新的随机“名称”(注意:尽管函数名称不同,但仅仅是“名称”,而不是 UUID)。

设置和获取磁盘的“名称”取决于卷当前是否已安装。“名称”存储在卷的“Finder Info”中。获取和设置已安装卷的“Finder Info”数据可以使用获取属性列表设置属性列表但是如果卷未安装,它们将直接访问卷数据(毕竟这是 unix,未安装的卷是可以由 root 以文件形式访问的块设备)。

  • 设置卷UUID设置体积UUIDRaw设置音量UUIDAttr获取卷UUID获取卷UUIDRaw获取卷UUIDAttr读取/写入“名称”(再次强调,尽管名称不同,但它们仅处理卷的“名称”,而不是 UUID)。*Raw 函数处理通过设备“文件”对未安装卷的直接访问,*Attr 函数使用 get/setattrlist API。普通函数检查卷是否已安装并调用适当的 *Raw/*Attr 版本。

然后是实现该工具功能的“高级”函数:

  • 获取UUID密钥获取“名称”,调整字节顺序,然后计算显示的 UUID。
  • 更改UUID密钥创建一个新的、随机的“名称”并将其写入卷。

所以你能做的最好的事情就是重新编码 Shirt Pocket 的 SuperDuper! 中嵌入的小型命令行工具的相同功能(请参阅我上面发布的链接)。

答案2

我解决了这个问题。我下载了源代码hfs.util,做了你提到的更改(以便它可以编译),重新启用了 UUID 功能(例如在当前源代码中禁用的 -s),并添加了一个新命令(-S 用于指定 UUID)。

新命令的格式如下:

sudo hfs.util -S disk0s2 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

您必须使用 sudo 或以 root 身份运行,但不必卸载该卷(即使它是您当前的系统卷)。

但是,我仍在调试它(我不太擅长 C 语言)。我可以无错误地运行它,但它仍然会使用 -S 有效地随机化新的 UUID。无论我指定什么 UUID,我仍然会得到不同的 UUID。

如果我让它正常工作,我要么在这里发布一个差异,要么找个地方上传修改后的源,并从这里链接到它。

如果我失败了,我可能仍会发布差异,也许其他人(更擅长 C 语言的人)可以修复它。

编辑:好的。我发现处理 UUID 字符串 <--> 二进制函数的 Apple 源代码中似乎存在一个重大错误hfs.util。作为二进制值,需要 4 个(无符号)32 位字来存储 128 位 UUID。Apple 源代码似乎只能处理 16 个十六进制字符(应该是 16 个八位字节,每个字节有 2 个十六进制字符)。

它还似乎使用了一个有缺陷的结构来保存 UUID(它似乎只存储一个“高”32 位字和一个“低”32 位字,但需要 4 个(无符号)32 位字)。我想我可以修复它,但我必须更改结构和使用该结构的所有函数(因此可能需要一段时间)。

编辑#2:在花了太多时间调试 hfs.util 的 Apple 源代码之后(我真的不是一个 C 程序员),我发现 Apple故意地处理 UUID 时仅处理 64 位。其余部分由 64 位常量、计算机组件值、当前时间等的哈希值生成。因此,如果您两次使用相同的 64 位“密钥”,您仍然会得到两个不同的 UUID(即使您使用同一台计算机,时间仍然会改变)。只要实际写入卷头发送实际 UUID(而不仅仅是密钥),并且只要卷头存储实际 UUID(而不仅仅是可用于计算 UUID 的密钥和/或值),那么就有希望。我的调试还没有进行到那一步。当我了解更多信息时,我会再次发布。

相关内容