2

我正在尝试使用 Swift 获得我计算机所有卷的树状结构。

获取所有已安装卷的最简单方法是以下代码:

FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: nil)

使用它URL,我可以创建一个DADisk对象来获取 BSD 名称:

if let session = DASessionCreate(kCFAllocatorDefault) {
  if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, url as CFURL) {
    if let bsdName = DADiskGetBSDName(disk) {
      volume.bsdName = String(cString : bsdName) // Volume is my own class.
    }
  }
}

现在对于“主”磁盘,我得到“disk0”。我想获得有关此磁盘的更多信息。如果我看一下磁盘实用程序,disk0 似乎没有做太多,所以我想获取 disk0 的所有“子”卷。我试图收集所有磁盘,剪切“磁盘”,然后解析剩余编号。有时这可行(如果disk1 有子卷disk1s1 和disk1s2),但有时有一个根磁盘(我们称之为disk2)并且有一个(虚拟?)容器。在这个容器下面,还有额外的磁盘,称为 disk3 和 disk3s1(这是我的方法失败的地方)。

我尝试使用IOKitwhich 打印所有磁盘名称。但是,我不知道如何构建树状结构(我想我可以根据路径破解一些东西):

var iterator: io_iterator_t = 0
let matching: CFDictionary = IOServiceMatching(kIOServicePlane)
IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator)
var child: io_object_t = IOIteratorNext(iterator)

while child != 0
{
    if let bsdName = IORegistryEntryCreateCFProperty(child, self.bsdNameKey as CFString, kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively))
    {
        Swift.print(bsdName)
    }

    child = IOIteratorNext(iterator)
}

有没有一种可靠的方法可以在某种层次结构中获取主磁盘及其所有卷?

4

1 回答 1

1

我设法使用一种 hacky 的方式制作了一个类似的结构,而且目前对沙盒不太友好(它可能对沙盒友好,继续阅读以获取更多信息)。

这一切都基于这样一个事实,即当您执行以下终端命令时,diskutil 命令实际上会返回一个树状结构,其中包含您可能需要的有关系统中存在的磁盘的所有详细信息:diskutil list -plist

因此,为了在我的代码中使用它来获取磁盘树结构,我执行了以下操作:

  1. 我使用 Process Object 实现了一个函数,以将“diskutil list -plist”的输出作为字符串返回给我(据我所知,如果你想让你的应用程序对沙箱友好,这部分代码需要在需要嵌入到应用程序包中的辅助工具中)

  2. 我创建了一些 Codable 结构和一些协议来与它们一起以最小的努力反序列化 plist 字符串

  3. 我让我的代码对结构执行了一些操作,以便更容易处理一些事情,例如将与其物理设备关联的 APFS 容器放入树状结构中

在这里复制粘贴所有代码会造成很多混乱(这是很多代码),我更喜欢将我在开源项目中完成大部分这些工作的 swift 文件链接:https ://github.com /ITzTravelInTime/TINU/blob/development/TINU/DiskutilListCodable.swift

老实说,我不知道 Diskutil 可执行文件使用什么样的黑魔法来收集这些信息并生成三个结构,但现在这是我发现收集这些信息的最简单方法,我知道一些开发人员(比如工作的人一些 EFI 分区/ESP 安装工具)已经设法使用系统 API 来解决这个问题,但我不知道如何。

于 2021-06-25T19:22:58.090 回答