diff --git a/autotests/kerfuffle/adddialogtest.cpp b/autotests/kerfuffle/adddialogtest.cpp --- a/autotests/kerfuffle/adddialogtest.cpp +++ b/autotests/kerfuffle/adddialogtest.cpp @@ -69,7 +69,6 @@ QTest::newRow("tarZ") << QStringLiteral("application/x-tarz") << false << -1 << -1; QTest::newRow("tarxz") << QStringLiteral("application/x-xz-compressed-tar") << true << 3 << 7; QTest::newRow("tarlzma") << QStringLiteral("application/x-lzma-compressed-tar") << true << 3 << 7; - QTest::newRow("tarlzop") << QStringLiteral("application/x-tzo") << true << 3 << 7; QTest::newRow("tarlzip") << QStringLiteral("application/x-lzip-compressed-tar") << true << 3 << 7; const auto writeMimeTypes = m_pluginManager.supportedWriteMimeTypes(); @@ -97,6 +96,12 @@ } else { qDebug() << "tar.lrzip format not available, skipping test."; } + + if (writeMimeTypes.contains(QStringLiteral("application/x-tzo"))) { + QTest::newRow("tarlzop") << QStringLiteral("application/x-tzo") << true << 3 << 7; + } else { + qDebug() << "tar.lzo format not available, skipping test."; + } } void AddDialogTest::testBasicWidgets() diff --git a/autotests/kerfuffle/createdialogtest.cpp b/autotests/kerfuffle/createdialogtest.cpp --- a/autotests/kerfuffle/createdialogtest.cpp +++ b/autotests/kerfuffle/createdialogtest.cpp @@ -61,7 +61,6 @@ QTest::newRow("tarZ") << QStringLiteral("application/x-tarz"); QTest::newRow("tarxz") << QStringLiteral("application/x-xz-compressed-tar"); QTest::newRow("tarlzma") << QStringLiteral("application/x-lzma-compressed-tar"); - QTest::newRow("tarlzop") << QStringLiteral("application/x-tzo"); QTest::newRow("tarlzip") << QStringLiteral("application/x-lzip-compressed-tar"); const auto writeMimeTypes = m_pluginManager.supportedWriteMimeTypes(); @@ -89,6 +88,12 @@ } else { qDebug() << "tar.lrzip format not available in CreateDialog, skipping test."; } + + if (writeMimeTypes.contains(QStringLiteral("application/x-tzo"))) { + QTest::newRow("tarlzop") << QStringLiteral("application/x-tzo"); + } else { + qDebug() << "tar.lzo format not available in CreateDialog, skipping test."; + } } void CreateDialogTest::testBasicWidgets() diff --git a/autotests/kerfuffle/extracttest.cpp b/autotests/kerfuffle/extracttest.cpp --- a/autotests/kerfuffle/extracttest.cpp +++ b/autotests/kerfuffle/extracttest.cpp @@ -25,6 +25,7 @@ */ #include "archive_kerfuffle.h" +#include "pluginmanager.h" #include "jobs.h" #include "testhelper.h" @@ -269,22 +270,25 @@ << optionsPreservePaths << 7; - archivePath = QFINDTESTDATA("data/simplearchive.tar.lzo"); - QTest::newRow("extract selected entries from a lzop-compressed tarball without path") - << archivePath - << QVector { - new Archive::Entry(this, QStringLiteral("file3.txt"), QString()), - new Archive::Entry(this, QStringLiteral("dir2/file22.txt"), QString()) - } - << optionsNoPaths - << 2; + // Only run tests if tar.lzo format is available + if (PluginManager().supportedMimeTypes().contains(QStringLiteral("application/x-tzo"))) { + archivePath = QFINDTESTDATA("data/simplearchive.tar.lzo"); + QTest::newRow("extract selected entries from a lzop-compressed tarball without path") + << archivePath + << QVector { + new Archive::Entry(this, QStringLiteral("file3.txt"), QString()), + new Archive::Entry(this, QStringLiteral("dir2/file22.txt"), QString()) + } + << optionsNoPaths + << 2; - archivePath = QFINDTESTDATA("data/simplearchive.tar.lzo"); - QTest::newRow("extract all entries from a lzop-compressed tarball with path") - << archivePath - << QVector() - << optionsPreservePaths - << 7; + archivePath = QFINDTESTDATA("data/simplearchive.tar.lzo"); + QTest::newRow("extract all entries from a lzop-compressed tarball with path") + << archivePath + << QVector() + << optionsPreservePaths + << 7; + } // Only run test for lrzipped tar if lrzip executable is found in path. if (!QStandardPaths::findExecutable(QStringLiteral("lrzip")).isEmpty()) { diff --git a/autotests/kerfuffle/loadtest.cpp b/autotests/kerfuffle/loadtest.cpp --- a/autotests/kerfuffle/loadtest.cpp +++ b/autotests/kerfuffle/loadtest.cpp @@ -26,6 +26,7 @@ #include "archive_kerfuffle.h" #include "jobs.h" +#include "pluginmanager.h" #include "testhelper.h" #include @@ -132,11 +133,15 @@ << false << false << false << false << false << 0 << Archive::Unencrypted << QStringLiteral("simplearchive"); - QTest::newRow("lzop-compressed tarball") - << QFINDTESTDATA("data/simplearchive.tar.lzo") - << QStringLiteral("simplearchive") - << false << false << false << false << false << 0 << Archive::Unencrypted - << QStringLiteral("simplearchive"); + if (PluginManager().supportedMimeTypes().contains(QStringLiteral("application/x-tzo"))) { + QTest::newRow("lzop-compressed tarball") + << QFINDTESTDATA("data/simplearchive.tar.lzo") + << QStringLiteral("simplearchive") + << false << false << false << false << false << 0 << Archive::Unencrypted + << QStringLiteral("simplearchive"); + } else { + qDebug() << "tar.lzo format not available. Skipping lzo test."; + } // Only run test for lrzipped tar if lrzip executable is found in path. if (!QStandardPaths::findExecutable(QStringLiteral("lrzip")).isEmpty()) { diff --git a/kerfuffle/pluginmanager.h b/kerfuffle/pluginmanager.h --- a/kerfuffle/pluginmanager.h +++ b/kerfuffle/pluginmanager.h @@ -130,6 +130,11 @@ */ static QStringList sortByComment(const QSet &mimeTypes); + /** + * Workaround for libarchive >= 3.3 not linking against liblzo. + */ + static bool libarchiveHasLzo(); + QVector m_plugins; QHash> m_preferredPluginsCache; }; diff --git a/kerfuffle/pluginmanager.cpp b/kerfuffle/pluginmanager.cpp --- a/kerfuffle/pluginmanager.cpp +++ b/kerfuffle/pluginmanager.cpp @@ -33,7 +33,10 @@ #include #include +#include #include +#include +#include #include #include @@ -138,6 +141,11 @@ supported.remove(QStringLiteral("application/x-lz4-compressed-tar")); } + // Remove entry for lzo-compressed tar if libarchive not linked against lzo and lzop executable not found in path. + if (!libarchiveHasLzo() && QStandardPaths::findExecutable(QStringLiteral("lzop")).isEmpty()) { + supported.remove(QStringLiteral("application/x-tzo")); + } + if (mode == SortByComment) { return sortByComment(supported); } @@ -167,6 +175,11 @@ supported.remove(QStringLiteral("application/x-lz4-compressed-tar")); } + // Remove entry for lzo-compressed tar if libarchive not linked against lzo and lzop executable not found in path. + if (!libarchiveHasLzo() && QStandardPaths::findExecutable(QStringLiteral("lzop")).isEmpty()) { + supported.remove(QStringLiteral("application/x-tzo")); + } + if (mode == SortByComment) { return sortByComment(supported); } @@ -242,4 +255,35 @@ return sortedMimeTypes; } +bool PluginManager::libarchiveHasLzo() +{ + // Step 1: look for the libarchive plugin, which is built against libarchive. + const QString pluginPath = []() { + foreach (const QString &path, QCoreApplication::libraryPaths()) { + const QString pluginPath = QStringLiteral("%1/kerfuffle/kerfuffle_libarchive.so").arg(path); + if (QFileInfo::exists(pluginPath)) { + return pluginPath; + } + } + + return QString(); + }(); + + // Step 2: ldd the libarchive plugin to figure out the absolute libarchive path. + QProcess ldd; + ldd.start(QStringLiteral("ldd"), {pluginPath}); + ldd.waitForFinished(); + const QString output = QString::fromUtf8(ldd.readAllStandardOutput()); + QRegularExpression regex(QStringLiteral("/.*/libarchive.so")); + if (!regex.match(output).hasMatch()) { + return false; + } + + // Step 3: check whether libarchive links against liblzo. + const QString libarchivePath = regex.match(output).captured(0); + ldd.start(QStringLiteral("ldd"), {libarchivePath}); + ldd.waitForFinished(); + return ldd.readAllStandardOutput().contains(QByteArrayLiteral("lzo")); +} + }