Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[systemsettings] Cleanup unwanted partitions. Contributes to JB#40936
External block device are now read through udisks2 upon
PartitionModel creation. This guarantees that all block devices
will have also file system interface. For instance now memory sticks
that do not have partition table but formatted directly will be
shown as well.

In future, similar approach should be take for encrypted devices.
  • Loading branch information
rainemak committed Aug 24, 2018
1 parent 27b75fc commit 5772467
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 166 deletions.
115 changes: 37 additions & 78 deletions src/partitionmanager.cpp
Expand Up @@ -71,8 +71,7 @@ PartitionManagerPrivate::PartitionManagerPrivate()
home->mountPath = QStringLiteral("/home");

m_partitions.append(home);

refresh();
refresh(m_partitions, m_partitions);

// Remove any prospective internal partitions that aren't mounted.
int internalPartitionCount = 0;
Expand Down Expand Up @@ -105,8 +104,6 @@ PartitionManagerPrivate::PartitionManagerPrivate()
if (root->status == Partition::Mounted) {
m_root = Partition(QExplicitlySharedDataPointer<PartitionPrivate>(root));
}

m_udisksMonitor->getBlockDevices();
}

PartitionManagerPrivate::~PartitionManagerPrivate()
Expand Down Expand Up @@ -147,85 +144,41 @@ QVector<Partition> PartitionManagerPrivate::partitions(const Partition::StorageT
return partitions;
}

void PartitionManagerPrivate::refresh()
void PartitionManagerPrivate::add(Partitions &partitions)
{
int index;
for (index = 0; index < m_partitions.count(); ++index) {
if (m_partitions.at(index)->storageType == Partition::External) {
break;
}
}

Partitions addedPartitions;
Partitions changedPartitions;

QFile partitionFile(QStringLiteral("/proc/partitions"));
if (partitionFile.open(QIODevice::ReadOnly)) {
// Read headers.
partitionFile.readLine();
partitionFile.readLine();

static const QRegularExpression whitespace(QStringLiteral("\\s+"));
static const QRegularExpression deviceRoot(QStringLiteral("^mmcblk\\d+$"));
m_partitions.append(partitions);
refresh(partitions, partitions);

while (!partitionFile.atEnd()) {
QStringList line = QString::fromUtf8(partitionFile.readLine()).split(whitespace, QString::SkipEmptyParts);

if (line.count() != 4) {
continue;
}

const QString deviceName = line.at(3);
for (const auto partition : partitions) {
emit partitionAdded(Partition(partition));
}
}

if (!externalMedia.match(deviceName).hasMatch()) {
continue;
void PartitionManagerPrivate::remove(const Partitions &partitions)
{
for (const auto removedPartition : partitions) {
for (int i = m_partitions.count() - 1; i >= 0 && m_partitions.at(i)->storageType == Partition::External; --i) {
const auto partition = m_partitions.at(i);
if (removedPartition->devicePath == partition->devicePath) {
m_partitions.removeAt(i);
}

const auto partition = [&]() {
for (int i = index; i < m_partitions.count(); ++i) {
const auto partition = m_partitions.at(i);
if (partition->deviceName == deviceName) {
if (index != i) {
m_partitions.removeAt(i);
m_partitions.insert(index, partition);
}

changedPartitions.append(partition);

return partition;
}
}
QExplicitlySharedDataPointer<PartitionPrivate> partition(new PartitionPrivate(this));
partition->storageType = Partition::External;
partition->deviceName = deviceName;
partition->devicePath = QStringLiteral("/dev/") + deviceName;
partition->deviceRoot = deviceRoot.match(deviceName).hasMatch();

m_partitions.insert(index, partition);
addedPartitions.append(partition);

return partition;
}();

partition->bytesTotal = line.at(2).toInt() * 1024;

++index;
}
}

const auto removedPartitions = m_partitions.mid(index);
m_partitions.resize(index);

refresh(m_partitions, changedPartitions);

for (const auto partition : removedPartitions) {
emit partitionRemoved(Partition(partition));
emit partitionRemoved(Partition(removedPartition));
}
}

for (const auto partition : addedPartitions) {
emit partitionAdded(Partition(partition));
void PartitionManagerPrivate::refresh()
{
Partitions changedPartitions;
for (int index = 0; index < m_partitions.count(); ++index) {
const auto partition = m_partitions.at(index);
if (partition->storageType == Partition::External) {
changedPartitions.append(partition);
}
}

refresh(m_partitions, changedPartitions);
for (const auto partition : changedPartitions) {
emit partitionChanged(Partition(partition));
}
Expand All @@ -246,9 +199,11 @@ void PartitionManagerPrivate::refresh(const Partitions &partitions, Partitions &
partition->bytesFree = 0;
partition->bytesAvailable = 0;
if (!partition->valid) {
partition->status = partition->activeState == QStringLiteral("activating")
? Partition::Mounting
: Partition::Unmounted;
if (partition->status != Partition::Formatting) {
partition->status = partition->activeState == QStringLiteral("activating")
? Partition::Mounting
: Partition::Unmounted;
}
partition->canMount = false;
partition->readOnly = true;
partition->filesystemType.clear();
Expand All @@ -266,7 +221,7 @@ void PartitionManagerPrivate::refresh(const Partitions &partitions, Partitions &

const QString mountPath = QString::fromUtf8(mountEntry.mnt_dir);
const QString devicePath = QString::fromUtf8(mountEntry.mnt_fsname);

const QString deviceName = devicePath.section(QChar('/'), 2);

for (auto partition : partitions) {
if (partition->valid || ((partition->status == Partition::Mounted || partition->status == Partition::Mounting) &&
Expand All @@ -282,6 +237,10 @@ void PartitionManagerPrivate::refresh(const Partitions &partitions, Partitions &
&& partition->devicePath == devicePath)) {
partition->mountPath = mountPath;
partition->devicePath = devicePath;
// There two values wrong for system partitions as devicePath will not start with mmcblk.
// Currently deviceName and deviceRoot are merely informative data fields.
partition->deviceName = deviceName;
partition->deviceRoot = deviceRoot.match(deviceName).hasMatch();
partition->filesystemType = QString::fromUtf8(mountEntry.mnt_type);
partition->status = partition->activeState == QStringLiteral("deactivating")
? Partition::Unmounting
Expand All @@ -292,7 +251,7 @@ void PartitionManagerPrivate::refresh(const Partitions &partitions, Partitions &
}

endmntent(mtab);

for (auto partition : partitions) {
if (partition->status == Partition::Mounted) {
struct statvfs64 stat;
Expand Down
5 changes: 4 additions & 1 deletion src/partitionmanager_p.h
Expand Up @@ -43,7 +43,7 @@ namespace UDisks2 {
class Monitor;
}

static const auto externalDevice = QStringLiteral("mmcblk(?!0)\\d+(?:p\\d+$)?|(sd[a-z]\\d+)");
static const auto externalDevice = QStringLiteral("mmcblk(?!0)\\d+(?:p\\d+$)?|(sd[a-z]\\d*)");

class PartitionManagerPrivate : public QObject, public QSharedData
{
Expand All @@ -59,6 +59,9 @@ class PartitionManagerPrivate : public QObject, public QSharedData
Partition root() const;
QVector<Partition> partitions(Partition::StorageTypes types) const;

void add(Partitions &partitions);
void remove(const Partitions &partitions);

void refresh();
void refresh(PartitionPrivate *partition);
void refresh(const Partitions &partitions, Partitions &changedPartitions);
Expand Down
36 changes: 29 additions & 7 deletions src/udisks2block.cpp
Expand Up @@ -12,6 +12,9 @@ UDisks2::Block::Block(const QString &path, const QVariantMap &data, QObject *par
, m_path(path)
, m_data(data)
, m_connection(QDBusConnection::systemBus())
, m_mountable(false)
, m_pendingFileSystem(nullptr)
, m_pendingBlock(nullptr)
{
if (!m_connection.connect(
UDISKS2_SERVICE,
Expand All @@ -28,36 +31,42 @@ UDisks2::Block::Block(const QString &path, const QVariantMap &data, QObject *par
DBUS_OBJECT_PROPERTIES_INTERFACE,
m_connection);
QDBusPendingCall pendingCall = dbusPropertyInterface.asyncCall(DBUS_GET_ALL, UDISKS2_FILESYSTEM_INTERFACE);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, path](QDBusPendingCallWatcher *watcher) {
m_pendingFileSystem = new QDBusPendingCallWatcher(pendingCall, this);
connect(m_pendingFileSystem, &QDBusPendingCallWatcher::finished, this, [this, path](QDBusPendingCallWatcher *watcher) {
if (watcher->isValid() && watcher->isFinished()) {
QDBusPendingReply<> reply = *watcher;
QDBusMessage message = reply.reply();
m_mountable = true;
updateMountPoint(message.arguments().at(0));
} else {
QDBusError error = watcher->error();
qCWarning(lcMemoryCardLog) << "Error reading filesystem properties:" << error.name() << error.message();
qCWarning(lcMemoryCardLog) << "Error reading filesystem properties:" << error.name() << error.message() << path;
}
watcher->deleteLater();
m_pendingFileSystem = nullptr;
complete();
});

if (data.isEmpty()) {
pendingCall = dbusPropertyInterface.asyncCall(DBUS_GET_ALL, UDISKS2_BLOCK_INTERFACE);
watcher = new QDBusPendingCallWatcher(pendingCall, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, path](QDBusPendingCallWatcher *watcher) {
m_pendingBlock = new QDBusPendingCallWatcher(pendingCall, this);
connect(m_pendingBlock, &QDBusPendingCallWatcher::finished, this, [this, path](QDBusPendingCallWatcher *watcher) {
if (watcher->isValid() && watcher->isFinished()) {
QDBusPendingReply<> reply = *watcher;
QDBusMessage message = reply.reply();
QVariantMap blockProperties = NemoDBus::demarshallArgument<QVariantMap>(message.arguments().at(0));
qCInfo(lcMemoryCardLog) << "Block properties:" << blockProperties;
m_data = blockProperties;
emit blockUpdated();
} else {
QDBusError error = watcher->error();
qCWarning(lcMemoryCardLog) << "Error reading block properties:" << error.name() << error.message();
}
watcher->deleteLater();
m_pendingBlock = nullptr;
complete();
});
} else {
complete();
}
}

Expand Down Expand Up @@ -102,6 +111,11 @@ qint64 UDisks2::Block::size() const
return value(QStringLiteral("Size")).toLongLong();
}

bool UDisks2::Block::isMountable() const
{
return m_mountable;
}

bool UDisks2::Block::isReadOnly() const
{
return value(QStringLiteral("ReadOnly")).toBool();
Expand Down Expand Up @@ -152,8 +166,9 @@ void UDisks2::Block::updateProperties(const QDBusMessage &message)
for (QMap<QString, QVariant>::const_iterator i = changedProperties.begin(); i != changedProperties.end(); ++i) {
m_data.insert(i.key(), i.value());
}
emit blockUpdated();
emit updated();
} else if (interface == UDISKS2_FILESYSTEM_INTERFACE) {
m_mountable = true;
updateMountPoint(arguments.value(1));
}
}
Expand All @@ -174,3 +189,10 @@ void UDisks2::Block::updateMountPoint(const QVariant &mountPoints)
qCInfo(lcMemoryCardLog) << "New file system mount points:" << mountPoints << "resolved mount path: " << m_mountPath;
emit mountPathChanged();
}

void UDisks2::Block::complete()
{
if (!m_pendingFileSystem && !m_pendingBlock) {
QMetaObject::invokeMethod(this, "completed", Qt::QueuedConnection);
}
}
12 changes: 11 additions & 1 deletion src/udisks2block_p.h
Expand Up @@ -36,6 +36,8 @@
#include <QVariantMap>
#include <QDBusConnection>

class QDBusPendingCallWatcher;

namespace UDisks2 {

class Block : public QObject
Expand All @@ -57,6 +59,8 @@ class Block : public QObject

qint64 size() const;

bool isMountable() const;

bool isReadOnly() const;

QString idType() const;
Expand All @@ -71,19 +75,25 @@ class Block : public QObject
bool hasData() const;

signals:
void blockUpdated();
void completed();
void updated();
void mountPathChanged();

private slots:
void updateProperties(const QDBusMessage &message);

private:
void updateMountPoint(const QVariant &mountPoints);
void complete();

QString m_path;
QVariantMap m_data;
QDBusConnection m_connection;
QString m_mountPath;
bool m_mountable;

QDBusPendingCallWatcher *m_pendingFileSystem;
QDBusPendingCallWatcher *m_pendingBlock;
};

}
Expand Down
8 changes: 5 additions & 3 deletions src/udisks2defines.h
Expand Up @@ -36,10 +36,12 @@
#define DBUS_OBJECT_PROPERTIES_INTERFACE QLatin1String("org.freedesktop.DBus.Properties")
#define DBUS_GET_ALL QLatin1String("GetAll")

#define UDISKS2_SERVICE QLatin1String("org.freedesktop.UDisks2")
#define UDISKS2_PATH QLatin1String("/org/freedesktop/UDisks2")
#define UDISKS2_SERVICE QLatin1String("org.freedesktop.UDisks2")
#define UDISKS2_PATH QLatin1String("/org/freedesktop/UDisks2")
#define UDISKS2_MANAGER_PATH QLatin1String("/org/freedesktop/UDisks2/Manager")

// Interfaces
#define UDISKS2_MANAGER_INTERFACE QLatin1String("org.freedesktop.UDisks2.Manager")
#define UDISKS2_BLOCK_INTERFACE QLatin1String("org.freedesktop.UDisks2.Block")
#define UDISKS2_FILESYSTEM_INTERFACE QLatin1String("org.freedesktop.UDisks2.Filesystem")
#define UDISKS2_PARTITION_INTERFACE QLatin1String("org.freedesktop.UDisks2.Partition")
Expand All @@ -56,7 +58,7 @@
#define UDISKS2_JOB_KEY_OBJECTS QLatin1String("Objects")

// Mount, Unmount, Format
#define UDISKS2_BLOCK_DEVICE_PATH QString("/org/freedesktop/UDisks2/block_devices/%1")
#define UDISKS2_BLOCK_DEVICE_PATH QString(QLatin1String("/org/freedesktop/UDisks2/block_devices/%1"))
#define UDISKS2_BLOCK_FORMAT QLatin1String("Format")
#define UDISKS2_FILESYSTEM_MOUNT QLatin1String("Mount")
#define UDISKS2_FILESYSTEM_UNMOUNT QLatin1String("Unmount")
Expand Down
4 changes: 2 additions & 2 deletions src/udisks2job.cpp
Expand Up @@ -32,9 +32,9 @@
#include "udisks2job_p.h"
#include "udisks2monitor_p.h"
#include "udisks2defines.h"
#include "logging_p.h"

#include <QDBusConnection>
#include <QDebug>

#include <nemo-dbus/dbus.h>

Expand All @@ -54,7 +54,7 @@ UDisks2::Job::Job(const QString &path, const QVariantMap &data, QObject *parent)
QStringLiteral("Completed"),
this,
SLOT(updateCompleted(bool, QString)))) {
qWarning("Failed to connect to Job's at path %p completed signal: %s: ", qPrintable(m_path), qPrintable(m_connection.lastError().message()));
qCWarning(lcMemoryCardLog) << "Failed to connect to Job's at path" << qPrintable(m_path) << "completed signal" << qPrintable(m_connection.lastError().message());
}

connect(Monitor::instance(), &Monitor::errorMessage, this, [this](const QString &objectPath, const QString &errorName) {
Expand Down

0 comments on commit 5772467

Please sign in to comment.