diff --git a/src/partition.h b/src/partition.h index 7b5d969..79c3190 100644 --- a/src/partition.h +++ b/src/partition.h @@ -62,7 +62,11 @@ class SYSTEMSETTINGS_EXPORT Partition Mounted, Unmounting, Formatting, - Formatted + Formatted, + Unlocking, + Unlocked, + Locking, + Locked }; Q_DECLARE_FLAGS(StorageTypes, StorageType) diff --git a/src/partitionmanager.cpp b/src/partitionmanager.cpp index 010ea6e..8ea7c61 100644 --- a/src/partitionmanager.cpp +++ b/src/partitionmanager.cpp @@ -56,6 +56,8 @@ PartitionManagerPrivate::PartitionManagerPrivate() m_udisksMonitor.reset(new UDisks2::Monitor(this)); connect(m_udisksMonitor.data(), &UDisks2::Monitor::status, this, &PartitionManagerPrivate::status); connect(m_udisksMonitor.data(), &UDisks2::Monitor::errorMessage, this, &PartitionManagerPrivate::errorMessage); + connect(m_udisksMonitor.data(), &UDisks2::Monitor::lockError, this, &PartitionManagerPrivate::lockError); + connect(m_udisksMonitor.data(), &UDisks2::Monitor::unlockError, this, &PartitionManagerPrivate::unlockError); connect(m_udisksMonitor.data(), &UDisks2::Monitor::mountError, this, &PartitionManagerPrivate::mountError); connect(m_udisksMonitor.data(), &UDisks2::Monitor::unmountError, this, &PartitionManagerPrivate::unmountError); connect(m_udisksMonitor.data(), &UDisks2::Monitor::formatError, this, &PartitionManagerPrivate::formatError); @@ -273,11 +275,33 @@ void PartitionManagerPrivate::refresh(const Partitions &partitions, Partitions & } } +void PartitionManagerPrivate::lock(const Partition &partition) +{ + qCInfo(lcMemoryCardLog) << "Can lock:" << externalMedia.match(partition.deviceName()).hasMatch() << partition.deviceName(); + if (externalMedia.match(partition.deviceName()).hasMatch()) { + m_udisksMonitor->lock(partition.deviceName()); + } else { + qCWarning(lcMemoryCardLog) << "Lock allowed only for external memory cards," << partition.devicePath() << "is not allowed"; + } +} + +void PartitionManagerPrivate::unlock(const Partition &partition, const QString &passphrase) +{ + qCInfo(lcMemoryCardLog) << "Can unlock:" << externalMedia.match(partition.deviceName()).hasMatch() << partition.deviceName(); + if (externalMedia.match(partition.deviceName()).hasMatch()) { + m_udisksMonitor->instance()->unlock(partition.deviceName(), passphrase); + } else { + qCWarning(lcMemoryCardLog) << "Unlock allowed only for external memory cards," << partition.devicePath() << "is not allowed"; + } +} + void PartitionManagerPrivate::mount(const Partition &partition) { qCInfo(lcMemoryCardLog) << "Can mount:" << externalMedia.match(partition.deviceName()).hasMatch() << partition.deviceName(); if (externalMedia.match(partition.deviceName()).hasMatch()) { - m_udisksMonitor->mount(partition.deviceName()); + m_udisksMonitor->instance()->mount(partition.deviceName()); + } else { + qCWarning(lcMemoryCardLog) << "Mount allowed only for external memory cards," << partition.devicePath() << "is not allowed"; } } diff --git a/src/partitionmanager_p.h b/src/partitionmanager_p.h index 5046c30..29857b2 100644 --- a/src/partitionmanager_p.h +++ b/src/partitionmanager_p.h @@ -66,6 +66,8 @@ class PartitionManagerPrivate : public QObject, public QSharedData void refresh(PartitionPrivate *partition); void refresh(const Partitions &partitions, Partitions &changedPartitions); + void lock(const Partition &partition); + void unlock(const Partition &partition, const QString &passphrase); void mount(const Partition &partition); void unmount(const Partition &partition); void format(const Partition &partition, const QString &type, const QString &label, const QString &passphrase); @@ -79,6 +81,8 @@ class PartitionManagerPrivate : public QObject, public QSharedData void status(const QString &deviceName, Partition::Status); void errorMessage(const QString &objectPath, const QString &errorName); + void lockError(Partition::Error error); + void unlockError(Partition::Error error); void mountError(Partition::Error error); void unmountError(Partition::Error error); void formatError(Partition::Error error); diff --git a/src/partitionmodel.cpp b/src/partitionmodel.cpp index 7de45cf..7f222fa 100644 --- a/src/partitionmodel.cpp +++ b/src/partitionmodel.cpp @@ -51,6 +51,13 @@ PartitionModel::PartitionModel(QObject *parent) connect(m_manager.data(), &PartitionManagerPrivate::errorMessage, this, &PartitionModel::errorMessage); + connect(m_manager.data(), &PartitionManagerPrivate::lockError, this, [this](Partition::Error error) { + emit lockError(static_cast(error)); + }); + connect(m_manager.data(), &PartitionManagerPrivate::unlockError, this, [this](Partition::Error error) { + emit unlockError(static_cast(error)); + }); + connect(m_manager.data(), &PartitionManagerPrivate::mountError, this, [this](Partition::Error error) { emit mountError(static_cast(error)); }); @@ -112,40 +119,94 @@ void PartitionModel::refresh(int index) } } +void PartitionModel::lock(const QString &deviceName) +{ + qCInfo(lcMemoryCardLog) << Q_FUNC_INFO << deviceName << m_partitions.count(); + + bool found = false; + for (const Partition &partition : m_partitions) { + if (deviceName == partition.deviceName()) { + found = true; + m_manager->lock(partition); + break; + } + } + + if (!found) { + qCWarning(lcMemoryCardLog) << "Unable to lock unknown device:" << deviceName; + } +} + +void PartitionModel::unlock(const QString &deviceName, const QString &passphrase) +{ + qCInfo(lcMemoryCardLog) << Q_FUNC_INFO << deviceName << m_partitions.count(); + + bool found = false; + for (const Partition &partition : m_partitions) { + if (deviceName == partition.deviceName()) { + found = true; + m_manager->unlock(partition, passphrase); + break; + } + } + + if (!found) { + qCWarning(lcMemoryCardLog) << "Unable to unlock unknown device:" << deviceName; + } +} + void PartitionModel::mount(const QString &deviceName) { qCInfo(lcMemoryCardLog) << Q_FUNC_INFO << deviceName << m_partitions.count(); + bool found = false; for (const Partition &partition : m_partitions) { if (deviceName == partition.deviceName()) { + found = true; m_manager->mount(partition); break; } } + + if (!found) { + qCWarning(lcMemoryCardLog) << "Unable to mount unknown device:" << deviceName; + } } void PartitionModel::unmount(const QString &deviceName) { qCInfo(lcMemoryCardLog) << Q_FUNC_INFO << deviceName << m_partitions.count(); + bool found = false; for (const Partition &partition : m_partitions) { if (deviceName == partition.deviceName()) { + found = true; m_manager->unmount(partition); break; } } + + if (!found) { + qCWarning(lcMemoryCardLog) << "Unable to unmount unknown device:" << deviceName; + } } void PartitionModel::format(const QString &deviceName, const QString &type, const QString &label, const QString &passphrase) { qCInfo(lcMemoryCardLog) << Q_FUNC_INFO << deviceName << type << label << m_partitions.count(); + bool found = false; for (const Partition &partition : m_partitions) { if (deviceName == partition.deviceName()) { + found = true; m_manager->format(partition, type, label, passphrase); break; } } + + if (!found) { + qCWarning(lcMemoryCardLog) << "Unable to format unknown device:" << deviceName; + } } void PartitionModel::update() diff --git a/src/partitionmodel.h b/src/partitionmodel.h index d45b4da..b10b77d 100644 --- a/src/partitionmodel.h +++ b/src/partitionmodel.h @@ -119,6 +119,8 @@ class SYSTEMSETTINGS_EXPORT PartitionModel : public QAbstractListModel Q_INVOKABLE void refresh(); Q_INVOKABLE void refresh(int index); + Q_INVOKABLE void lock(const QString &deviceName); + Q_INVOKABLE void unlock(const QString &deviceName, const QString &passphrase); Q_INVOKABLE void mount(const QString &deviceName); Q_INVOKABLE void unmount(const QString &deviceName); Q_INVOKABLE void format(const QString &deviceName, const QString &type, const QString &label, const QString &passphrase = QString()); @@ -133,6 +135,8 @@ class SYSTEMSETTINGS_EXPORT PartitionModel : public QAbstractListModel void storageTypesChanged(); void errorMessage(const QString &objectPath, const QString &errorName); + void lockError(Error error); + void unlockError(Error error); void mountError(Error error); void unmountError(Error error); void formatError(Error error); diff --git a/src/udisks2defines.h b/src/udisks2defines.h index 13c34f3..2c86140 100644 --- a/src/udisks2defines.h +++ b/src/udisks2defines.h @@ -49,6 +49,8 @@ #define UDISKS2_JOB_INTERFACE QLatin1String("org.freedesktop.UDisks2.Job") // Jobs +#define UDISKS2_JOB_OP_ENC_LOCK QLatin1String("encrypted-lock") +#define UDISKS2_JOB_OP_ENC_UNLOCK QLatin1String("encrypted-unlock") #define UDISKS2_JOB_OP_FS_UNMOUNT QLatin1String("filesystem-unmount") #define UDISKS2_JOB_OP_FS_MOUNT QLatin1String("filesystem-mount") #define UDISKS2_JOB_OP_CLEANUP QLatin1String("cleanup") @@ -61,6 +63,8 @@ // Lock, Unlock, Mount, Unmount, Format #define UDISKS2_BLOCK_DEVICE_PATH QString(QLatin1String("/org/freedesktop/UDisks2/block_devices/%1")) #define UDISKS2_BLOCK_FORMAT QLatin1String("Format") +#define UDISKS2_ENCRYPTED_LOCK QLatin1String("Lock") +#define UDISKS2_ENCRYPTED_UNLOCK QLatin1String("Unlock") #define UDISKS2_FILESYSTEM_MOUNT QLatin1String("Mount") #define UDISKS2_FILESYSTEM_UNMOUNT QLatin1String("Unmount") diff --git a/src/udisks2job.cpp b/src/udisks2job.cpp index e673e83..d27dd31 100644 --- a/src/udisks2job.cpp +++ b/src/udisks2job.cpp @@ -124,6 +124,10 @@ UDisks2::Job::Operation UDisks2::Job::operation() const return Unmount; } else if (operation == UDISKS2_JOB_OF_FS_FORMAT) { return Format; + } else if (operation == UDISKS2_JOB_OP_ENC_LOCK) { + return Lock; + } else if (operation == UDISKS2_JOB_OP_ENC_UNLOCK) { + return Unlock; } else { return Unknown; } diff --git a/src/udisks2job_p.h b/src/udisks2job_p.h index 16befd7..3f187ca 100644 --- a/src/udisks2job_p.h +++ b/src/udisks2job_p.h @@ -53,6 +53,8 @@ class Job : public QObject Q_ENUM(Status) enum Operation { + Lock, + Unlock, Mount, Unmount, Format, diff --git a/src/udisks2monitor.cpp b/src/udisks2monitor.cpp index 291e2a5..9f0497a 100644 --- a/src/udisks2monitor.cpp +++ b/src/udisks2monitor.cpp @@ -130,18 +130,42 @@ UDisks2::Monitor::~Monitor() m_jobsToWait.clear(); } +void UDisks2::Monitor::lock(const QString &deviceName) +{ + const QString objectPath(UDISKS2_BLOCK_DEVICE_PATH.arg(deviceName)); + QVariantList arguments; + QVariantMap options; + arguments << options; + startLuksOperation(deviceName, UDISKS2_ENCRYPTED_LOCK, objectPath, arguments); +} + +void UDisks2::Monitor::unlock(const QString &deviceName, const QString &passphrase) +{ + const QString objectPath(UDISKS2_BLOCK_DEVICE_PATH.arg(deviceName)); + QVariantList arguments; + arguments << passphrase; + QVariantMap options; + arguments << options; + startLuksOperation(deviceName, UDISKS2_ENCRYPTED_UNLOCK, objectPath, arguments); +} + void UDisks2::Monitor::mount(const QString &deviceName) { - QVariantHash arguments; - arguments.insert(QString("fstype"), QString()); - startMountOperation(UDISKS2_FILESYSTEM_MOUNT, deviceName, arguments); + const QString objectPath(UDISKS2_BLOCK_DEVICE_PATH.arg(deviceName)); + QVariantList arguments; + QVariantMap options; + options.insert(QStringLiteral("fstype"), QString()); + arguments << options; + startMountOperation(deviceName, UDISKS2_FILESYSTEM_MOUNT, objectPath, arguments); } void UDisks2::Monitor::unmount(const QString &deviceName) { - QVariantHash arguments; - arguments.insert(QString(), QString()); - startMountOperation(UDISKS2_FILESYSTEM_UNMOUNT, deviceName, arguments); + const QString objectPath(UDISKS2_BLOCK_DEVICE_PATH.arg(deviceName)); + QVariantList arguments; + QVariantMap options; + arguments << options; + startMountOperation(deviceName, UDISKS2_FILESYSTEM_UNMOUNT, objectPath, arguments); } void UDisks2::Monitor::format(const QString &deviceName, const QString &type, const QString &label, const QString &passphrase) @@ -165,18 +189,19 @@ void UDisks2::Monitor::format(const QString &deviceName, const QString &type, co arguments.insert(QStringLiteral("encrypt.passphrase"), passphrase); } + const QString objectPath(UDISKS2_BLOCK_DEVICE_PATH.arg(deviceName)); PartitionManagerPrivate::Partitions affectedPartions; - lookupPartitions(affectedPartions, QStringList() << UDISKS2_BLOCK_DEVICE_PATH.arg(deviceName)); + lookupPartitions(affectedPartions, QStringList() << objectPath); for (auto partition : affectedPartions) { if (partition->status == Partition::Mounted) { - m_operationQueue.enqueue(Operation(QString("format"), deviceName, type, arguments)); + m_operationQueue.enqueue(Operation(QString("format"), deviceName, objectPath, type, arguments)); unmount(deviceName); return; } } - doFormat(deviceName, type, arguments); + doFormat(deviceName, objectPath, type, arguments); } void UDisks2::Monitor::interfacesAdded(const QDBusObjectPath &objectPath, const InterfaceAndPropertyMap &interfaces) @@ -198,7 +223,9 @@ void UDisks2::Monitor::interfacesAdded(const QDBusObjectPath &objectPath, const } else if (path.startsWith(QStringLiteral("/org/freedesktop/UDisks2/jobs"))) { QVariantMap dict = interfaces.value(UDISKS2_JOB_INTERFACE); QString operation = dict.value(UDISKS2_JOB_KEY_OPERATION, QString()).toString(); - if (operation == UDISKS2_JOB_OP_FS_MOUNT || + if (operation == UDISKS2_JOB_OP_ENC_LOCK || + operation == UDISKS2_JOB_OP_ENC_UNLOCK || + operation == UDISKS2_JOB_OP_FS_MOUNT || operation == UDISKS2_JOB_OP_FS_UNMOUNT || operation == UDISKS2_JOB_OP_CLEANUP || operation == UDISKS2_JOB_OF_FS_FORMAT) { @@ -276,8 +303,27 @@ void UDisks2::Monitor::updatePartitionStatus(const UDisks2::Job *job, bool succe UDisks2::Job::Operation operation = job->operation(); PartitionManagerPrivate::Partitions affectedPartions; lookupPartitions(affectedPartions, job->value(UDISKS2_JOB_KEY_OBJECTS).toStringList()); - - if (operation == UDisks2::Job::Mount || operation == UDisks2::Job::Unmount) { + if (operation == UDisks2::Job::Lock || operation == UDisks2::Job::Unlock) { + for (auto partition : affectedPartions) { + Partition::Status oldStatus = partition->status; + if (success) { + if (job->status() == UDisks2::Job::Added) { + partition->activeState = QStringLiteral("inactive"); + partition->status = operation == UDisks2::Job::Unlock ? Partition::Unlocking : Partition::Locking; + } else { + partition->activeState = QStringLiteral("inactive"); + partition->status = operation == UDisks2::Job::Unlock ? Partition::Unmounted : Partition::Locked; + } + } else { + partition->activeState = QStringLiteral("failed"); + partition->status = operation == UDisks2::Job::Unlock ? Partition::Locked : Partition::Unmounted; + } + partition->valid = true; + if (oldStatus != partition->status) { + m_manager->refresh(partition.data()); + } + } + } else if (operation == UDisks2::Job::Mount || operation == UDisks2::Job::Unmount) { for (auto partition : affectedPartions) { Partition::Status oldStatus = partition->status; @@ -344,9 +390,70 @@ bool UDisks2::Monitor::externalBlockDevice(const QString &deviceName) const return externalBlockDevice.match(deviceName).hasMatch(); } -void UDisks2::Monitor::startMountOperation(const QString &dbusMethod, const QString &deviceName, QVariantHash arguments) +void UDisks2::Monitor::startLuksOperation(const QString &deviceName, const QString &dbusMethod, const QString &dbusObjectPath, const QVariantList &arguments) { + Q_ASSERT(dbusMethod == UDISKS2_ENCRYPTED_LOCK || dbusMethod == UDISKS2_ENCRYPTED_UNLOCK); + + if (deviceName.isEmpty()) { + qCCritical(lcMemoryCardLog) << "Cannot" << dbusMethod.toLower() << "without device name"; + return; + } + + QDBusInterface udisks2Interface(UDISKS2_SERVICE, + dbusObjectPath, + UDISKS2_ENCRYPTED_INTERFACE, + QDBusConnection::systemBus()); + + QDBusPendingCall pendingCall = udisks2Interface.asyncCallWithArgumentList(dbusMethod, arguments); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall, this); + connect(watcher, &QDBusPendingCallWatcher::finished, + this, [this, deviceName, dbusMethod](QDBusPendingCallWatcher *watcher) { + if (watcher->isValid() && watcher->isFinished()) { + if (dbusMethod == UDISKS2_ENCRYPTED_LOCK) { + emit status(deviceName, Partition::Locked); + } else { + emit status(deviceName, Partition::Unmounted); + } + } else if (watcher->isError()) { + QDBusError error = watcher->error(); + QByteArray errorData = error.name().toLocal8Bit(); + const char *errorCStr = errorData.constData(); + + qCWarning(lcMemoryCardLog) << dbusMethod << "error:" << errorCStr << error.message(); + + for (uint i = 0; i < sizeof(dbus_error_entries) / sizeof(ErrorEntry); i++) { + if (strcmp(dbus_error_entries[i].dbusErrorName, errorCStr) == 0) { + if (dbusMethod == UDISKS2_ENCRYPTED_LOCK) { + emit lockError(dbus_error_entries[i].errorCode); + break; + } else { + emit unlockError(dbus_error_entries[i].errorCode); + break; + } + } + } + + if (dbusMethod == UDISKS2_ENCRYPTED_LOCK) { + // All other errors will revert back the previous state. + emit status(deviceName, Partition::Unmounted); // TODO: could it have been in Mounted state? + } else if (dbusMethod == UDISKS2_ENCRYPTED_UNLOCK) { + // All other errors will revert back the previous state. + emit status(deviceName, Partition::Locked); + } + } + watcher->deleteLater(); + }); + + if (dbusMethod == UDISKS2_ENCRYPTED_LOCK) { + emit status(deviceName, Partition::Locking); + } else { + emit status(deviceName, Partition::Unlocking); + } +} + +void UDisks2::Monitor::startMountOperation(const QString &deviceName, const QString &dbusMethod, const QString &dbusObjectPath, const QVariantList &arguments) +{ Q_ASSERT(dbusMethod == UDISKS2_FILESYSTEM_MOUNT || dbusMethod == UDISKS2_FILESYSTEM_UNMOUNT); if (deviceName.isEmpty()) { @@ -355,11 +462,11 @@ void UDisks2::Monitor::startMountOperation(const QString &dbusMethod, const QStr } QDBusInterface udisks2Interface(UDISKS2_SERVICE, - UDISKS2_BLOCK_DEVICE_PATH.arg(deviceName), + dbusObjectPath, UDISKS2_FILESYSTEM_INTERFACE, QDBusConnection::systemBus()); - QDBusPendingCall pendingCall = udisks2Interface.asyncCall(dbusMethod, arguments); + QDBusPendingCall pendingCall = udisks2Interface.asyncCallWithArgumentList(dbusMethod, arguments); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall, this); connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, deviceName, dbusMethod](QDBusPendingCallWatcher *watcher) { @@ -515,17 +622,17 @@ void UDisks2::Monitor::createBlockDevice(const QString &path, const QVariantMap Operation op = m_operationQueue.head(); if (op.command == QStringLiteral("format") && block->mountPath().isEmpty()) { m_operationQueue.dequeue(); - doFormat(op.deviceName, op.type, op.arguments); + doFormat(op.deviceName, op.dbusObjectPath, op.type, op.arguments); } } }); } } -void UDisks2::Monitor::doFormat(const QString &deviceName, const QString &type, const QVariantHash &arguments) +void UDisks2::Monitor::doFormat(const QString &deviceName, const QString &dbusObjectPath, const QString &type, const QVariantHash &arguments) { QDBusInterface blockDeviceInterface(UDISKS2_SERVICE, - UDISKS2_BLOCK_DEVICE_PATH.arg(deviceName), + dbusObjectPath, UDISKS2_BLOCK_INTERFACE, QDBusConnection::systemBus()); diff --git a/src/udisks2monitor_p.h b/src/udisks2monitor_p.h index 342bedd..081cf9a 100644 --- a/src/udisks2monitor_p.h +++ b/src/udisks2monitor_p.h @@ -37,6 +37,7 @@ #include #include #include +#include #include "partitionmodel.h" #include "partitionmanager_p.h" @@ -56,15 +57,17 @@ class Job; struct Operation { - Operation(const QString &command, const QString &deviceName, const QString &type, const QVariantHash &arguments) + Operation(const QString &command, const QString &deviceName, const QString &dbusObjectPath, const QString &type, const QVariantHash &arguments) : command(command) , deviceName(deviceName) + , dbusObjectPath(dbusObjectPath) , type(type) , arguments(arguments) {} QString command; QString deviceName; + QString dbusObjectPath; QString type; QVariantHash arguments; }; @@ -78,6 +81,9 @@ class Monitor : public QObject static Monitor *instance(); + void lock(const QString &deviceName); + void unlock(const QString &deviceName, const QString &passphrase); + void mount(const QString &deviceName); void unmount(const QString &deviceName); @@ -86,6 +92,8 @@ class Monitor : public QObject signals: void status(const QString &deviceName, Partition::Status); void errorMessage(const QString &objectPath, const QString &errorName); + void lockError(Partition::Error error); + void unlockError(Partition::Error error); void mountError(Partition::Error error); void unmountError(Partition::Error error); void formatError(Partition::Error error); @@ -100,13 +108,14 @@ private slots: void updatePartitionStatus(const UDisks2::Job *job, bool success); bool externalBlockDevice(const QString &objectPathStr) const; - void startMountOperation(const QString &dbusMethod, const QString &deviceName, QVariantHash arguments); + void startLuksOperation(const QString &deviceName, const QString &dbusMethod, const QString &dbusObjectPath, const QVariantList &arguments); + void startMountOperation(const QString &deviceName, const QString &dbusMethod, const QString &dbusObjectPath, const QVariantList &arguments); void lookupPartitions(PartitionManagerPrivate::Partitions &affectedPartions, const QStringList &objects); void createPartition(const Block *block); void createBlockDevice(const QString &path, const QVariantMap &dict); - void doFormat(const QString &deviceName, const QString &type, const QVariantHash &arguments); + void doFormat(const QString &deviceName, const QString &dbusObjectPath, const QString &type, const QVariantHash &arguments); void getBlockDevices(); private: