diff --git a/src/engine/experimental/databasesanitizer.h b/src/engine/experimental/databasesanitizer.h --- a/src/engine/experimental/databasesanitizer.h +++ b/src/engine/experimental/databasesanitizer.h @@ -33,6 +33,16 @@ */ class BALOO_ENGINE_EXPORT DatabaseSanitizer { +public: + enum ItemAccessFilterFlags { + IgnoreNone = 0, + IgnoreAvailable = 1, + IgnoreUnavailable = 2, + IgnoreMounted = 8, + IgnoreUnmounted = 0x10, + }; + Q_DECLARE_FLAGS(ItemAccessFilters, ItemAccessFilterFlags) + public: DatabaseSanitizer(const Database& db, Transaction::TransactionType type); DatabaseSanitizer(Database* db, Transaction::TransactionType type); @@ -49,23 +59,26 @@ * \p urlFilter Filter result urls. Default is null = Print everything. */ void printList(const QVector& deviceIds, - const bool missingOnly, - const QSharedPointer& urlFilter + const ItemAccessFilters accessFilter = IgnoreNone, + const QSharedPointer& urlFilter = nullptr ); /** * Print info about known devices to stdout * * \p deviceIDs filter by device ids. Negative numbers list everything but... * with empty \p deviceIDs(default) everything is printed. * - * \p missingOnly Only inaccessible items are printed. + * \p accessFilter filter by accessibility. E.g IgnoreAvailable|IgnoreUnmounted + * prints only mounted devices with inaccessible files. */ - void printDevices(const QVector& deviceIds, const bool missingOnly = false); + void printDevices(const QVector& deviceIds, const ItemAccessFilters accessFilter = IgnoreNone); private: DatabaseSanitizer(const DatabaseSanitizer& rhs) = delete; DatabaseSanitizerImpl* m_pimpl; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(DatabaseSanitizer::ItemAccessFilters) + } #endif // BALOODATABASESANITIZER_H diff --git a/src/engine/experimental/databasesanitizer.cpp b/src/engine/experimental/databasesanitizer.cpp --- a/src/engine/experimental/databasesanitizer.cpp +++ b/src/engine/experimental/databasesanitizer.cpp @@ -59,22 +59,29 @@ } cur++; } - + /** + * Summary of createList() actions + */ + struct Summary { + quint64 total = 0; ///Count of all files + quint64 ignored = 0; ///Count of filtered out files + quint64 accessible = 0; ///Count of checked and accessible files + }; /** * Create a list of \a FileInfo items. * * \p deviceIDs filter by device ids. If the vector is empty no filtering is done * and every item is collected. * Positive numbers are including filters collecting only the mentioned device ids. * Negative numbers are excluding filters collecting everything but the mentioned device ids. * - * \p missingOnly Only inaccessible items are collected. + * \p accessFilter Flags to filter items by accessibility. * * \p urlFilter Filter result urls. Default is null = Collect everything. */ - QVector createList( + QPair, Summary> createList( const QVector& deviceIds, - const bool purging, + const DatabaseSanitizer::ItemAccessFilters accessFilter, const QSharedPointer& urlFilter ) const { @@ -86,9 +93,9 @@ const auto map = docUrlDb.toTestMap(); const auto keys = map.keys(); QVector result; - result.reserve(keys.count()); + uint max = map.size(); uint i = 0; - uint max = keys.count(); + result.reserve(max); QVector includeIds; QVector excludeIds; for (qint64 deviceId : deviceIds) { @@ -98,28 +105,39 @@ excludeIds.append(-deviceId); } } - + Summary summary; + summary.total = max; + summary.ignored = max; QTextStream err(stderr); - for (quint64 id: keys) { + for (auto it = map.constBegin(), end = map.constEnd(); it != end; it++) { printProgress(err, i, max, 100); + const quint64 id = it.key(); + const quint32 deviceId = idToDeviceId(id); + if (!includeIds.isEmpty() && !includeIds.contains(deviceId)) { + continue; + } else if (excludeIds.contains(deviceId)) { + continue; + } else if (urlFilter && !urlFilter->match(it.value()).hasMatch()) { + continue; + } - const quint32* arr = reinterpret_cast(&id); - const auto url = docUrlDb.get(id); + summary.ignored--; FileInfo info; - info.deviceId = arr[0]; - info.inode = arr[1]; - info.url = url; - info.accessible = !url.isEmpty() && QFileInfo::exists(url); - if ((!includeIds.isEmpty() && !includeIds.contains(info.deviceId)) - || (!excludeIds.isEmpty() && excludeIds.contains(info.deviceId)) - || (purging && info.accessible) - || (urlFilter && !urlFilter->match(info.url).hasMatch()) - ) { - continue; + info.deviceId = deviceId; + info.inode = idToInode(id); + info.url = it.value(); + info.accessible = !info.url.isEmpty() && QFileInfo::exists(info.url); + + if (info.accessible) { + summary.accessible++; + } + + if ((info.accessible && !(accessFilter & DatabaseSanitizer::IgnoreAvailable)) || + (!info.accessible && !(accessFilter & DatabaseSanitizer::IgnoreUnavailable))) { + result.append(info); } - result.append(info); } - return result; + return {result, summary}; } struct DeviceInfo { @@ -141,7 +159,6 @@ devInfo.id = id; devInfo.fsInfo = dev; devInfo.mounted = true && (dev.filesystem != QLatin1String("tmpfs")); - qDebug() << "filesystem" << dev.filesystem; result[id] = devInfo; } return result; @@ -157,14 +174,24 @@ return 1; } - QMap createDeviceList(const QVector& infos) + QMap createDeviceList( + const QVector& infos, + const DatabaseSanitizer::ItemAccessFilters accessFilter = DatabaseSanitizer::IgnoreNone) { QMap usedDevices; for (const auto& info : infos) { usedDevices[info.deviceId].items++; } - for (auto it = usedDevices.begin(), end = usedDevices.end(); it != end; it++) { + for (auto it = usedDevices.begin(), end = usedDevices.end(); it != end;) { fillInDeviceInfo(it.key(), it.value()); + + if ((it.value().mounted && !(accessFilter & DatabaseSanitizer::IgnoreMounted)) + || (!it.value().mounted && !(accessFilter & DatabaseSanitizer::IgnoreUnmounted)) + ) { + it++; + } else { + usedDevices.erase(it++); + } } return usedDevices; } @@ -207,42 +234,41 @@ */ void DatabaseSanitizer::printList( const QVector& deviceIds, - const bool missingOnly, + const ItemAccessFilters accessFilter, const QSharedPointer& urlFilter) { - auto infos = m_pimpl->createList(deviceIds, missingOnly, urlFilter); + auto listResult = m_pimpl->createList(deviceIds, accessFilter, urlFilter); const auto sep = QLatin1Char(' '); QTextStream out(stdout); QTextStream err(stderr); - for (const auto& info: infos) { - if (!missingOnly) { - out << QStringLiteral("%1").arg(info.accessible ? "+" : "!") << sep; - } else if (!info.accessible) { - out << i18n("Missing:") << sep; - } else { - Q_ASSERT(false); - continue; - } - out << QStringLiteral("device: %1").arg(info.deviceId) + for (const auto& info: listResult.first) { + out << QStringLiteral("%1").arg(info.accessible ? "+" : "!") + << sep << QStringLiteral("device: %1").arg(info.deviceId) << sep << QStringLiteral("inode: %1").arg(info.inode) << sep << QStringLiteral("url: %1").arg(info.url) << endl; } - err << i18n("Found %1 matching items", infos.count()) << endl; + + const auto& summary = listResult.second; + err << i18n("Total: %1, Ignored: %2, Accessible: %3, Inaccessible: %4", + summary.total, + summary.ignored, + summary.accessible, + summary.total - (summary.ignored + summary.accessible)) << endl; } -void DatabaseSanitizer::printDevices(const QVector& deviceIds, const bool missingOnly) +void DatabaseSanitizer::printDevices(const QVector& deviceIds, const ItemAccessFilters accessFilter) { - auto infos = m_pimpl->createList(deviceIds, false, nullptr); - auto usedDevices = m_pimpl->createDeviceList(infos); + auto infos = m_pimpl->createList(deviceIds, accessFilter, nullptr); + auto usedDevices = m_pimpl->createDeviceList(infos.first, accessFilter); const auto sep = QLatin1Char(' '); QTextStream out(stdout); QTextStream err(stderr); int matchCount = 0; for (const auto& dev : usedDevices) { - if (missingOnly && dev.mounted) { + if ((accessFilter & IgnoreMounted) && dev.mounted) { continue; } matchCount++; diff --git a/src/tools/experimental/baloodb/main.cpp b/src/tools/experimental/baloodb/main.cpp --- a/src/tools/experimental/baloodb/main.cpp +++ b/src/tools/experimental/baloodb/main.cpp @@ -61,6 +61,10 @@ QCommandLineOption{ QStringList{QStringLiteral("m"), QStringLiteral("missing-only")}, i18n("List only inaccessible entries.\nOnly applies to \"%1\"", QStringLiteral("list")) + }, + QCommandLineOption{ + QStringList{QStringLiteral("u"), QStringLiteral("mounted-only")}, + i18n("Act only on item on mounted devices") } }; @@ -102,7 +106,7 @@ QStringLiteral("devices"), i18n("List devices"), QStringList{}, - QStringList{QStringLiteral("missing-only")} + QStringList{QStringLiteral("missing-only"), QStringLiteral("mounted-only")} } }; @@ -205,7 +209,15 @@ for (const auto& dev : parser.values(QStringLiteral("device-id"))) { deviceIds.append(dev.toInt()); } - const bool missingOnly = parser.isSet(QStringLiteral("missing-only")); + const DatabaseSanitizer::ItemAccessFilters accessFilter = ( + parser.isSet(QStringLiteral("missing-only")) + ? DatabaseSanitizer::IgnoreAvailable + : DatabaseSanitizer::IgnoreNone + ) | ( + parser.isSet(QStringLiteral("mounted-only")) + ? DatabaseSanitizer::IgnoreUnmounted + : DatabaseSanitizer::IgnoreNone + ); const QString pattern = args.isEmpty() ? QString() : args.at(0); @@ -225,15 +237,15 @@ } DatabaseSanitizer san(db, Transaction::ReadOnly); err << i18n("Listing database contents...") << endl; - san.printList(deviceIds, missingOnly, urlFilter); + san.printList(deviceIds, accessFilter, urlFilter); } else if (command == QStringLiteral("devices")) { if (!db->open(Database::ReadOnlyDatabase)) { err << i18n("Baloo Index could not be opened") << endl; return 1; } DatabaseSanitizer san(db, Transaction::ReadOnly); err << i18n("Listing database contents...") << endl; - san.printDevices(deviceIds, missingOnly); + san.printDevices(deviceIds, accessFilter); } else if (command == QStringLiteral("clean")) { /* TODO: add prune command */