summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2022-01-18 00:09:36 +0100
committerCarl Hetherington <cth@carlh.net>2022-01-19 20:39:34 +0100
commit9b9202c7f9fc26fcef0984189aaed366b7c6d726 (patch)
tree66653eea92abc8d7f5e551b6336145331bc9190c /src/lib
parent59bb9538218eee564ab3c07f923628e0a47bf207 (diff)
Adjust how macOS drives are analysed and add a couple of tests.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/cross.h10
-rw-r--r--src/lib/cross_common.cc68
-rw-r--r--src/lib/cross_osx.cc18
3 files changed, 47 insertions, 49 deletions
diff --git a/src/lib/cross.h b/src/lib/cross.h
index ac1f028f4..aad223d60 100644
--- a/src/lib/cross.h
+++ b/src/lib/cross.h
@@ -142,19 +142,17 @@ void disk_write_finished ();
struct OSXMediaPath
{
- bool real; ///< true for a "real" disk, false for a synthesized APFS one
- std::string prt; ///< "PRT" entry from the media path
+ 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 mount_point;
+ std::string device;
boost::optional<std::string> vendor;
boost::optional<std::string> model;
- bool real;
- std::string prt;
+ OSXMediaPath media_path;
bool whole;
std::vector<boost::filesystem::path> mount_points;
unsigned long size;
diff --git a/src/lib/cross_common.cc b/src/lib/cross_common.cc
index 250db3cd5..bc1a54367 100644
--- a/src/lib/cross_common.cc
+++ b/src/lib/cross_common.cc
@@ -124,8 +124,6 @@ Drive::log_summary () const
optional<OSXMediaPath>
analyse_osx_media_path (string path)
{
- using namespace boost::algorithm;
-
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");
@@ -133,27 +131,32 @@ analyse_osx_media_path (string path)
}
OSXMediaPath mp;
- if (starts_with(path, "IODeviceTree:")) {
+ 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;
- } else if (starts_with(path, "IOService:")) {
+ if (mp.parts.size() < 2) {
+ /* Later we expect at least 2 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 {};
}
- vector<string> bits;
- split(bits, path, boost::is_any_of("/"));
- for (auto i: bits) {
- if (starts_with(i, "PRT")) {
- mp.prt = i;
- }
- }
-
return mp;
}
-/* This is in _common so we can use it in unit tests */
+/* Take soem 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)
{
@@ -165,38 +168,37 @@ osx_disks_to_drives (vector<OSXDisk> disks)
continue;
}
for (auto& j: disks) {
- if (!j.mount_points.empty() && starts_with(j.mount_point, i.mount_point)) {
- LOG_DISK("Marking %1 as mounted because %2 is", i.mount_point, j.mount_point);
+ if (!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));
}
}
}
- /* Make a map of the PRT codes and mount points of mounted, synthesized disks */
- map<string, vector<boost::filesystem::path>> mounted_synths;
- for (auto const& i: disks) {
- if (!i.real && !i.mount_points.empty()) {
- LOG_DISK("Found a mounted synth %1 with %2", i.mount_point, i.prt);
- mounted_synths[i.prt] = i.mount_points;
- }
- }
-
- /* Mark containers of those mounted synths as themselves mounted */
+ /* Mark containers of mounted synths as themselves mounted */
for (auto& i: disks) {
- if (i.real) {
- auto j = mounted_synths.find(i.prt);
- if (j != mounted_synths.end()) {
- LOG_DISK("Marking %1 (%2) as mounted because it contains a mounted synth", i.mount_point, i.prt);
- std::copy(j->second.begin(), j->second.end(), back_inserter(i.mount_points));
+ 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 two parts
+ * of i anywhere in j we assume they are related and so i shares
+ * j's mount points.
+ */
+ if (
+ find(j.media_path.parts.begin(), j.media_path.parts.end(), i.media_path.parts[0]) != j.media_path.parts.end() &&
+ find(j.media_path.parts.begin(), j.media_path.parts.end(), i.media_path.parts[1]) != j.media_path.parts.end()) {
+ LOG_DISK("Marking %1 as mounted because %2 is (found %3 and %4)", i.device, j.device, i.media_path.parts[0], i.media_path.parts[1]);
+ 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) {
- /* A whole disk that is not a container for a mounted synth */
- drives.push_back(Drive(i.mount_point, i.mount_points, i.size, i.vendor, i.model));
+ 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());
}
}
diff --git a/src/lib/cross_osx.cc b/src/lib/cross_osx.cc
index 018516abb..2dc9b2702 100644
--- a/src/lib/cross_osx.cc
+++ b/src/lib/cross_osx.cc
@@ -380,8 +380,8 @@ mount_point (CFDictionaryRef& description)
* 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 picking out what looks like a suitable identifier prefixed with PRT from the MediaContentKey.
- * If disk2s2 and disk3 have the same PRT code I am assuming they are linked.
+ * 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.
@@ -399,8 +399,8 @@ disk_appeared (DADiskRef disk, void* context)
OSXDisk this_disk;
- this_disk.mount_point = string("/dev/") + bsd_name;
- LOG_DISK("Mount point is %1", this_disk.mount_point);
+ this_disk.device = string("/dev/") + bsd_name;
+ LOG_DISK("Device is %1", this_disk.device);
CFDictionaryRef description = DADiskCopyDescription (disk);
@@ -414,8 +414,7 @@ disk_appeared (DADiskRef disk, void* context)
return;
}
- this_disk.real = media_path->real;
- this_disk.prt = media_path->prt;
+ this_disk.media_path = *media_path;
this_disk.whole = is_whole_drive (disk);
auto mp = mount_point (description);
if (mp) {
@@ -423,11 +422,10 @@ disk_appeared (DADiskRef disk, void* context)
}
LOG_DISK(
- "%1 prt=%2 %3 %4",
- this_disk.real ? "Real" : "Synth",
- this_disk.prt,
+ "%1 %2 mounted at %3",
+ this_disk.media_path.real ? "Real" : "Synth",
this_disk.whole ? "whole" : "part",
- mp ? ("mounted at " + mp->string()) : "unmounted"
+ mp ? mp->string() : "[nowhere]"
);
auto media_size_cstr = CFDictionaryGetValue (description, kDADiskDescriptionMediaSizeKey);