X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Flib%2Fcross_common.cc;h=bc1a543678964a8daeaf8e9c69a708649bd54cfc;hb=9b9202c7f9fc26fcef0984189aaed366b7c6d726;hp=10ffb0677bf48060610a8e31122576e2087848c5;hpb=350afcbc40fffd8c8780180e153a2ee91088f562;p=dcpomatic.git diff --git a/src/lib/cross_common.cc b/src/lib/cross_common.cc index 10ffb0677..bc1a54367 100644 --- a/src/lib/cross_common.cc +++ b/src/lib/cross_common.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2020 Carl Hetherington + Copyright (C) 2012-2021 Carl Hetherington This file is part of DCP-o-matic. @@ -18,12 +18,61 @@ */ + #include "cross.h" #include "compose.hpp" +#include "dcpomatic_log.h" +#include "warnings.h" +#include +DCPOMATIC_DISABLE_WARNINGS +#include +DCPOMATIC_ENABLE_WARNINGS +#include +#include #include "i18n.h" + +using std::map; using std::string; +using std::vector; +using boost::optional; + + +Drive::Drive (string xml) +{ + cxml::Document doc; + doc.read_string (xml); + _device = doc.string_child("Device"); + for (auto i: doc.node_children("MountPoint")) { + _mount_points.push_back (i->content()); + } + _size = doc.number_child("Size"); + _vendor = doc.optional_string_child("Vendor"); + _model = doc.optional_string_child("Model"); +} + + +string +Drive::as_xml () const +{ + xmlpp::Document doc; + auto root = doc.create_root_node ("Drive"); + root->add_child("Device")->add_child_text(_device); + for (auto i: _mount_points) { + root->add_child("MountPoint")->add_child_text(i.string()); + } + root->add_child("Size")->add_child_text(dcp::raw_convert(_size)); + if (_vendor) { + root->add_child("Vendor")->add_child_text(*_vendor); + } + if (_model) { + root->add_child("Model")->add_child_text(*_model); + } + + return doc.write_to_string("UTF-8"); +} + string Drive::description () const @@ -46,6 +95,113 @@ Drive::description () const name = _("Unknown"); } - return String::compose(_("%1 (%2 GB) [%3]"), name, gb, _internal_name); + return String::compose(_("%1 (%2 GB) [%3]"), name, gb, _device); +} + + +string +Drive::log_summary () const +{ + string mp; + for (auto i: _mount_points) { + mp += i.string() + ","; + } + if (mp.empty()) { + mp = "[none]"; + } else { + mp = mp.substr (0, mp.length() - 1); + } + + return String::compose( + "Device %1 mounted on %2 size %3 vendor %4 model %5", + _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 +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 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() < 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 {}; + } + + return mp; +} + + +/* 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 +osx_disks_to_drives (vector 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.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 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 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; +}