Use a simpler way to decide what devices we could write to on macOS.
authorCarl Hetherington <cth@carlh.net>
Sat, 3 Feb 2024 20:11:46 +0000 (21:11 +0100)
committerCarl Hetherington <cth@carlh.net>
Sun, 4 Feb 2024 12:21:20 +0000 (13:21 +0100)
This basically involves the kDADiskDescriptionDeviceInternalKey,
kDADiskDescriptionMediaRemovableKey and kDADiskDescriptionMediaWritableKey
keys revealed by looking in

https://github.com/balena-io-modules/drivelist.git

src/lib/cross.h
src/lib/cross_common.cc
src/lib/cross_osx.cc
test/disk_writer_test.cc

index 6904811b756bd7299c57c96bbdad45baac079761..150199561f31223ac2ecadbefdc123681329413a 100644 (file)
@@ -138,29 +138,19 @@ private:
 void disk_write_finished ();
 
 
-struct OSXMediaPath
-{
-       bool real; ///< true for a "real" disk, false for a synthesized APFS one
-       std::vector<std::string> parts; ///< parts of the media path after the :
-};
-
-
 struct OSXDisk
 {
        std::string device;
        boost::optional<std::string> vendor;
        boost::optional<std::string> model;
-       OSXMediaPath media_path;
-       bool whole;
        std::vector<boost::filesystem::path> mount_points;
        unsigned long size;
+       bool system;
+       bool writeable;
+       bool partition;
 };
 
 
-boost::optional<OSXMediaPath> analyse_osx_media_path (std::string path);
-std::vector<Drive> osx_disks_to_drives (std::vector<OSXDisk> disks);
-
-
 class ArgFixer
 {
 public:
index b4d322096a5645f3bf7f7fd5c09d40f94279b3ef..b8f1d48f13dbc983de6493d73d1c8689480603a7 100644 (file)
@@ -40,9 +40,6 @@ using std::vector;
 using boost::optional;
 
 
-auto constexpr MEDIA_PATH_REQUIRED_MATCHES = 3;
-
-
 Drive::Drive (string xml)
 {
        cxml::Document doc;
@@ -122,97 +119,3 @@ Drive::log_summary () const
                        );
 }
 
-
-
-/* This is in _common so we can use it in unit tests */
-optional<OSXMediaPath>
-analyse_osx_media_path (string path)
-{
-       if (path.find("/IOHDIXController") != string::npos) {
-               /* This is a disk image, so we completely ignore it */
-               LOG_DISK_NC("Ignoring this as it seems to be a disk image");
-               return {};
-       }
-
-       OSXMediaPath mp;
-       vector<string> parts;
-       split(parts, path, boost::is_any_of("/"));
-       std::copy(parts.begin() + 1, parts.end(), back_inserter(mp.parts));
-
-       if (!parts.empty() && parts[0] == "IODeviceTree:") {
-               mp.real = true;
-               if (mp.parts.size() < MEDIA_PATH_REQUIRED_MATCHES) {
-                       /* Later we expect at least MEDIA_PATH_REQUIRED_MATCHES parts in a IODeviceTree */
-                       LOG_DISK_NC("Ignoring this as it has a strange media path");
-                       return {};
-               }
-       } else if (!parts.empty() && parts[0] == "IOService:") {
-               mp.real = false;
-       } else {
-               return {};
-       }
-
-       return mp;
-}
-
-
-/* Take some OSXDisk objects, representing disks that `DARegisterDiskAppearedCallback` told us about,
- * and find those drives that we could write a DCP to.  The drives returned are "real" (not synthesized)
- * and are whole disks (not partitions).  They may be mounted, or contain mounted partitions, in which
- * their mounted() method will return true.
- */
-vector<Drive>
-osx_disks_to_drives (vector<OSXDisk> disks)
-{
-       using namespace boost::algorithm;
-
-       /* Mark disks containing mounted partitions as themselves mounted */
-       for (auto& i: disks) {
-               if (!i.whole) {
-                       continue;
-               }
-               for (auto& j: disks) {
-                       if (&i != &j && !j.mount_points.empty() && starts_with(j.device, i.device)) {
-                               LOG_DISK("Marking %1 as mounted because %2 is", i.device, j.device);
-                               std::copy(j.mount_points.begin(), j.mount_points.end(), back_inserter(i.mount_points));
-                       }
-               }
-       }
-
-       /* Mark containers of mounted synths as themselves mounted */
-       for (auto& i: disks) {
-               if (i.media_path.real) {
-                       for (auto& j: disks) {
-                               if (!j.media_path.real && !j.mount_points.empty()) {
-                                       /* i is real, j is a mounted synth; if we see the first MEDIA_PATH_REQUIRED_MATCHES parts
-                                        * of i anywhere in j we assume they are related and so i shares j's mount points.
-                                        */
-                                       bool one_missing = false;
-                                       string all_parts;
-                                       DCPOMATIC_ASSERT (i.media_path.parts.size() >= MEDIA_PATH_REQUIRED_MATCHES);
-                                       for (auto k = 0; k < MEDIA_PATH_REQUIRED_MATCHES; ++k) {
-                                               if (find(j.media_path.parts.begin(), j.media_path.parts.end(), i.media_path.parts[k]) == j.media_path.parts.end()) {
-                                                       one_missing = true;
-                                               }
-                                               all_parts += i.media_path.parts[k] + " ";
-                                       }
-
-                                       if (!one_missing) {
-                                               LOG_DISK("Marking %1 as mounted because %2 is (found %3)", i.device, j.device, all_parts);
-                                               std::copy(j.mount_points.begin(), j.mount_points.end(), back_inserter(i.mount_points));
-                                       }
-                               }
-                       }
-               }
-       }
-
-       vector<Drive> drives;
-       for (auto const& i: disks) {
-               if (i.whole && i.media_path.real) {
-                       drives.push_back(Drive(i.device, i.mount_points, i.size, i.vendor, i.model));
-                       LOG_DISK_NC(drives.back().log_summary());
-               }
-       }
-
-       return drives;
-}
index 913b19103865ae2992e4bbfc802d3c4e0eb70d20..20fe9bce870b22bca53c3b6d104f46b9cee5d82c 100644 (file)
@@ -240,44 +240,6 @@ get_model (CFDictionaryRef& description)
 }
 
 
-static optional<OSXMediaPath>
-analyse_media_path (CFDictionaryRef& description)
-{
-       using namespace boost::algorithm;
-
-       void const* str = CFDictionaryGetValue (description, kDADiskDescriptionMediaPathKey);
-       if (!str) {
-               LOG_DISK_NC("There is no MediaPathKey (no dictionary value)");
-               return {};
-       }
-
-       auto path_key_cstr = CFStringGetCStringPtr((CFStringRef) str, kCFStringEncodingUTF8);
-       if (!path_key_cstr) {
-               LOG_DISK_NC("There is no MediaPathKey (no cstring)");
-               return {};
-       }
-
-       string path(path_key_cstr);
-       LOG_DISK("MediaPathKey is %1", path);
-       return analyse_osx_media_path (path);
-}
-
-
-static bool
-is_whole_drive (DADiskRef& disk)
-{
-       io_service_t service = DADiskCopyIOMedia (disk);
-        CFTypeRef whole_media_ref = IORegistryEntryCreateCFProperty (service, CFSTR(kIOMediaWholeKey), kCFAllocatorDefault, 0);
-       bool whole_media = false;
-        if (whole_media_ref) {
-               whole_media = CFBooleanGetValue((CFBooleanRef) whole_media_ref);
-                CFRelease (whole_media_ref);
-        }
-       IOObjectRelease (service);
-       return whole_media;
-}
-
-
 static optional<boost::filesystem::path>
 mount_point (CFDictionaryRef& description)
 {
@@ -294,29 +256,17 @@ mount_point (CFDictionaryRef& description)
 }
 
 
-/* Here follows some rather intricate and (probably) fragile code to find the list of available
- * "real" drives on macOS that we might want to write a DCP to.
- *
- * We use the Disk Arbitration framework to give us a series of mount_points (/dev/disk0, /dev/disk1,
- * /dev/disk1s1 and so on) and we use the API to gather useful information about these mount_points into
- * a vector of Disk structs.
- *
- * Then we read the Disks that we found and try to derive a list of drives that we should offer to the
- * user, with details of whether those drives are currently mounted or not.
- *
- * At the basic level we find the "disk"-level mount_points, looking at whether any of their partitions are mounted.
- *
- * This is complicated enormously by recent-ish macOS versions' habit of making `synthesized' volumes which
- * reflect data in `real' partitions.  So, for example, we might have a real (physical) drive /dev/disk2 with
- * a partition /dev/disk2s2 whose content is made into a synthesized /dev/disk3, itself containing some partitions
- * which are mounted.  /dev/disk2s2 is not considered to be mounted, in this case.  So we need to know that
- * disk2s2 is related to disk3 so we can consider disk2s2 as mounted if any parts of disk3 are.  In order to do
- * this I am taking the first two parts of the IODeviceTree and seeing if they exist anywhere in a
- * IOService identifier.  If they do, I am assuming the IOService device is on the matching IODeviceTree device.
- *
- * Lots of this is guesswork and may be broken.  In my defence the documentation that I have been able to
- * unearth is, to put it impolitely, crap.
- */
+static bool
+get_bool(CFDictionaryRef& description, void const* key)
+{
+       auto value = CFDictionaryGetValue(description, key);
+       if (!value) {
+               return false;
+       }
+
+       return CFBooleanGetValue(reinterpret_cast<CFBooleanRef>(value));
+}
+
 
 static void
 disk_appeared (DADiskRef disk, void* context)
@@ -339,32 +289,30 @@ disk_appeared (DADiskRef disk, void* context)
        this_disk.model = get_model (description);
        LOG_DISK("Vendor/model: %1 %2", this_disk.vendor.get_value_or("[none]"), this_disk.model.get_value_or("[none]"));
 
-       auto media_path = analyse_media_path (description);
-       if (!media_path) {
-               LOG_DISK("Finding media path for %1 failed", bsd_name);
-               return;
-       }
-
-       this_disk.media_path = *media_path;
-       this_disk.whole = is_whole_drive (disk);
        auto mp = mount_point (description);
        if (mp) {
                this_disk.mount_points.push_back (*mp);
        }
 
-       LOG_DISK(
-               "%1 %2 mounted at %3",
-                this_disk.media_path.real ? "Real" : "Synth",
-                this_disk.whole ? "whole" : "part",
-                mp ? mp->string() : "[nowhere]"
-               );
-
        auto media_size_cstr = CFDictionaryGetValue (description, kDADiskDescriptionMediaSizeKey);
        if (!media_size_cstr) {
                LOG_DISK_NC("Could not read media size");
                return;
        }
 
+       this_disk.system = get_bool(description, kDADiskDescriptionDeviceInternalKey) && !get_bool(description, kDADiskDescriptionMediaRemovableKey);
+       this_disk.writeable = get_bool(description, kDADiskDescriptionMediaWritableKey);
+       this_disk.partition = string(bsd_name).find("s", 5) != std::string::npos;
+
+       LOG_DISK(
+               "%1 %2 %3 %4 mounted at %5",
+               bsd_name,
+               this_disk.system ? "system" : "non-system",
+               this_disk.writeable ? "writeable" : "read-only",
+               this_disk.partition ? "partition" : "drive",
+               mp ? mp->string() : "[nowhere]"
+               );
+
        CFNumberGetValue ((CFNumberRef) media_size_cstr, kCFNumberLongType, &this_disk.size);
        CFRelease (description);
 
@@ -395,7 +343,12 @@ Drive::get ()
        DAUnregisterCallback(session, (void *) disk_appeared, &disks);
        CFRelease(session);
 
-       auto drives = osx_disks_to_drives(disks);
+       vector<Drive> drives;
+       for (auto const& disk: disks) {
+               if (!disk.system && !disk.partition && disk.writeable) {
+                       drives.push_back({disk.device, disk.mount_points, disk.size, disk.vendor, disk.model});
+               }
+       }
 
        LOG_DISK("Drive::get() found %1 drives:", drives.size());
        for (auto const& drive: drives) {
index 553adcae7188693f8c330a0b7018e6c0f1894a43..ff39eaaeab6d373d6addfb5de3858e0717f31a39 100644 (file)
@@ -228,110 +228,3 @@ BOOST_AUTO_TEST_CASE (disk_writer_test3)
 
        cl.run();
 }
-
-
-BOOST_AUTO_TEST_CASE (osx_drive_identification_test)
-{
-       vector<OSXDisk> disks;
-
-       auto disk = [&disks](string mount_point, string media_path, bool whole, std::vector<boost::filesystem::path> mount_points)
-       {
-               auto mp = analyse_osx_media_path (media_path);
-               if (mp) {
-                       disks.push_back({mount_point, {}, {}, *mp, whole, mount_points, 0});
-               }
-       };
-
-       auto find_unmounted = [](vector<OSXDisk> disks) {
-               auto drives = osx_disks_to_drives (disks);
-               vector<Drive> unmounted;
-               std::copy_if (drives.begin(), drives.end(), std::back_inserter(unmounted), [](Drive const& drive) { return !drive.mounted(); });
-               return unmounted;
-       };
-
-       disk("/dev/disk4s1", "IODeviceTree:/arm-io@10F00000/apcie@90000000/pci-bridge1@1/pcie-xhci@0/@7:1", false, {});
-       disk("/dev/disk4", "IODeviceTree:/arm-io@10F00000/apcie@90000000/pci-bridge1@1/pcie-xhci@0/@7:0", true, {});
-       disk("/dev/disk0", "IODeviceTree:/arm-io@10F00000/ans@77400000/iop-ans-nub/AppleANS3NVMeController/@1:0", true, {});
-       disk("/dev/disk0s1", "IODeviceTree:/arm-io@10F00000/ans@77400000/iop-ans-nub/AppleANS3NVMeController/@1:1", false, {});
-       disk("/dev/disk0s2", "IODeviceTree:/arm-io@10F00000/ans@77400000/iop-ans-nub/AppleANS3NVMeController/@1:2", false, {});
-       disk("/dev/disk0s3", "IODeviceTree:/arm-io@10F00000/ans@77400000/iop-ans-nub/AppleANS3NVMeController/@1:3", false, {});
-       disk("/dev/disk1", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/iBootSystemContainer@1/AppleAPFSContainerScheme/AppleAPFSMedia", true, {});
-       disk("/dev/disk2", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/RecoveryOSContainer@3/AppleAPFSContainerScheme/AppleAPFSMedia", true, {});
-       disk("/dev/disk3", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia", false, {});
-       disk("/dev/disk1s1", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/iBootSystemContainer@1/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/iSCPreboot@1", false, {});
-       disk("/dev/disk1s2", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/iBootSystemContainer@1/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/xART@2", false, {});
-       disk("/dev/disk1s3", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/iBootSystemContainer@1/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Hardware@3", false, {});
-       disk("/dev/disk1s4", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/iBootSystemContainer@1/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Recovery@4", false, {});
-       disk("/dev/disk2s1", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/RecoveryOSContainer@3/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Recovery@1", false, {});
-       disk("/dev/disk2s2", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/RecoveryOSContainer@3/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Update@2", false, {});
-       disk("/dev/disk3s1", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Macintosh HD@1", false, {});
-       disk("/dev/disk3s4", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Update@4", false, {"/System/Volumes/Update"});
-       disk("/dev/disk3s5", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Data@5", false, {"/System/Volumes/Data"});
-       disk("/dev/disk3s2", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Preboot@2", false, {"/System/Volumes/Preboot"});
-       disk("/dev/disk3s3", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Recovery@3", false, {});
-       disk("/dev/disk3s6", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/VM@6", false, {"/System/Volumes/VM"});
-       disk("/dev/disk3s1s1", "IOService:/AppleARMPE/arm-io@10F00000/AppleT810xIO/ans@77400000/AppleASCWrapV4/iop-ans-nub/RTBuddyV2/RTBuddyService/AppleANS3NVMeController/NS_01@1/IOBlockStorageDriver/APPLE SSD AP0512Q Media/IOGUIDPartitionScheme/Container@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Macintosh HD@1/com.apple.os.update-EA882DCA7A28EBA0A6E94689836BB10D77D84D1AEE2468E17775A447AA815278@1", false, {"/"});
-
-       vector<Drive> writeable = find_unmounted (disks);
-       BOOST_REQUIRE_EQUAL (writeable.size(), 1U);
-       BOOST_CHECK_EQUAL (writeable[0].device(), "/dev/disk4");
-
-       disks.clear ();
-       disk("/dev/disk4s1", "IOService:/IOResources/IOHDIXController/IOHDIXHDDriveOutKernel@0/IODiskImageBlockStorageDeviceOutKernel/IOBlockStorageDriver/Apple UDIF read-only compressed (zlib) Media/IOGUIDPartitionScheme/disk image@1", false, {});
-       disk("/dev/disk4", "IOService:/IOResources/IOHDIXController/IOHDIXHDDriveOutKernel@0/IODiskImageBlockStorageDeviceOutKernel/IOBlockStorageDriver/Apple UDIF read-only compressed (zlib) Media", true, {});
-       disk("/dev/disk3s1", "IODeviceTree:/PCI0@0/XHC1@14/@2:1", false, {});
-       disk("/dev/disk3", "IODeviceTree:/PCI0@0/XHC1@14/@2:0", true, {});
-       disk("/dev/disk0", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:0", true, {});
-       disk("/dev/disk0s1", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:1", false, {});
-       disk("/dev/disk0s2", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:2", false, {"/Volumes/Macintosh HD"});
-       disk("/dev/disk0s3", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:3", false, {});
-       disk("/dev/disk0s4", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:4", false, {});
-       disk("/dev/disk0s5", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:5", false, {"/Volumes/High Sierra"});
-       disk("/dev/disk0s6", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:6", false, {});
-       disk("/dev/disk0s7", "IODeviceTree:/PCI0@0/SATA@1F,2/PRT1@1/PMP@0/@0:7", false, {"/Volumes/Recovery HD"});
-       disk("/dev/disk1", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 3@3/AppleAPFSContainerScheme/AppleAPFSMedia", true, {});
-       disk("/dev/disk", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 4@4/AppleAPFSContainerScheme/AppleAPFSMedia", true, {});
-       disk("/dev/disk1s1", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 3@3/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Untitled - Data@1", false, {"/Volumes/Untitled - Data"});
-       disk("/dev/disk1s2", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 3@3/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Preboot@2", false, {});
-       disk("/dev/disk1s3", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 3@3/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Recovery@3", false, {});
-       disk("/dev/disk1s4", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 3@3/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/VM@4", false, {});
-       disk("/dev/disk1s5", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 3@3/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Untitled@5", false, {"/Volumes/Untitled"});
-       disk("/dev/disk2s1", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 4@4/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Catalina - Data@1", false, {});
-       disk("/dev/disk2s2", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 4@4/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Preboot@2", false, {});
-       disk("/dev/disk2s3", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 4@4/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Recovery@3", false, {});
-       disk("/dev/disk2s4", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 4@4/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/VM@4", false, {"/private/var/vm"});
-       disk("/dev/disk2s5", "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/SATA@1F,2/AppleIntelPchSeriesAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/APPLE HDD ST500LM012 Media/IOGUIDPartitionScheme/Untitled 4@4/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Catalina@5", false, {"/"});
-
-       writeable = find_unmounted (disks);
-       BOOST_REQUIRE_EQUAL (writeable.size(), 1U);
-       BOOST_CHECK_EQUAL (writeable[0].device(), "/dev/disk3");
-
-       disks.clear ();
-       disk("/dev/disk7", "IOService:/IOResources/IOHDIXController/IOHDIXHDDriveOutKernel@3/IODiskImageBlockStorageDeviceOutKernel/IOBlockStorageDriver/Apple UDIF read-only compressed (zlib) Media", true, {});
-       disk("/dev/disk7s1", "IOService:/IOResources/IOHDIXController/IOHDIXHDDriveOutKernel@3/IODiskImageBlockStorageDeviceOutKernel/IOBlockStorageDriver/Apple UDIF read-only compressed (zlib) Media/IOGUIDPartitionScheme/disk image@1", false, {});
-       disk("/dev/disk6s1", "MediaPathKey is IOService:/IOResources/IOHDIXController/IOHDIXHDDriveOutKernel@2/IODiskImageBlockStorageDeviceOutKernel/IOBlockStorageDriver/Apple UDIF read-only compressed (zlib) Media/IOGUIDPartitionScheme/disk image@1", false, {});
-       disk("/dev/disk6", "IOService:/IOResources/IOHDIXController/IOHDIXHDDriveOutKernel@2/IODiskImageBlockStorageDeviceOutKernel/IOBlockStorageDriver/Apple UDIF read-only compressed (zlib) Media", true, {});
-       disk("/dev/disk5s1", "IOService:/IOResources/IOHDIXController/IOHDIXHDDriveOutKernel@1/IODiskImageBlockStorageDeviceOutKernel/IOBlockStorageDriver/Apple UDIF read-only compressed (zlib) Media/IOGUIDPartitionScheme/disk image@1", false, {});
-       disk("/dev/disk5", "IOService:/IOResources/IOHDIXController/IOHDIXHDDriveOutKernel@1/IODiskImageBlockStorageDeviceOutKernel/IOBlockStorageDriver/Apple UDIF read-only compressed (zlib) Media", true, {});
-       disk("/dev/disk4s1", "IOService:/IOResources/IOHDIXController/IOHDIXHDDriveOutKernel@0/IODiskImageBlockStorageDeviceOutKernel/IOBlockStorageDriver/Apple UDIF read-only compressed (zlib) Media/IOGUIDPartitionScheme/disk image@1", false, {});
-       disk("/dev/disk4", "IOService:/IOResources/IOHDIXController/IOHDIXHDDriveOutKernel@0/IODiskImageBlockStorageDeviceOutKernel/IOBlockStorageDriver/Apple UDIF read-only compressed (zlib) Media", true, {});
-       disk("/dev/disk0", "IODeviceTree:/PCI0@1e0000/pci8086,2829@1F,2/PRT3@3/PMP@0/@0:0", true, {});
-       disk("/dev/disk2", "IODeviceTree:/PCI0@1e0000/pci8086,2829@1F,2/PRT1@1/PMP@0/@0:0", true, {});
-       disk("/dev/disk1", "IODeviceTree:/PCI0@1e0000/pci8086,2829@1F,2/PRT0@0/PMP@0/@0:0", true, {});
-       disk("/dev/disk1s1", "IODeviceTree:/PCI0@1e0000/pci8086,2829@1F,2/PRT0@0/PMP@0/@0:1", false, {"/Volumes/EFI"});
-       disk("/dev/disk2s1", "IODeviceTree:/PCI0@1e0000/pci8086,2829@1F,2/PRT1@1/PMP@0/@0:1", false, {});
-       disk("/dev/disk2s2", "IODeviceTree:/PCI0@1e0000/pci8086,2829@1F,2/PRT1@1/PMP@0/@0:2", false, {});
-       disk("/dev/disk3", "IOService:/AppleACPIPlatformExpert/PCI0@1e0000/AppleACPIPCI/pci8086,2829@1F,2/AppleAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/VBOX HARDDISK Media/IOGUIDPartitionScheme/disk image@2/AppleAPFSContainerScheme/AppleAPFSMedia", false, {});
-       disk("/dev/disk3s1", "IOService:/AppleACPIPlatformExpert/PCI0@1e0000/AppleACPIPCI/pci8086,2829@1F,2/AppleAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/VBOX HARDDISK Media/IOGUIDPartitionScheme/disk image@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/macOS - Data@1", false, {"/System/Volumes/Data"});
-       disk("/dev/disk3s2", "IOService:/AppleACPIPlatformExpert/PCI0@1e0000/AppleACPIPCI/pci8086,2829@1F,2/AppleAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/VBOX HARDDISK Media/IOGUIDPartitionScheme/disk image@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Preboot@2", false, {"/System/Volumes/Preboot"});
-       disk("/dev/disk3s3", "IOService:/AppleACPIPlatformExpert/PCI0@1e0000/AppleACPIPCI/pci8086,2829@1F,2/AppleAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/VBOX HARDDISK Media/IOGUIDPartitionScheme/disk image@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Recovery@3", false, {});
-       disk("/dev/disk3s4", "IOService:/AppleACPIPlatformExpert/PCI0@1e0000/AppleACPIPCI/pci8086,2829@1F,2/AppleAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/VBOX HARDDISK Media/IOGUIDPartitionScheme/disk image@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/VM@4", false, {"/System/Volumes/VM"});
-       disk("/dev/disk3s5", "IOService:/AppleACPIPlatformExpert/PCI0@1e0000/AppleACPIPCI/pci8086,2829@1F,2/AppleAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/VBOX HARDDISK Media/IOGUIDPartitionScheme/disk image@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/macOS@5", false, {});
-       disk("/dev/disk3s6", "IOService:/AppleACPIPlatformExpert/PCI0@1e0000/AppleACPIPCI/pci8086,2829@1F,2/AppleAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/VBOX HARDDISK Media/IOGUIDPartitionScheme/disk image@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/Update@6", false, {"/System/Volumes/Update"});
-       disk("/dev/disk3s5s1", "IOService:/AppleACPIPlatformExpert/PCI0@1e0000/AppleACPIPCI/pci8086,2829@1F,2/AppleAHCI/PRT1@1/IOAHCIDevice@0/AppleAHCIDiskDriver/IOAHCIBlockStorageDevice/IOBlockStorageDriver/VBOX HARDDISK Media/IOGUIDPartitionScheme/disk image@2/AppleAPFSContainerScheme/AppleAPFSMedia/AppleAPFSContainer/macOS@5/com.apple.os.update-5523D8E63431315F9F949CCDD0274BF797F5CEE4EAF616D4C66A01B8D6A83C7B@1", false, {"/"});
-
-       writeable = find_unmounted (disks);
-       BOOST_REQUIRE_EQUAL (writeable.size(), 1U);
-       BOOST_CHECK_EQUAL (writeable[0].device(), "/dev/disk0");
-}
-