Skip to content

Commit

Permalink
[nemo-qml-plugin-systemsettings] Add removable storage model. Contrib…
Browse files Browse the repository at this point in the history
…utes to MER#1334

Add a simple removable media model. The available removable media is
currently limit to /dev/mmcblk1* devices. This is to match what
sd-utils (git@github.com:nemomobile/sd-utils.git) supports.
  • Loading branch information
Aaron McCarthy committed Oct 2, 2015
1 parent 8e98f8c commit 53c72f5
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 43 deletions.
180 changes: 138 additions & 42 deletions src/aboutsettings.cpp
Expand Up @@ -46,7 +46,10 @@
#include <mntent.h>


static QMap<QString, QString> parseReleaseFile(const QString &filename)
namespace
{

QMap<QString, QString> parseReleaseFile(const QString &filename)
{
QMap<QString, QString> result;

Expand Down Expand Up @@ -115,14 +118,67 @@ static QMap<QString, QString> parseReleaseFile(const QString &filename)
return result;
}

struct StorageInfo {
StorageInfo()
: partitionSize(0), external(false)
{ }

QString mountPath;
QString devicePath;
QString filesystem;
quint64 partitionSize;
bool external;
};

QMap<QString, StorageInfo> parseExternalPartitions()
{
QMap<QString, StorageInfo> devices;

QFile partitions(QStringLiteral("/proc/partitions"));
if (!partitions.open(QIODevice::ReadOnly))
return devices;

// Read file headers
partitions.readLine();
partitions.readLine();

while (!partitions.atEnd()) {
QByteArray line = partitions.readLine().trimmed();

int nameIndex = line.lastIndexOf(' ');
if (nameIndex <= 0)
continue;

int sizeIndex = line.lastIndexOf(' ', nameIndex - 1);
if (sizeIndex == -1)
continue;

QByteArray size = line.mid(sizeIndex+1, nameIndex - sizeIndex - 1);
QByteArray name = line.mid(nameIndex+1);

if (name.startsWith("mmcblk1")) {
// If adding a partition remove the whole device.
devices.remove(QStringLiteral("/dev/mmcblk1"));

StorageInfo info;
info.devicePath = QStringLiteral("/dev/") + QString::fromLatin1(name);
info.partitionSize = size.toULongLong() * 1024;
info.external = true;

devices.insert(info.devicePath, info);
}
}

return devices;
}

}

AboutSettings::AboutSettings(QObject *parent)
: QObject(parent),
m_sysinfo(new QStorageInfo(this)),
m_netinfo(new QNetworkInfo(this)),
m_devinfo(new QDeviceInfo(this))
: QObject(parent), m_sysinfo(new QStorageInfo(this)), m_netinfo(new QNetworkInfo(this)),
m_devinfo(new QDeviceInfo(this))
{
qDebug() << "Drives:" << m_sysinfo->allLogicalDrives();
refreshStorageModels();
}

AboutSettings::~AboutSettings()
Expand All @@ -141,43 +197,12 @@ qlonglong AboutSettings::availableDiskSpace() const

QVariant AboutSettings::diskUsageModel() const
{
QVariantList result;

// Optional mountpoints that we want to report disk usage for
QStringList candidates;
candidates << "/home";

// Always report the rootfs
QStringList paths;
paths << "/";

QMap<QString,QString> devices;

FILE *fsd = setmntent(_PATH_MOUNTED, "r");
struct mntent entry;
char buffer[PATH_MAX];
while ((getmntent_r(fsd, &entry, buffer, sizeof(buffer))) != NULL) {
devices[QString::fromLatin1(entry.mnt_dir)] = QString::fromLatin1(entry.mnt_fsname);
}
endmntent(fsd);

foreach (const QString &mountpoint, devices.keys()) {
// Add a reported mountpoint if it's a candidate and if it's not the same as the rootfs
if (candidates.contains(mountpoint) && devices[mountpoint] != devices["/"]) {
paths << mountpoint;
}
}

foreach (const QString &path, paths) {
QVariantMap row;
row["storageType"] = (paths.count() == 1) ? QString("mass") : (path == "/") ? QString("system") : QString("user");
row["path"] = QString(path);
row["available"] = m_sysinfo->availableDiskSpace(path);
row["total"] = m_sysinfo->totalDiskSpace(path);
result << QVariant(row);
}
return m_internalStorage;
}

return result;
QVariant AboutSettings::externalStorageUsageModel() const
{
return m_externalStorage;
}

QString AboutSettings::bluetoothAddress() const
Expand Down Expand Up @@ -220,3 +245,74 @@ QString AboutSettings::adaptationVersion() const
{
return parseReleaseFile("/etc/hw-release")["VERSION_ID"];
}

void AboutSettings::refreshStorageModels()
{
// Optional mountpoints that we want to report disk usage for
QStringList candidates;
candidates << QStringLiteral("/home");

QMap<QString, StorageInfo> devices = parseExternalPartitions();

FILE *fsd = setmntent(_PATH_MOUNTED, "r");
struct mntent entry;
char buffer[3*PATH_MAX];
while ((getmntent_r(fsd, &entry, buffer, sizeof(buffer))) != NULL) {
StorageInfo info;
info.mountPath = QString::fromLatin1(entry.mnt_dir);
info.devicePath = QString::fromLatin1(entry.mnt_fsname);
info.filesystem = QString::fromLatin1(entry.mnt_type);

if (info.mountPath == QLatin1String("/") && info.devicePath.startsWith(QLatin1Char('/'))) {
// Always report rootfs, replacing other mounts from same device
devices.insert(info.devicePath, info);
} else if (!devices.contains(info.devicePath) || devices.value(info.devicePath).external) {
// Optional candidates and external storage
if (candidates.contains(info.mountPath)) {
devices.insert(info.devicePath, info);
} else if (info.devicePath.startsWith(QLatin1String("/dev/mmcblk1"))) {
info.external = true;
devices.insert(info.devicePath, info);
}
}
}
endmntent(fsd);

m_internalStorage.clear();
m_externalStorage.clear();

foreach (const StorageInfo &info, devices) {
if (!info.external) {
QVariantMap row;

row[QStringLiteral("storageType")] = info.mountPath == QLatin1String("/")
? QStringLiteral("system")
: QStringLiteral("user");

row[QStringLiteral("path")] = info.mountPath;
row[QStringLiteral("mounted")] = true;
row[QStringLiteral("available")] = m_sysinfo->availableDiskSpace(info.mountPath);
row[QStringLiteral("total")] = m_sysinfo->totalDiskSpace(info.mountPath);
row[QStringLiteral("filesystem")] = info.filesystem;
row[QStringLiteral("devicePath")] = info.devicePath;

m_internalStorage << QVariant(row);
} else {
QVariantMap row;

bool mounted = !info.mountPath.isEmpty();

row[QStringLiteral("storageType")] = QStringLiteral("card");
row[QStringLiteral("mounted")] = mounted;
row[QStringLiteral("path")] = info.mountPath;
row[QStringLiteral("available")] = mounted ? m_sysinfo->availableDiskSpace(info.mountPath) : 0;
row[QStringLiteral("total")] = mounted ? m_sysinfo->totalDiskSpace(info.mountPath) : info.partitionSize;
row[QStringLiteral("filesystem")] = info.filesystem;
row[QStringLiteral("devicePath")] = info.devicePath;

m_externalStorage << QVariant(row);
}
}

emit storageChanged();
}
11 changes: 11 additions & 0 deletions src/aboutsettings.h
Expand Up @@ -49,6 +49,9 @@ class AboutSettings: public QObject
Q_PROPERTY(QString softwareVersion READ softwareVersion CONSTANT)
Q_PROPERTY(QString adaptationVersion READ adaptationVersion CONSTANT)

Q_PROPERTY(QVariant internalStorageUsageModel READ diskUsageModel NOTIFY storageChanged)
Q_PROPERTY(QVariant externalStorageUsageModel READ externalStorageUsageModel NOTIFY storageChanged)

public:
explicit AboutSettings(QObject *parent = 0);
virtual ~AboutSettings();
Expand All @@ -66,6 +69,8 @@ class AboutSettings: public QObject
* - total: total bytes on the storage
**/
Q_INVOKABLE QVariant diskUsageModel() const;
QVariant externalStorageUsageModel() const;
Q_INVOKABLE void refreshStorageModels();

QString bluetoothAddress() const;
QString wlanMacAddress() const;
Expand All @@ -74,10 +79,16 @@ class AboutSettings: public QObject
QString softwareVersion() const;
QString adaptationVersion() const;

signals:
void storageChanged();

private:
QStorageInfo *m_sysinfo;
QNetworkInfo *m_netinfo;
QDeviceInfo *m_devinfo;

QVariantList m_internalStorage;
QVariantList m_externalStorage;
};

#endif
2 changes: 1 addition & 1 deletion src/src.pro
Expand Up @@ -2,7 +2,7 @@ TEMPLATE = lib
TARGET = systemsettings

# TODO: hide_symbols
CONFIG += qt create_pc create_prl no_install_prl
CONFIG += qt create_pc create_prl no_install_prl c++11
QT += qml dbus systeminfo
QT -= gui

Expand Down

0 comments on commit 53c72f5

Please sign in to comment.