Mike Bombich为我提供了这个解决方案:
您可以从 IOKit 获取卷 UUID 和卷组 UUID。同一组中的两个卷将具有相同的组 UUID。请注意,组 UUID 始终与数据卷的 UUID 相同(至少在实践中)。
这是获取已安装卷列表的代码,包括属于卷组的隐藏卷:
- (void)listVolumes
{
NSArray<NSURL*> *vols = [NSFileManager.defaultManager mountedVolumeURLsIncludingResourceValuesForKeys:nil options: 0 ];
vols = [vols arrayByAddingObject:[NSURL fileURLWithPath:@"/System/Volumes/Data"]]; // the root's Data vol isn't added by default
NSMutableArray<NSString*> *lines = [NSMutableArray new];
for (NSURL *vol in vols) {
NSDictionary *d = [vol resourceValuesForKeys:@[
NSURLVolumeIsBrowsableKey,
NSURLVolumeIsRootFileSystemKey,
NSURLVolumeIdentifierKey,
NSURLVolumeNameKey
] error:nil];
struct statfs fsinfo;
statfs(vol.path.UTF8String, &fsinfo);
NSString *bsdName = [NSString stringWithUTF8String:fsinfo.f_mntfromname];
bsdName = [bsdName lastPathComponent];
[lines addObject:[NSString stringWithFormat:@"%@, %@, %@, %@", bsdName, vol.path, d[NSURLVolumeIsBrowsableKey], d[NSURLVolumeNameKey]]];
}
NSLog(@"\n%@", [lines componentsJoinedByString:@"\n"]);
}
以及列出卷组 ID 及其角色的代码:
- (void)listGroupIDs
{
io_iterator_t iterator; io_object_t obj;
IOServiceGetMatchingServices (kIOMasterPortDefault, IOServiceMatching("IOMediaBSDClient"), &iterator);
while ((obj = IOIteratorNext (iterator)) != 0) {
io_object_t obj2;
IORegistryEntryGetParentEntry (obj, kIOServicePlane, &obj2);
NSString *bsdName = CFBridgingRelease(IORegistryEntryCreateCFProperty(obj2, CFSTR("BSD Name"), kCFAllocatorDefault, 0));
//NSString *volID = CFBridgingRelease(IORegistryEntryCreateCFProperty(obj2, CFSTR("UUID"), kCFAllocatorDefault, 0));
NSString *groupID = CFBridgingRelease(IORegistryEntryCreateCFProperty(obj2, CFSTR("VolGroupUUID"), kCFAllocatorDefault, 0));
NSArray *roles = CFBridgingRelease(IORegistryEntryCreateCFProperty(obj2, CFSTR("Role"), kCFAllocatorDefault, 0));
if (groupID != nil && ![groupID isEqualToString:@"00000000-0000-0000-0000-000000000000"]) {
NSLog(@"%@: %@, %@", bsdName, groupID, roles);
}
}
}
有了这两个信息,来自 IOKit 的卷可以通过它们的 BSD 名称与 NSURL 匹配。
但是,还有一种特殊情况:在 macOS Big Sur 上,根系统的设备不是常规的“diskXsY”,而是一个快照设备,例如“diskXsYsZ”。虽然 IOKit 代码也列出了这一点,但它的条目缺少角色信息。
这是 Mac 的示例输出,其中包含 Big Sur 和 Catalina 系统,如问题所示(为便于阅读,稍作编辑):
disk3s1s1, /, 1, BigSur
disk3s5, /System/Volumes/VM, 0, VM
disk3s3, /System/Volumes/Preboot, 0, Preboot
disk3s6, /System/Volumes/Update, 0, Update
disk4s1, /Volumes/Catalina - Daten, 0, Catalina - Daten
disk4s2, /Volumes/Catalina, 1, Catalina
disk3s2, /System/Volumes/Data, 1, BigSur
disk4s1: 18464FE4-8321-4D36-B87A-53AC38EF6AEF, 18464FE4-8321-4D36-B87A-53AC38EF6AEF, ("Data")
disk3s1: 86812DBD-9252-4A2E-8887-752418DECE13, 058517A6-48DD-46AB-8A78-C1F115AE6E13, ("System")
disk4s2: 51DEC6AC-2D68-4B60-AE23-74BCA2C3A484, 18464FE4-8321-4D36-B87A-53AC38EF6AEF, ("System")
disk3s2: 058517A6-48DD-46AB-8A78-C1F115AE6E13, 058517A6-48DD-46AB-8A78-C1F115AE6E13, ("Data")
disk3s1s1: C26440B0-0207-4227-A4B1-EBDD62C90D24, 058517A6-48DD-46AB-8A78-C1F115AE6E13, (null)
我已经发布了一个工作代码示例,该示例确定了所有已安装的卷及其组关系。整个可编译代码(您可以在新的 Obj-C App 项目的AppDelegate.m
文件中替换它)可以在这里找到:https ://gist.github.com/tempelmann/80efc2eb84f0171a96822290dee7d8d9