10#include <config-libkleo.h>
12#include "checksumdefinition.h"
14#include "kleoexception.h"
16#include <libkleo_debug.h>
19#include <KConfigGroup>
20#include <KLocalizedString>
21#include <KSharedConfig>
25#include <QCoreApplication>
30#include <QRegularExpression>
31#include <QStandardPaths>
39static QMutex installPathMutex;
40Q_GLOBAL_STATIC(
QString, _installPath)
41QString ChecksumDefinition::installPath()
44 QString *
const ip = _installPath();
49 qCWarning(LIBKLEO_LOG) <<
"checksumdefinition.cpp: installPath() called before QCoreApplication was constructed";
54void ChecksumDefinition::setInstallPath(
const QString &ip)
70static const QLatin1Char NEWLINE_SEPARATED_STDIN_INDICATOR(
'|');
73static const QLatin1StringView CHECKSUM_DEFINITION_ID_ENTRY(
"checksum-definition-id");
78class ChecksumDefinitionError :
public Kleo::Exception
84 : Kleo::Exception(GPG_ERR_INV_PARAMETER,
i18n(
"Error in checksum definition %1: %2", id, message), MessageOnly)
88 ~ChecksumDefinitionError() throw()
override
92 const QString &checksumDefinitionId()
const
102 static const char exts[][4] = {
109 static const size_t numExts =
sizeof exts /
sizeof *exts;
110 for (
unsigned int i = 0; i < numExts; ++i) {
113 return fi.filePath();
119static void parse_command(
QString cmdline,
125 ChecksumDefinition::ArgumentPassingMethod *method)
134 if (cmdline.
startsWith(NULL_SEPARATED_STDIN_INDICATOR)) {
135 *method = ChecksumDefinition::NullSeparatedInputFile;
137 }
else if (cmdline.
startsWith(NEWLINE_SEPARATED_STDIN_INDICATOR)) {
138 *method = ChecksumDefinition::NewlineSeparatedInputFile;
141 *method = ChecksumDefinition::CommandLine;
143 if (*method != ChecksumDefinition::CommandLine && cmdline.
contains(FILE_PLACEHOLDER)) {
144 throw ChecksumDefinitionError(
id,
i18n(
"Cannot use both %f and | in '%1'", whichCommand));
148 .
replace(INSTALLPATH_PLACEHOLDER, QStringLiteral(
"__path_goes_here__"));
150 l = l.
replaceInStrings(QStringLiteral(
"__files_go_here__"), FILE_PLACEHOLDER);
152 if (l.
indexOf(regExpression) >= 0) {
153 l = l.
replaceInStrings(QStringLiteral(
"__path_goes_here__"), ChecksumDefinition::installPath());
156 throw ChecksumDefinitionError(
id,
i18n(
"Quoting error in '%1' entry", whichCommand));
159 throw ChecksumDefinitionError(
id,
i18n(
"'%1' too complex (would need shell)", whichCommand));
161 qCDebug(LIBKLEO_LOG) <<
"ChecksumDefinition[" <<
id <<
']' << l;
163 throw ChecksumDefinitionError(
id,
i18n(
"'%1' entry is empty/missing", whichCommand));
166 if (fi1.isAbsolute()) {
167 *command = try_extensions(l.front());
172 throw ChecksumDefinitionError(
id,
i18n(
"'%1' empty or not found", whichCommand));
174 const int idx1 = l.indexOf(FILE_PLACEHOLDER);
179 *prefix = l.
mid(1, idx1 - 1);
180 *suffix = l.
mid(idx1 + 1);
183 case ChecksumDefinition::CommandLine:
184 qCDebug(LIBKLEO_LOG) <<
"ChecksumDefinition[" <<
id <<
']' << *command << *prefix << FILE_PLACEHOLDER << *suffix;
186 case ChecksumDefinition::NewlineSeparatedInputFile:
187 qCDebug(LIBKLEO_LOG) <<
"ChecksumDefinition[" <<
id <<
']' <<
"find | " << *command << *prefix;
189 case ChecksumDefinition::NullSeparatedInputFile:
190 qCDebug(LIBKLEO_LOG) <<
"ChecksumDefinition[" <<
id <<
']' <<
"find -print0 | " << *command << *prefix;
192 case ChecksumDefinition::NumArgumentPassingMethods:
193 Q_ASSERT(!
"Should not happen");
201class KConfigBasedChecksumDefinition :
public ChecksumDefinition
204 explicit KConfigBasedChecksumDefinition(
const KConfigGroup &group)
205 : ChecksumDefinition(group.readEntryUntranslated(ID_ENTRY),
206 group.readEntry(NAME_ENTRY),
207 group.readEntry(OUTPUT_FILE_ENTRY),
208 group.readEntry(FILE_PATTERNS_ENTRY,
QStringList()))
210 if (
id().isEmpty()) {
211 throw ChecksumDefinitionError(group.
name(),
i18n(
"'id' entry is empty/missing"));
213 if (outputFileName().isEmpty()) {
214 throw ChecksumDefinitionError(
id(),
i18n(
"'output-file' entry is empty/missing"));
216 if (patterns().empty()) {
217 throw ChecksumDefinitionError(
id(),
i18n(
"'file-patterns' entry is empty/missing"));
221 ArgumentPassingMethod method;
222 parse_command(group.
readEntry(CREATE_COMMAND_ENTRY),
224 CREATE_COMMAND_ENTRY,
226 &m_createPrefixArguments,
227 &m_createPostfixArguments,
229 setCreateCommandArgumentPassingMethod(method);
232 parse_command(group.
readEntry(VERIFY_COMMAND_ENTRY),
234 VERIFY_COMMAND_ENTRY,
236 &m_verifyPrefixArguments,
237 &m_verifyPostfixArguments,
239 setVerifyCommandArgumentPassingMethod(method);
243 QString doGetCreateCommand()
const override
245 return m_createCommand;
249 return m_createPrefixArguments + files + m_createPostfixArguments;
251 QString doGetVerifyCommand()
const override
253 return m_verifyCommand;
257 return m_verifyPrefixArguments + files + m_verifyPostfixArguments;
261 QString m_createCommand, m_verifyCommand;
262 QStringList m_createPrefixArguments, m_createPostfixArguments;
263 QStringList m_verifyPrefixArguments, m_verifyPostfixArguments;
270 , m_label(label.isEmpty() ? id : label)
271 , m_outputFileName(outputFileName)
272 , m_patterns(patterns)
273 , m_createMethod(CommandLine)
274 , m_verifyMethod(CommandLine)
278ChecksumDefinition::~ChecksumDefinition()
282QString ChecksumDefinition::createCommand()
const
284 return doGetCreateCommand();
287QString ChecksumDefinition::verifyCommand()
const
289 return doGetVerifyCommand();
295 return doGetCreateArguments(files);
300 return doGetVerifyArguments(files);
307 for (
const QString &file : files) {
309 result += file.toUtf8();
318static bool start_command(
QProcess *p,
319 const char *functionName,
323 ChecksumDefinition::ArgumentPassingMethod method)
326 qCWarning(LIBKLEO_LOG) << functionName <<
": process == NULL";
331 case ChecksumDefinition::NumArgumentPassingMethods:
332 Q_ASSERT(!
"Should not happen");
334 case ChecksumDefinition::CommandLine:
335 qCDebug(LIBKLEO_LOG) <<
"Starting: " << cmd <<
" " << args.
join(
QLatin1Char(
' '));
339 case ChecksumDefinition::NewlineSeparatedInputFile:
340 case ChecksumDefinition::NullSeparatedInputFile:
341 qCDebug(LIBKLEO_LOG) <<
"Starting: " << cmd <<
" " << args.
join(
QLatin1Char(
' '));
346 const char sep = method == ChecksumDefinition::NewlineSeparatedInputFile ?
'\n' :
'\0';
347 const QByteArray stdin = make_input(files, sep);
360 return start_command(p,
362 doGetCreateCommand(),
363 m_createMethod == CommandLine ? doGetCreateArguments(files) : doGetCreateArguments(
QStringList()),
370 return start_command(p,
372 doGetVerifyCommand(),
373 m_verifyMethod == CommandLine ? doGetVerifyArguments(files) : doGetVerifyArguments(
QStringList()),
379std::vector<std::shared_ptr<ChecksumDefinition>> ChecksumDefinition::getChecksumDefinitions()
382 return getChecksumDefinitions(errors);
386std::vector<std::shared_ptr<ChecksumDefinition>> ChecksumDefinition::getChecksumDefinitions(
QStringList &errors)
388 std::vector<std::shared_ptr<ChecksumDefinition>> result;
392 for (
const QString &group : groups) {
394 const std::shared_ptr<ChecksumDefinition> ad(
new KConfigBasedChecksumDefinition(
KConfigGroup(config, group)));
395 result.push_back(ad);
396 }
catch (
const std::exception &e) {
397 qDebug() << e.what();
400 errors.
push_back(
i18n(
"Caught unknown exception in group %1", group));
407std::shared_ptr<ChecksumDefinition>
408ChecksumDefinition::getDefaultChecksumDefinition(
const std::vector<std::shared_ptr<ChecksumDefinition>> &checksumDefinitions)
411 const QString checksumDefinitionId = group.
readEntry(CHECKSUM_DEFINITION_ID_ENTRY, QStringLiteral(
"sha256sum"));
413 if (!checksumDefinitionId.
isEmpty()) {
414 for (
const std::shared_ptr<ChecksumDefinition> &cd : checksumDefinitions) {
415 if (cd && cd->id() == checksumDefinitionId) {
420 if (!checksumDefinitions.empty()) {
421 return checksumDefinitions.front();
423 return std::shared_ptr<ChecksumDefinition>();
428void ChecksumDefinition::setDefaultChecksumDefinition(
const std::shared_ptr<ChecksumDefinition> &checksumDefinition)
430 if (!checksumDefinition) {
434 group.
writeEntry(CHECKSUM_DEFINITION_ID_ENTRY, checksumDefinition->id());
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
QString readEntry(const char *key, const char *aDefault=nullptr) const
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
QString i18n(const char *text, const TYPE &arg...)
KCOREADDONS_EXPORT QStringList splitArgs(const QString &cmd, Options flags=NoOptions, Errors *err=nullptr)
qsizetype size() const const
QString applicationDirPath()
QCoreApplication * instance()
QByteArray encodeName(const QString &fileName)
qint64 write(const QByteArray &data)
QList< T > mid(qsizetype pos, qsizetype length) const const
void push_back(parameter_type value)
void reserve(qsizetype size)
qsizetype size() const const
void start(OpenMode mode)
bool waitForStarted(int msecs)
QString findExecutable(const QString &executableName, const QStringList &paths)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString fromLocal8Bit(QByteArrayView str)
bool isEmpty() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QStringList filter(QStringView str, Qt::CaseSensitivity cs) const const
qsizetype indexOf(const QRegularExpression &re, qsizetype from) const const
QString join(QChar separator) const const
QStringList & replaceInStrings(QStringView before, QStringView after, Qt::CaseSensitivity cs)