diff --git a/src/engine/databasesanitizer.cpp b/src/engine/databasesanitizer.cpp --- a/src/engine/databasesanitizer.cpp +++ b/src/engine/databasesanitizer.cpp @@ -21,7 +21,8 @@ #include "databasesanitizer.h" #include "documenturldb.h" -#include "baloodebug.h" +#include "fsutils.h" +#include "idutils.h" #include #include @@ -118,14 +119,56 @@ return result; } - QMultiHash createDeviceList(const QVector& deviceIds) + struct DeviceInfo { + quint32 id = 0; + int items = 0; + FSUtils::DeviceInfo fsInfo = {}; + bool mounted = false; + }; + + DeviceInfo getDeviceInfo(const quint32 deviceId) + { + static QMap deviceInfos; + if (deviceInfos.isEmpty()) { + const auto devices = FSUtils::attachedDevices(); + for (const auto& dev : devices) { + const auto fsinfo = filePathToStat(qPrintable(dev.mountpoint)); + const quint32 id = static_cast(fsinfo.st_dev); + DeviceInfo devInfo; + devInfo.id = id; + devInfo.fsInfo = dev; + devInfo.mounted = true; + deviceInfos[id] = devInfo; + } + } + if (deviceInfos.contains(deviceId)) { + return deviceInfos.value(deviceId); + } else { + DeviceInfo empty; + empty.id = deviceId; + empty.mounted = false; + return empty; + } + } + + QVector createDeviceList(const QVector& deviceIds) { auto infos = createList(deviceIds, false, nullptr); + // Create a hash to sum-up indexed items QMultiHash usedDevices; - for (const auto& info: infos) { + for (const auto& info : infos) { usedDevices.insert(info.deviceId, info); } - return usedDevices; + + QVector result; + const auto keys = usedDevices.uniqueKeys(); + for (const auto& dev : keys) { + auto devinfo = getDeviceInfo(dev); + devinfo.items = usedDevices.values(dev).count(); + result.append(devinfo); + } + + return result; } private: @@ -193,22 +236,34 @@ void DatabaseSanitizer::printDevices(const QVector& deviceIds, const bool missingOnly) { - Q_UNUSED(missingOnly) - /* - * TODO: Implement missingOnly filter. Checking for file existence - * will not work. We need to read /etc/mtab or so. - */ auto usedDevices = m_pimpl->createDeviceList(deviceIds); const auto sep = QLatin1Char(' '); QTextStream out(stdout); QTextStream err(stderr); - - for (const auto& dev: usedDevices.uniqueKeys()) { - out << "Device:" << dev - << sep << usedDevices.values(dev).count() << sep << "items" - << endl; + int matchCount = 0; + for (const auto& dev : usedDevices) { + if (missingOnly && dev.mounted) { + continue; + } + matchCount++; + // TODO coloring would be nice, but "...|grep '^!'" does not work with it. + // out << QStringLiteral("%1").arg(dev.mounted ? "+" : "\033[1;31m!") + out << QStringLiteral("%1").arg(dev.mounted ? "+" : "!") + << sep << QStringLiteral("device:%1").arg(dev.id) + << sep << QStringLiteral("indexed-items:%1").arg(dev.items); + + if (dev.mounted) { + out + << sep << QStringLiteral("fstype:%1").arg(dev.fsInfo.filesystem) + << sep << QStringLiteral("fsname:%1").arg(dev.fsInfo.name) + << sep << QStringLiteral("mount:%1").arg(dev.fsInfo.mountpoint) + ; + } + // TODO: see above + // out << QStringLiteral("\033[0m") << endl; + out << endl; } - - err << i18n("Found %1 matching items", usedDevices.count()) << endl; + + err << i18n("Found %1 matching in %2 devices", matchCount, usedDevices.count()) << endl; } diff --git a/src/engine/fsutils.h b/src/engine/fsutils.h --- a/src/engine/fsutils.h +++ b/src/engine/fsutils.h @@ -25,6 +25,7 @@ #define BALOO_ENGINE_FSUTILS_H #include +#include namespace Baloo { namespace FSUtils { @@ -45,6 +46,16 @@ */ void disableCoW(const QString &path); +struct DeviceInfo { + quint64 id = 0; + QString filesystem = QString(); + QString name = QString(); + QString mountpoint = QString(); + QStringList options = {}; +}; + +const QVector attachedDevices(); + } } diff --git a/src/engine/fsutils.cpp b/src/engine/fsutils.cpp --- a/src/engine/fsutils.cpp +++ b/src/engine/fsutils.cpp @@ -107,3 +107,31 @@ close(fd); #endif } + +const QVector FSUtils::attachedDevices() +{ + QVector result; +#ifndef Q_OS_LINUX + return result; +#else + FILE *mtab = setmntent("/etc/mtab", "r"); + if (!mtab) { + return result; + } + while (mntent *mnt = getmntent(mtab)) { + if (qstrcmp(mnt->mnt_type, MNTTYPE_IGNORE) == 0) { + continue; + } + DeviceInfo info; + info.mountpoint = QString::fromLocal8Bit(mnt->mnt_dir); + info.filesystem = QString::fromLocal8Bit(mnt->mnt_type); + info.name = QString::fromLocal8Bit(mnt->mnt_fsname); + info.options = QString::fromLocal8Bit(mnt->mnt_opts).split(QLatin1Char(',')); + result.append(info); + } + + endmntent(mtab); + + return result; +#endif +} diff --git a/src/engine/idutils.h b/src/engine/idutils.h --- a/src/engine/idutils.h +++ b/src/engine/idutils.h @@ -53,6 +53,25 @@ static_cast(stBuf.st_ino)); } +inline QT_STATBUF filePathToStat(const QByteArray& filePath) +{ + QT_STATBUF statBuf; +#ifndef Q_OS_WIN + if (QT_LSTAT(filePath.constData(), &statBuf) != 0) { + statBuf.st_dev = 0; + } +#else + if (QT_STAT(filePath.constData(), &statBuf) != 0) { + statBuf.st_dev = 0; + } + if (QFileInfo(filePath).isSymLink()) { + if (QT_STAT(QFileInfo(filePath).symLinkTarget().toUtf8().constData(), &statBuf) != 0) { + statBuf.st_dev = 0; + } + } +#endif + return statBuf; +} inline quint64 filePathToId(const QByteArray& filePath) { QT_STATBUF statBuf; diff --git a/src/tools/baloodb/main.cpp b/src/tools/baloodb/main.cpp --- a/src/tools/baloodb/main.cpp +++ b/src/tools/baloodb/main.cpp @@ -230,7 +230,7 @@ } DatabaseSanitizer san(db, Transaction::ReadOnly); err << i18n("Listing database contents...") << endl; - san.printDevices(deviceIds); + san.printDevices(deviceIds, missingOnly); } else if (command == QStringLiteral("clean")) { /* TODO: add prune command */