8#include "udisksstorageaccess.h"
10#include "udisks_debug.h"
12#include <QDBusConnection>
13#include <QDBusInterface>
14#include <QDBusMetaType>
16#include <QGuiApplication>
19#include <config-solid.h>
24struct AvailableAnswer {
28Q_DECLARE_METATYPE(AvailableAnswer)
33 argument << answer.checkResult << answer.binaryName;
41 argument >> answer.checkResult >> answer.binaryName;
46using namespace Solid::Backends::UDisks2;
48StorageAccess::StorageAccess(Device *device)
49 : DeviceInterface(device)
50 , m_setupInProgress(false)
51 , m_teardownInProgress(false)
52 , m_repairInProgress(false)
53 , m_passphraseRequested(false)
55 qDBusRegisterMetaType<AvailableAnswer>();
57 connect(device, SIGNAL(changed()),
this, SLOT(checkAccessibility()));
65StorageAccess::~StorageAccess()
69void StorageAccess::connectDBusSignals()
71 m_device->registerAction(QStringLiteral(
"setup"),
this, SLOT(slotSetupRequested()), SLOT(slotSetupDone(
int, QString)));
73 m_device->registerAction(QStringLiteral(
"teardown"),
this, SLOT(slotTeardownRequested()), SLOT(slotTeardownDone(
int, QString)));
75 m_device->registerAction(QStringLiteral(
"repair"),
this, SLOT(slotRepairRequested()), SLOT(slotRepairDone(
int, QString)));
78bool StorageAccess::isLuksDevice()
const
80 return m_device->isEncryptedContainer();
83bool StorageAccess::isAccessible()
const
86 const QString
path = clearTextPath();
91 Device holderDevice(path);
92 return holderDevice.isMounted();
95 return m_device->isMounted();
98bool StorageAccess::isEncrypted()
const
102 return isLuksDevice() || m_device->isEncryptedCleartext();
105bool StorageAccess::canCheck()
const
107 const auto idType = m_device->prop(QStringLiteral(
"IdType")).toString();
110 QStringLiteral(UD2_DBUS_PATH_MANAGER),
111 QStringLiteral(
"org.freedesktop.UDisks2.Manager"),
112 QStringLiteral(
"CanCheck"));
114 QDBusReply<AvailableAnswer> r = c.call(msg);
116 qCDebug(UDISKS2) << Q_FUNC_INFO << dbusPath() << idType <<
"DBus error, code" << r.
error().
type();
120 const bool ret = r.value().checkResult;
121 qCDebug(UDISKS2) << Q_FUNC_INFO << dbusPath() << idType << ret << r.value().binaryName;
125bool StorageAccess::check()
127 if (m_setupInProgress || m_teardownInProgress) {
131 const auto path = dbusPath();
133 auto msg =
QDBusMessage::createMethodCall(QStringLiteral(UD2_DBUS_SERVICE), path, QStringLiteral(UD2_DBUS_INTERFACE_FILESYSTEM), QStringLiteral(
"Check"));
136 QDBusReply<bool> r = c.call(msg);
137 bool ret = r.
isValid() && r.value();
138 qCDebug(UDISKS2) << Q_FUNC_INFO <<
path << ret;
142bool StorageAccess::canRepair()
const
144 const auto idType = m_device->prop(QStringLiteral(
"IdType")).toString();
147 QStringLiteral(UD2_DBUS_PATH_MANAGER),
148 QStringLiteral(
"org.freedesktop.UDisks2.Manager"),
149 QStringLiteral(
"CanRepair"));
151 QDBusReply<AvailableAnswer> r = c.call(msg);
153 qCDebug(UDISKS2) << Q_FUNC_INFO << dbusPath() << idType <<
"DBus error, code" << r.
error().
type();
157 const bool ret = r.value().checkResult;
158 qCDebug(UDISKS2) << Q_FUNC_INFO << dbusPath() << idType << ret << r.value().binaryName;
162bool StorageAccess::repair()
164 if (m_teardownInProgress || m_setupInProgress || m_repairInProgress) {
167 m_repairInProgress =
true;
168 m_device->broadcastActionRequested(QStringLiteral(
"repair"));
170 const auto path = dbusPath();
172 auto msg =
QDBusMessage::createMethodCall(QStringLiteral(UD2_DBUS_SERVICE), path, QStringLiteral(UD2_DBUS_INTERFACE_FILESYSTEM), QStringLiteral(
"Repair"));
176 qCDebug(UDISKS2) << Q_FUNC_INFO <<
path;
177 return c.callWithCallback(msg,
this, SLOT(slotDBusReply(QDBusMessage)), SLOT(slotDBusError(QDBusError)));
180static QString baseMountPoint(
const QByteArray &dev)
187 if (
struct libmnt_table *table = mnt_new_table()) {
189 if (mnt_table_parse_mtab(table,
"/proc/self/mountinfo") == 0) {
191 struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_BACKWARD);
192 struct libmnt_fs *fs;
194 const QByteArray devicePath = dev.
endsWith(
'\x00') ? dev.
chopped(1) : dev;
196 while (mnt_table_next_fs(table, itr, &fs) == 0) {
197 if (mnt_fs_get_srcpath(fs) == devicePath
198 && (qstrcmp(mnt_fs_get_root(fs),
"/") == 0)
208 mnt_free_table(table);
217QString StorageAccess::filePath()
const
219 if (isLuksDevice()) {
220 const QString
path = clearTextPath();
221 if (
path.
isEmpty() || path == QLatin1String(
"/")) {
224 Device holderDevice(path);
225 const auto mntPoints = qdbus_cast<QByteArrayList>(holderDevice.prop(QStringLiteral(
"MountPoints")));
226 if (!mntPoints.isEmpty()) {
227 QByteArray first = mntPoints.first();
237 const auto mntPoints = qdbus_cast<QByteArrayList>(m_device->prop(QStringLiteral(
"MountPoints")));
238 if (mntPoints.isEmpty()) {
242 QByteArray first = mntPoints.
first();
248 if (mntPoints.size() == 1) {
249 return potentialMountPoint;
253 const QString basePoint = baseMountPoint(m_device->prop(QStringLiteral(
"Device")).toByteArray());
255 return !basePoint.
isEmpty() ? basePoint : potentialMountPoint;
258bool StorageAccess::isIgnored()
const
260 if (m_device->prop(QStringLiteral(
"HintIgnore")).toBool()) {
264 const QStringList mountOptions = m_device->prop(QStringLiteral(
"UserspaceMountOptions")).toStringList();
265 if (mountOptions.
contains(QLatin1String(
"x-gdu.hide"))) {
269 const QString
path = filePath();
271 const bool inUserPath = (
path.
startsWith(QLatin1String(
"/media/"))
277bool StorageAccess::setup()
279 if (m_teardownInProgress || m_setupInProgress || m_repairInProgress) {
282 m_setupInProgress =
true;
283 m_device->broadcastActionRequested(QStringLiteral(
"setup"));
285 if (m_device->isEncryptedContainer() && clearTextPath().isEmpty()) {
286 return requestPassphrase();
292bool StorageAccess::teardown()
294 if (m_teardownInProgress || m_setupInProgress || m_repairInProgress) {
297 m_teardownInProgress =
true;
298 m_device->broadcastActionRequested(QStringLiteral(
"teardown"));
303void StorageAccess::updateCache()
305 m_isAccessible = isAccessible();
308void StorageAccess::checkAccessibility()
310 const bool old_isAccessible = m_isAccessible;
313 if (old_isAccessible != m_isAccessible) {
314 Q_EMIT accessibilityChanged(m_isAccessible, m_device->udi());
318void StorageAccess::slotDBusReply(
const QDBusMessage & )
320 if (m_setupInProgress) {
321 if (isLuksDevice() && !isAccessible()) {
324 m_setupInProgress =
false;
325 m_device->invalidateCache();
326 m_device->broadcastActionDone(QStringLiteral(
"setup"));
328 checkAccessibility();
330 }
else if (m_teardownInProgress) {
331 const QString ctPath = clearTextPath();
332 qCDebug(UDISKS2) <<
"Successfully unmounted " << m_device->udi();
333 if (isLuksDevice() && !ctPath.
isEmpty() && ctPath != QStringLiteral(
"/")) {
334 callCryptoTeardown();
335 }
else if (!ctPath.
isEmpty() && ctPath != QStringLiteral(
"/")) {
336 callCryptoTeardown(
true);
339 QString drivePath = m_device->drivePath();
340 if (!drivePath.
isEmpty() || drivePath != QStringLiteral(
"/")) {
341 Device drive(drivePath);
344 if (drive.prop(QStringLiteral(
"MediaRemovable")).toBool()
345 && drive.prop(QStringLiteral(
"MediaAvailable")).toBool()
346 && !m_device->isOpticalDisc()) {
349 QStringLiteral(UD2_DBUS_INTERFACE_DRIVE),
350 QStringLiteral(
"Eject"));
351 msg << QVariantMap();
353 }
else if (drive.prop(QStringLiteral(
"CanPowerOff")).toBool()
354 && !m_device->isOpticalDisc()) {
355 qCDebug(UDISKS2) <<
"Drive can power off:" << drivePath;
358 QStringLiteral(UD2_DBUS_INTERFACE_DRIVE),
359 QStringLiteral(
"PowerOff"));
360 msg << QVariantMap();
365 m_teardownInProgress =
false;
366 m_device->invalidateCache();
367 m_device->broadcastActionDone(QStringLiteral(
"teardown"));
369 checkAccessibility();
371 }
else if (m_repairInProgress) {
372 qCDebug(UDISKS2) <<
"Successfully repaired " << m_device->udi();
373 m_repairInProgress =
false;
374 m_device->broadcastActionDone(QStringLiteral(
"repair"));
378void StorageAccess::slotDBusError(
const QDBusError &error)
382 if (m_setupInProgress) {
383 m_setupInProgress =
false;
384 m_device->broadcastActionDone(QStringLiteral(
"setup"),
385 m_device->errorToSolidError(
error.name()),
386 m_device->errorToString(
error.name()) + QStringLiteral(
": ") +
error.message());
388 checkAccessibility();
389 }
else if (m_teardownInProgress) {
390 m_teardownInProgress =
false;
391 m_device->broadcastActionDone(QStringLiteral(
"teardown"),
392 m_device->errorToSolidError(
error.name()),
393 m_device->errorToString(
error.name()) + QStringLiteral(
": ") +
error.message());
394 checkAccessibility();
395 }
else if (m_repairInProgress) {
396 m_repairInProgress =
false;
397 m_device->broadcastActionDone(QStringLiteral(
"repair"),
398 m_device->errorToSolidError(
error.name()),
399 m_device->errorToString(
error.name()) + QStringLiteral(
": ") +
error.message());
403void StorageAccess::slotSetupRequested()
405 m_setupInProgress =
true;
407 Q_EMIT setupRequested(m_device->udi());
410void StorageAccess::slotSetupDone(
int error,
const QString &errorString)
412 m_setupInProgress =
false;
414 checkAccessibility();
415 Q_EMIT setupDone(
static_cast<Solid::ErrorType
>(error), errorString, m_device->udi());
418void StorageAccess::slotTeardownRequested()
420 m_teardownInProgress =
true;
421 Q_EMIT teardownRequested(m_device->udi());
424void StorageAccess::slotTeardownDone(
int error,
const QString &errorString)
426 m_teardownInProgress =
false;
427 checkAccessibility();
428 Q_EMIT teardownDone(
static_cast<Solid::ErrorType
>(error), errorString, m_device->udi());
431void StorageAccess::slotRepairRequested()
433 m_repairInProgress =
true;
434 Q_EMIT repairRequested(m_device->udi());
437void StorageAccess::slotRepairDone(
int error,
const QString &errorString)
439 m_repairInProgress =
false;
440 Q_EMIT repairDone(
static_cast<Solid::ErrorType
>(error), errorString, m_device->udi());
443bool StorageAccess::mount()
445 const auto path = dbusPath();
452 if (m_device->prop(QStringLiteral(
"IdType")).
toString() == QLatin1String(
"vfat")) {
453 options.insert(QStringLiteral(
"options"), QStringLiteral(
"flush"));
458 return c.
callWithCallback(msg,
this, SLOT(slotDBusReply(QDBusMessage)), SLOT(slotDBusError(QDBusError)));
461bool StorageAccess::unmount()
463 const auto path = dbusPath();
469 msg << QVariantMap();
471 qCDebug(UDISKS2) <<
"Initiating unmount of " <<
path;
472 return c.
callWithCallback(msg,
this, SLOT(slotDBusReply(QDBusMessage)), SLOT(slotDBusError(QDBusError)), s_unmountTimeout);
475QString StorageAccess::generateReturnObjectPath()
477 static QAtomicInt
number = 1;
479 return QStringLiteral(
"/org/kde/solid/UDisks2StorageAccess_") +
QString::number(number++);
482QString StorageAccess::clearTextPath()
const
484 const QString
path = m_device->prop(QStringLiteral(
"CleartextDevice")).value<QDBusObjectPath>().
path();
485 if (path != QLatin1String(
"/")) {
491QString StorageAccess::dbusPath()
const
493 QString
path = m_device->udi();
494 if (isLuksDevice()) {
495 const QString ctPath = clearTextPath();
503bool StorageAccess::requestPassphrase()
505 QString udi = m_device->udi();
507 m_lastReturnObject = generateReturnObjectPath();
515 if (activeWindow !=
nullptr) {
516 wId = (uint)activeWindow->winId();
521 const auto plasmaVersionMajor = qEnvironmentVariable(
"KDE_SESSION_VERSION", QStringLiteral(
"6"));
524 QDBusInterface soliduiserver(QStringLiteral(
"org.kde.kded") + plasmaVersionMajor,
525 QStringLiteral(
"/modules/soliduiserver"),
526 QStringLiteral(
"org.kde.SolidUiServer"));
527 QDBusReply<void> reply = soliduiserver.call(QStringLiteral(
"showPassphraseDialog"), udi, returnService, m_lastReturnObject, wId, appId);
528 m_passphraseRequested = reply.
isValid();
529 if (!m_passphraseRequested) {
530 qCWarning(UDISKS2) <<
"Failed to call the SolidUiServer, D-Bus said:" << reply.
error();
533 return m_passphraseRequested;
536void StorageAccess::passphraseReply(
const QString &passphrase)
538 if (m_passphraseRequested) {
540 m_passphraseRequested =
false;
542 callCryptoSetup(passphrase);
544 m_setupInProgress =
false;
545 m_device->broadcastActionDone(QStringLiteral(
"setup"), Solid::UserCanceled);
550void StorageAccess::callCryptoSetup(
const QString &passphrase)
555 QStringLiteral(UD2_DBUS_INTERFACE_ENCRYPTED),
556 QStringLiteral(
"Unlock"));
559 msg << QVariantMap();
561 c.
callWithCallback(msg,
this, SLOT(slotDBusReply(QDBusMessage)), SLOT(slotDBusError(QDBusError)));
564bool StorageAccess::callCryptoTeardown(
bool actOnParent)
569 actOnParent ? (m_device->prop(QStringLiteral(
"CryptoBackingDevice")).value<QDBusObjectPath>().
path()) : m_device->udi(),
570 QStringLiteral(UD2_DBUS_INTERFACE_ENCRYPTED),
571 QStringLiteral(
"Lock"));
572 msg << QVariantMap();
574 return c.
callWithCallback(msg,
this, SLOT(slotDBusReply(QDBusMessage)), SLOT(slotDBusError(QDBusError)));
577#include "moc_udisksstorageaccess.cpp"
char * toString(const EngineQuery &query)
KIOCORE_EXPORT QString number(KIO::filesize_t size)
QString path(const QString &relativePath)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QByteArray chopped(qsizetype len) const const
bool endsWith(QByteArrayView bv) const const
QByteArray first(qsizetype n) const const
QString baseService() const const
QDBusMessage call(const QDBusMessage &message, QDBus::CallMode mode, int timeout) const const
bool callWithCallback(const QDBusMessage &message, QObject *receiver, const char *returnMethod, const char *errorMethod, int timeout) const const
bool registerObject(const QString &path, QObject *object, RegisterOptions options)
QDBusConnection sessionBus()
QDBusConnection systemBus()
void unregisterObject(const QString &path, UnregisterMode mode)
ErrorType type() const const
QDBusMessage createMethodCall(const QString &service, const QString &path, const QString &interface, const QString &method)
const QDBusError & error()
bool isValid() const const
QString decodeName(const QByteArray &localFileName)
bool isEmpty() const const
QString number(double n, char format, int precision)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)