Extract osx_disks_to_drives to cross_common for tests.
[dcpomatic.git] / src / lib / cross_common.cc
index 2e48bf3e015131fab22094fea7a46b80f028325f..250db3cd5a5ded8b0f98a3eb7799b214e2931d9a 100644 (file)
 DCPOMATIC_DISABLE_WARNINGS
 #include <libxml++/libxml++.h>
 DCPOMATIC_ENABLE_WARNINGS
+#include <boost/algorithm/string.hpp>
 #include <iostream>
 
 #include "i18n.h"
 
 
+using std::map;
 using std::string;
+using std::vector;
+using boost::optional;
 
 
 Drive::Drive (string xml)
@@ -113,3 +117,89 @@ Drive::log_summary () const
                _device, mp, _size, _vendor.get_value_or("[none]"), _model.get_value_or("[none]")
                        );
 }
+
+
+
+/* This is in _common so we can use it in unit tests */
+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");
+               return {};
+       }
+
+       OSXMediaPath mp;
+       if (starts_with(path, "IODeviceTree:")) {
+               mp.real = true;
+       } else if (starts_with(path, "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 */
+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 (!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);
+                               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 */
+       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));
+                       }
+               }
+       }
+
+       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));
+                       LOG_DISK_NC(drives.back().log_summary());
+               }
+       }
+
+       return drives;
+}