/*
- Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "cross.h"
#include "compose.hpp"
+#include "dcpomatic_assert.h"
#include "dcpomatic_log.h"
#include "warnings.h"
#include <dcp/raw_convert.h>
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;
+
+
+auto constexpr MEDIA_PATH_REQUIRED_MATCHES = 3;
+
Drive::Drive (string xml)
{
Drive::as_xml () const
{
xmlpp::Document doc;
- xmlpp::Element* root = doc.create_root_node ("Drive");
+ 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());
return String::compose(_("%1 (%2 GB) [%3]"), name, gb, _device);
}
+
string
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)
+{
+ 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 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)
+{
+ 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 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;
+}