File indexing completed on 2024-04-21 05:48:34

0001 /*
0002     SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@kde.org>, 2023 Jonathan Esk-Riddell <jr@jriddell.org>
0003     SPDX-License-Identifier: GPL-3.0-or-later
0004 */
0005 
0006 ////////////////////////////////////////////////////////////////////////////////
0007 // This file contains Linux implementation of platform-dependent functions
0008 
0009 #include <KLocalizedString>
0010 #include <QDBusInterface>
0011 #include <QDBusReply>
0012 #include <QDBusConnection>
0013 #include <QDBusObjectPath>
0014 #include <QtDBus/QtDBus>
0015 #include <QMessageBox>
0016 #include <QDir>
0017 #include <QRegularExpression>
0018 
0019 #include "mainapplication.h"
0020 #include "usbdevice.h"
0021 
0022 typedef QHash<QString, QVariantMap> InterfacesAndProperties;
0023 typedef QHash<QDBusObjectPath, InterfacesAndProperties> DBusIntrospection;
0024 Q_DECLARE_METATYPE(InterfacesAndProperties)
0025 Q_DECLARE_METATYPE(DBusIntrospection)
0026 
0027 UsbDevice* handleObject(const QDBusObjectPath &object_path, const InterfacesAndProperties &interfaces_and_properties) {
0028     QRegularExpression numberRE("[0-9]$");
0029     QRegularExpressionMatch numberREMatch = numberRE.match(object_path.path());
0030     QRegularExpression mmcRE("[0-9]p[0-9]$");
0031     QRegularExpressionMatch mmcREMatch = mmcRE.match(object_path.path());
0032     QDBusObjectPath driveId = qvariant_cast<QDBusObjectPath>(interfaces_and_properties["org.freedesktop.UDisks2.Block"]["Drive"]);
0033 
0034     QDBusInterface driveInterface("org.freedesktop.UDisks2", driveId.path(), "org.freedesktop.UDisks2.Drive", QDBusConnection::systemBus());
0035     UsbDevice* deviceData = new UsbDevice;
0036 
0037     if ((numberREMatch.hasMatch() && !object_path.path().startsWith("/org/freedesktop/UDisks2/block_devices/mmcblk")) ||
0038             mmcREMatch.hasMatch())
0039         return nullptr;
0040 
0041     if (!driveId.path().isEmpty() && driveId.path() != "/") {
0042         bool portable = driveInterface.property("Removable").toBool();
0043         bool optical = driveInterface.property("Optical").toBool();
0044         bool containsMedia = driveInterface.property("MediaAvailable").toBool();
0045         QString connectionBus = driveInterface.property("ConnectionBus").toString().toLower();
0046         bool isValid = containsMedia && !optical && (portable || connectionBus == "usb");
0047 
0048         QString vendor = driveInterface.property("Vendor").toString();
0049         QString model = driveInterface.property("Model").toString();
0050         uint64_t size = driveInterface.property("Size").toULongLong();
0051         //bool isoLayout = interfaces_and_properties["org.freedesktop.UDisks2.Block"]["IdType"].toString() == "iso9660";
0052 
0053         QString name;
0054         if (vendor.isEmpty())
0055             if (model.isEmpty())
0056                 name = interfaces_and_properties["org.freedesktop.UDisks2.Block"]["Device"].toByteArray();
0057             else
0058                 name = model;
0059         else
0060             if (model.isEmpty())
0061                 name = vendor;
0062             else
0063                 name = QString("%1 %2").arg(vendor).arg(model);
0064 
0065         //qDebug() << "New drive" << driveId.path() << "-" << name << "(" << size << "bytes;" << (isValid ? "removable;" : "nonremovable;") << connectionBus << ")";
0066 
0067         deviceData->m_PhysicalDevice = object_path.path();
0068         deviceData->m_Volumes = QStringList{ deviceData->m_PhysicalDevice };
0069         deviceData->m_SectorSize = 512;
0070         deviceData->m_Size = size;
0071         deviceData->m_VisibleName = name;
0072 
0073         if (isValid) {
0074             return deviceData;
0075         }
0076     }
0077     return nullptr;
0078 }
0079 
0080 bool platformEnumFlashDevices(AddFlashDeviceCallbackProc callback, void* cbParam)
0081 {
0082 
0083     qDBusRegisterMetaType<InterfacesAndProperties>();
0084     qDBusRegisterMetaType<DBusIntrospection>();
0085     QDBusInterface* m_objManager = new QDBusInterface("org.freedesktop.UDisks2", "/org/freedesktop/UDisks2", "org.freedesktop.DBus.ObjectManager", QDBusConnection::systemBus());
0086     QDBusPendingReply<DBusIntrospection> reply = m_objManager->asyncCall("GetManagedObjects");
0087     reply.waitForFinished();
0088     if (reply.isError()) {
0089         qDebug() << "Could not read drives from UDisks:" << reply.error().name() << reply.error().message();
0090         return false;
0091     }
0092     DBusIntrospection introspection = reply.argumentAt<0>();
0093     for (auto i : introspection.keys()) {
0094         // ignore anything not block device
0095         if (!i.path().startsWith("/org/freedesktop/UDisks2/block_devices")) {
0096             continue;
0097         }
0098         UsbDevice* deviceData = nullptr;
0099         deviceData = handleObject(i, introspection[i]);
0100         if (deviceData) {
0101             callback(cbParam, deviceData);
0102         }
0103     }
0104 
0105     return true;
0106 }
0107 
0108 bool ensureElevated()
0109 {
0110     // on Linux we use udisks2 which uses polkit to run necessary bits as root
0111     return true;
0112 }