Baloo

tools/balooshow/main.cpp
1/*
2 SPDX-FileCopyrightText: 2012-2013 Vishesh Handa <me@vhanda.in>
3
4 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5*/
6
7#include <algorithm>
8
9#include <QCoreApplication>
10#include <QCommandLineParser>
11#include <QCommandLineOption>
12#include <QDateTime>
13#include <QFile>
14#include <QTextStream>
15
16#include <KAboutData>
17#include <KLocalizedString>
18
19#include <QJsonDocument>
20#include <QJsonObject>
21
22#include "global.h"
23#include "idutils.h"
24#include "database.h"
25#include "transaction.h"
26
27#include <unistd.h>
28#include <KFileMetaData/PropertyInfo>
29
30QString colorString(const QString& input, int color)
31{
32 static bool isTty = isatty(fileno(stdout));
33 if(isTty) {
34 QString colorStart = QStringLiteral("\033[0;%1m").arg(color);
35 QLatin1String colorEnd("\033[0;0m");
36
37 return colorStart + input + colorEnd;
38 } else {
39 return input;
40 }
41}
42
43inline KFileMetaData::PropertyMultiMap variantToPropertyMultiMap(const QVariantMap &varMap)
44{
45 KFileMetaData::PropertyMultiMap propMap;
46 QVariantMap::const_iterator it = varMap.constBegin();
47 for (; it != varMap.constEnd(); ++it) {
48 int p = it.key().toInt();
49 propMap.insert(static_cast<KFileMetaData::Property::Property>(p), it.value());
50 }
51 return propMap;
52}
53
54int main(int argc, char* argv[])
55{
57
58 KAboutData aboutData(QStringLiteral("balooshow"),
59 i18n("Baloo Show"),
60 QStringLiteral(PROJECT_VERSION),
61 i18n("The Baloo data Viewer - A debugging tool"),
63 i18n("(c) 2012, Vishesh Handa"));
64
66
68 parser.addPositionalArgument(QStringLiteral("files"), i18n("Urls, document ids or inodes of the files"), QStringLiteral("[file|id|inode...]"));
69 parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("x"),
70 i18n("Print internal info")));
71 parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("i"),
72 i18n("Arguments are interpreted as inode numbers (requires -d)")));
73 parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("d"),
74 i18n("Device id for the files"), QStringLiteral("deviceId"), QString()));
75 parser.addHelpOption();
76 parser.process(app);
77
78 const QStringList args = parser.positionalArguments();
79
80 if (args.isEmpty()) {
81 parser.showHelp(1);
82 }
83
84 QTextStream stream(stdout);
85
86 bool useInodes = parser.isSet(QStringLiteral("i"));
87 quint32 devId;
88 if (useInodes) {
89 bool ok;
90 devId = parser.value(QStringLiteral("d")).toULong(&ok, 10);
91 if (!ok) {
92 devId = parser.value(QStringLiteral("d")).toULong(&ok, 16);
93 }
94 }
95
96 if (useInodes && devId == 0) {
97 stream << i18n("Error: -i requires specifying a device (-d <deviceId>)") << '\n';
98 parser.showHelp(1);
99 }
100
101 Baloo::Database *db = Baloo::globalDatabaseInstance();
102 if (!db->open(Baloo::Database::ReadOnlyDatabase)) {
103 stream << i18n("The Baloo index could not be opened. Please run \"%1\" to see if Baloo is enabled and working.",
104 QStringLiteral("balooctl status")) << '\n';
105 return 1;
106 }
107
108 Baloo::Transaction tr(db, Baloo::Transaction::ReadOnly);
109
110 for (QString url : args) {
111 quint64 fid = 0;
113 if (!useInodes) {
114 if (QFile::exists(url)) {
115 quint64 fsFid = Baloo::filePathToId(QFile::encodeName(url));
116 fid = tr.documentId(QFile::encodeName(url));
117 internalUrl = QFile::decodeName(tr.documentUrl(fsFid));
118
119 if (fid && fid != fsFid) {
120 stream << i18n("The document IDs of the Baloo DB and the filesystem are different:") << '\n';
121 auto dbInode = Baloo::idToInode(fid);
122 auto fsInode = Baloo::idToInode(fsFid);
123 auto dbDevId = Baloo::idToDeviceId(fid);
124 auto fsDevId = Baloo::idToDeviceId(fsFid);
125
126 stream << "Url: " << url << "\n";
127 stream << "ID: " << fid << " (DB) <-> " << fsFid << " (FS)\n";
128 stream << "Inode: " << dbInode << " (DB) " << (dbInode == fsInode ? "== " : "<-> ") << fsInode << " (FS)\n";
129 stream << "DeviceID: " << dbDevId << " (DB) " << (dbDevId == fsDevId ? "== " : "<-> ") << fsDevId << " (FS)\n";
130 }
131 fid = fsFid;
132 } else {
133 bool ok;
134 fid = url.toULongLong(&ok, 10);
135 if (!ok) {
136 fid = url.toULongLong(&ok, 16);
137 }
138 if (!ok) {
139 stream << i18n("%1: Not a valid url or document id", url) << '\n';
140 continue;
141 }
142 url = QFile::decodeName(tr.documentUrl(fid));
143 internalUrl = url;
144 }
145
146 } else {
147 bool ok;
148 quint32 inode = url.toULong(&ok, 10);
149 if (!ok) {
150 inode = url.toULong(&ok, 16);
151 }
152 if (!ok) {
153 stream << i18n("%1: Failed to parse inode number", url) << '\n';
154 continue;
155 }
156
157 fid = Baloo::devIdAndInodeToId(devId, inode);
158 url = QFile::decodeName(tr.documentUrl(fid));
159 internalUrl = url;
160 }
161
162 if (fid) {
163 stream << colorString(QString::number(fid, 16), 31) << ' ';
164 stream << colorString(QString::number(Baloo::idToDeviceId(fid)), 28) << ' ';
165 stream << colorString(QString::number(Baloo::idToInode(fid)), 28) << ' ';
166 }
167 if (fid && tr.hasDocument(fid)) {
168 stream << colorString(url, 32);
169 if (!internalUrl.isEmpty() && internalUrl != url) {
170 // The document is know by a different name inside the DB,
171 // e.g. a hardlink, or untracked rename
172 stream << QLatin1String(" [") << internalUrl << QLatin1Char(']');
173 }
174 stream << '\n';
175 }
176 else {
177 stream << i18n("%1: No index information found", url) << '\n';
178 continue;
179 }
180
181 Baloo::DocumentTimeDB::TimeInfo time = tr.documentTimeInfo(fid);
182 stream << QStringLiteral("\tMtime: %1 ").arg(time.mTime)
184 << QStringLiteral("\n\tCtime: %1 ").arg(time.cTime)
186 << '\n';
187
188 const QJsonDocument jdoc = QJsonDocument::fromJson(tr.documentData(fid));
189 const QVariantMap varMap = jdoc.object().toVariantMap();
190 KFileMetaData::PropertyMultiMap propMap = variantToPropertyMultiMap(varMap);
191 if (!propMap.isEmpty()) {
192 stream << "\tCached properties:" << '\n';
193 }
194 for (auto it = propMap.constBegin(); it != propMap.constEnd(); ++it) {
195 QString str;
196 if (it.value().typeId() == QMetaType::QVariantList) {
198 const auto vars = it.value().toList();
199 for (const QVariant& var : vars) {
200 list << var.toString();
201 }
202 str = list.join(QLatin1String(", "));
203 } else {
204 str = it.value().toString();
205 }
206
208 stream << "\t\t" << pi.displayName() << ": " << str << '\n';
209 }
210
211 if (parser.isSet(QStringLiteral("x"))) {
212 QVector<QByteArray> terms = tr.documentTerms(fid);
213 QVector<QByteArray> fileNameTerms = tr.documentFileNameTerms(fid);
214 QVector<QByteArray> xAttrTerms = tr.documentXattrTerms(fid);
215
216 auto join = [](const QVector<QByteArray>& v) {
218 for (const QByteArray& arr : v) {
219 ba.append(arr);
220 ba.append(' ');
221 }
222 return QString::fromUtf8(ba);
223 };
224
225 auto propertiesBegin = std::stable_partition(terms.begin(), terms.end(),
226 [](const auto & t) { return t.isEmpty() || t[0] < 'A' || t[0] > 'Z'; });
229
230 stream << "\n" << i18n("Internal Info") << "\n";
231 stream << i18n("File Name Terms: %1", join(fileNameTerms)) << "\n";
232 stream << i18n("%1 Terms: %2", QStringLiteral("XAttr"), join(xAttrTerms)) << '\n';
233 stream << i18n("Plain Text Terms: %1", join(terms)) << "\n";
234 stream << i18n("Property Terms: %1", join(propertyTerms)) << "\n";
235
237 KLocalizedString errorPrefix = ki18nc("Prefix string for internal errors", "Internal Error - %1");
238
239 for (const QByteArray& arr : propertyTerms) {
240 auto arrAsPrintable = [arr]() {
241 return QString::fromLatin1(arr.toPercentEncoding());
242 };
243
244 if (arr.length() < 1) {
245 auto error = QStringLiteral("malformed term (short): '%1'\n").arg(arrAsPrintable());
246 stream << errorPrefix.subs(error).toString();
247 continue;
248 }
249
251
252 if (word[0] == QLatin1Char('X')) {
253 if (word.length() < 4) {
254 // 'X<num>-<value>
255 auto error = QStringLiteral("malformed property term (short): '%1' in '%2'\n").arg(word, arrAsPrintable());
256 stream << errorPrefix.subs(error).toString();
257 continue;
258 }
259 const int posOfNonNumeric = word.indexOf(QLatin1Char('-'), 2);
260 if ((posOfNonNumeric < 0) || ((posOfNonNumeric + 1) == word.length())) {
261 auto error = QStringLiteral("malformed property term (no data): '%1' in '%2'\n").arg(word, arrAsPrintable());
262 stream << errorPrefix.subs(error).toString();
263 continue;
264 }
265
266 bool ok;
268 int propNum = prop.toInt(&ok);
269 if (!ok) {
270 auto error = QStringLiteral("malformed property term (bad index): '%1' in '%2'\n").arg(prop, arrAsPrintable());
271 stream << errorPrefix.subs(error).toString();
272 continue;
273 }
274
275 const QString value = word.mid(posOfNonNumeric + 1);
277 }
278 }
279
280 for (auto it = propertyWords.constBegin(); it != propertyWords.constEnd(); it++) {
281 auto prop = static_cast<KFileMetaData::Property::Property>(it.key());
283
284 stream << pi.name() << ": " << it.value().join(QLatin1Char(' ')) << '\n';
285 }
286 }
287 }
288 stream.flush();
289 return 0;
290}
static void setApplicationData(const KAboutData &aboutData)
KLocalizedString KI18N_EXPORT ki18nc(const char *context, const char *text)
QString i18n(const char *text, const TYPE &arg...)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QDateTime fromSecsSinceEpoch(qint64 secs)
QString toString(QStringView format, QCalendar cal) const const
QString decodeName(const QByteArray &localFileName)
QByteArray encodeName(const QString &fileName)
bool exists() const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
void append(QList< T > &&value)
iterator begin()
const_iterator constBegin() const const
const_iterator constEnd() const const
iterator end()
iterator erase(const_iterator begin, const_iterator end)
qsizetype indexOf(const AT &value, qsizetype from) const const
iterator insert(const_iterator before, parameter_type value)
bool isEmpty() const const
qsizetype length() const const
QList< T > mid(qsizetype pos, qsizetype length) const const
T value(qsizetype i) const const
QString arg(Args &&... args) const const
QString fromLatin1(QByteArrayView str)
QString fromUtf8(QByteArrayView str)
QString number(double n, char format, int precision)
QStringView mid(qsizetype start, qsizetype length) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:20:16 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.