8#include "databasesanitizer.h"
9#include "documenturldb.h"
12#include <sys/sysmacros.h>
14#include <KLocalizedString>
16#include <QStorageInfo>
22class DatabaseSanitizerImpl {
24 DatabaseSanitizerImpl(
const Database& db, Transaction::TransactionType type)
25 : m_transaction(new Transaction(db,
type))
38 bool isSymLink =
false;
39 bool accessible =
true;
43 void printProgress(
QTextStream& out, uint& cur,
const uint max,
const uint step)
const
45 if (cur % step == 0) {
46 out << QStringLiteral(
"%1%2\r").arg(100 * cur / max, 6).arg(
"%", -16);
58 quint64 accessible = 0;
72 QPair<QVector<FileInfo>, Summary> createList(
78 Q_ASSERT(m_transaction);
80 const auto docUrlDb = DocumentUrlDB(m_transaction->m_dbis.idTreeDbi,
81 m_transaction->m_dbis.idFilenameDbi,
82 m_transaction->m_txn);
83 const auto map = docUrlDb.toTestMap();
84 const auto keys =
map.keys();
86 uint max =
map.size();
91 for (qint64 deviceId : deviceIds) {
93 includeIds.
append(deviceId);
94 }
else if (deviceId < 0) {
95 excludeIds.
append(-deviceId);
100 summary.ignored = max;
103 for (
auto it =
map.constBegin(), end =
map.constEnd(); it != end; it++) {
104 printProgress(err, i, max, 100);
105 const quint64
id = it.key();
106 const quint32 deviceId = idToDeviceId(
id);
109 }
else if (excludeIds.
contains(deviceId)) {
111 }
else if (urlFilter && !urlFilter->match(it.value()).hasMatch()) {
116 info.deviceId = deviceId;
117 info.inode = idToInode(
id);
121 info.accessible = !info.url.isEmpty() && fileInfo.exists();
123 if (info.accessible && (accessFilter & DatabaseSanitizer::IgnoreAvailable)) {
125 }
else if (!info.accessible && (accessFilter & DatabaseSanitizer::IgnoreUnavailable)) {
129 info.isSymLink = fileInfo.isSymLink();
133 if (info.accessible) {
134 summary.accessible++;
137 return {result, summary};
144 for (
const auto& vol : volumes) {
146 const auto id = filePathToId(rootPath);
147 const quint32 deviceId = idToDeviceId(
id);
149 result[deviceId] = vol;
161 for (
const auto& info : infos) {
162 result[info.deviceId] =
false;
165 for (
auto it = result.
begin(), end = result.
end(); it != end; it++) {
166 const auto storageInfo = getStorageInfo(it.key());
167 it.value() = isIgnored(storageInfo, accessFilter);
174 const bool mounted = storageInfo.
isValid();
175 if (mounted && (accessFilter & DatabaseSanitizer::IgnoreMounted)) {
177 }
else if (!mounted && (accessFilter & DatabaseSanitizer::IgnoreUnmounted)) {
193 void removeDocument(
const quint64
id) {
194 m_transaction->removeDocument(
id);
198 m_transaction->commit();
202 m_transaction->abort();
206 Transaction* m_transaction;
210using namespace Baloo;
212DatabaseSanitizer::DatabaseSanitizer(
const Database& db, Baloo::Transaction::TransactionType type)
213 : m_pimpl(new DatabaseSanitizerImpl(db,
type))
217DatabaseSanitizer::DatabaseSanitizer(Database* db, Transaction::TransactionType type)
222DatabaseSanitizer::~DatabaseSanitizer()
245 auto listResult = m_pimpl->createList(deviceIds, accessFilter, urlFilter);
249 for (
const auto& info: listResult.first) {
250 out << QStringLiteral(
"%1").arg(info.accessible ?
"+" :
"!")
251 << sep << QStringLiteral(
"device: %1").arg(info.deviceId)
252 << sep << QStringLiteral(
"inode: %1").arg(info.inode)
253 << sep << QStringLiteral(
"url: %1").arg(info.url)
257 const auto& summary = listResult.second;
258 if (accessFilter & IgnoreAvailable) {
259 err <<
i18n(
"Total: %1, Inaccessible: %2",
261 summary.total - (summary.ignored + summary.accessible)) << endl;
263 err <<
i18n(
"Total: %1, Ignored: %2, Accessible: %3, Inaccessible: %4",
267 summary.total - (summary.ignored + summary.accessible)) << endl;
273 auto infos = m_pimpl->createList(deviceIds, accessFilter,
nullptr);
276 for (
const auto& info : infos.first) {
277 useCount[info.deviceId]++;
284 for (
auto it = useCount.
cbegin(); it != useCount.
cend(); it++) {
286 auto info = m_pimpl->getStorageInfo(
id);
290 }
else if (mounted && (accessFilter & IgnoreMounted)) {
292 }
else if (!mounted && (accessFilter & IgnoreUnmounted)) {
299 out << QStringLiteral(
"%1").arg(mounted ?
"+" :
"!")
300 << sep << QStringLiteral(
"device:%1").arg(
id)
301 << sep << QStringLiteral(
"[%1:%2]")
304 << sep << QStringLiteral(
"indexed-items:%1").arg(it.value());
310 << sep << QStringLiteral(
"path:%1").arg(info.
rootPath())
318 err <<
i18n(
"Found %1 matching in %2 devices", matchCount, useCount.
size()) << endl;
321void DatabaseSanitizer::removeStaleEntries(
const QVector<qint64>& deviceIds,
326 auto listResult = m_pimpl->createList(deviceIds, IgnoreAvailable, urlFilter);
328 const auto ignoredDevices = m_pimpl->deviceFilters(listResult.first, accessFilter);
331 auto& summary = listResult.second;
334 for (
const auto& info: listResult.first) {
335 if (ignoredDevices[info.deviceId] ==
true) {
338 if (info.isSymLink) {
339 out <<
i18n(
"IgnoredSymbolicLink:");
342 m_pimpl->removeDocument(info.id);
343 out <<
i18n(
"Removing:");
345 out << sep << QStringLiteral(
"device: %1").arg(info.deviceId)
346 << sep << QStringLiteral(
"inode: %1").arg(info.inode)
347 << sep << QStringLiteral(
"url: %1").arg(info.url)
356 Q_ASSERT(summary.accessible == 0);
357 err <<
i18nc(
"numbers",
"Removed: %1, Total: %2, Ignored: %3",
358 summary.total - summary.ignored,
Provide methods to show database problems and sanitize them.
void printDevices(const QVector< qint64 > &deviceIds, const ItemAccessFilters accessFilter=IgnoreNone)
Print info about known devices to stdout.
void printList(const QVector< qint64 > &deviceIds, const ItemAccessFilters accessFilter=IgnoreNone, const QSharedPointer< QRegularExpression > &urlFilter=nullptr)
Print database content to stdout.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
Implements storage for docIds without any associated data Instantiated for:
const char * constData() const const
QByteArray toPercentEncoding(const QByteArray &exclude, const QByteArray &include, char percent) const const
QString decodeName(const QByteArray &localFileName)
QByteArray encodeName(const QString &fileName)
void append(QList< T > &&value)
bool contains(const AT &value) const const
bool isEmpty() const const
void reserve(qsizetype size)
const_iterator cbegin() const const
const_iterator cend() const const
size_type size() const const
T value(const Key &key, const T &defaultValue) const const
QByteArray device() const const
QByteArray fileSystemType() const const
bool isValid() const const
QList< QStorageInfo > mountedVolumes()
QString rootPath() const const
QTextStream & endl(QTextStream &stream)
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)