diff options
Diffstat (limited to 'src/libs/installer/metadatajob_p.h')
-rw-r--r-- | src/libs/installer/metadatajob_p.h | 155 |
1 files changed, 135 insertions, 20 deletions
diff --git a/src/libs/installer/metadatajob_p.h b/src/libs/installer/metadatajob_p.h index 9160f4cc9..837a7e9ae 100644 --- a/src/libs/installer/metadatajob_p.h +++ b/src/libs/installer/metadatajob_p.h @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -29,10 +29,10 @@ #ifndef METADATAJOB_P_H #define METADATAJOB_P_H -#include "lib7z_extract.h" -#include "lib7z_facade.h" +#include "archivefactory.h" #include "metadatajob.h" +#include <QCryptographicHash> #include <QDir> #include <QFile> @@ -47,9 +47,9 @@ public: : m_message(message) {} - void raise() const { throw *this; } + void raise() const override { throw *this; } QString message() const { return m_message; } - UnzipArchiveException *clone() const { return new UnzipArchiveException(*this); } + UnzipArchiveException *clone() const override{ return new UnzipArchiveException(*this); } private: QString m_message; @@ -62,11 +62,18 @@ class UnzipArchiveTask : public AbstractTask<void> public: UnzipArchiveTask(const QString &arcive, const QString &target) - : m_archive(arcive), m_targetDir(target) + : m_archive(arcive) + , m_targetDir(target) + , m_removeArchive(false) + , m_storeChecksums(false) {} + QString target() { return m_targetDir; } QString archive() { return m_archive; } - void doTask(QFutureInterface<void> &fi) + void setRemoveArchive(bool remove) { m_removeArchive = remove; } + void setStoreChecksums(bool store) { m_storeChecksums = store; } + + void doTask(QFutureInterface<void> &fi) override { fi.reportStarted(); fi.setExpectedResultCount(1); @@ -76,28 +83,136 @@ public: return; // ignore already canceled } - QFile archive(m_archive); - if (archive.open(QIODevice::ReadOnly)) { - try { - Lib7z::extractArchive(&archive, m_targetDir); - } catch (const Lib7z::SevenZipException& e) { - fi.reportException(UnzipArchiveException(MetadataJob::tr("Error while extracting " - "archive \"%1\": %2").arg(QDir::toNativeSeparators(m_archive), e.message()))); - } catch (...) { - fi.reportException(UnzipArchiveException(MetadataJob::tr("Unknown exception " - "caught while extracting archive \"%1\".").arg(QDir::toNativeSeparators(m_archive)))); - } - } else { + QScopedPointer<AbstractArchive> archive(ArchiveFactory::instance().create(m_archive)); + if (!archive) { + fi.reportException(UnzipArchiveException(MetadataJob::tr("Unsupported archive \"%1\": no handler " + "registered for file suffix \"%2\".").arg(m_archive, QFileInfo(m_archive).suffix()))); + return; + } else if (!archive->open(QIODevice::ReadOnly)) { fi.reportException(UnzipArchiveException(MetadataJob::tr("Cannot open file \"%1\" for " - "reading: %2").arg(QDir::toNativeSeparators(m_archive), archive.errorString()))); + "reading: %2").arg(QDir::toNativeSeparators(m_archive), archive->errorString()))); + return; + } else if (!archive->extract(m_targetDir)) { + fi.reportException(UnzipArchiveException(MetadataJob::tr("Error while extracting " + "archive \"%1\": %2").arg(QDir::toNativeSeparators(m_archive), archive->errorString()))); + return; + } + + if (m_storeChecksums) { + // Calculate and store checksums of extracted files for later use + const QVector<ArchiveEntry> entries = archive->list(); + for (auto &entry : entries) { + if (entry.isDirectory) + continue; + + QFile file(m_targetDir + QDir::separator() + entry.path); + if (!file.open(QIODevice::ReadOnly)) { + fi.reportException(UnzipArchiveException(MetadataJob::tr("Cannot open extracted file \"%1\" for " + "reading: %2").arg(QDir::toNativeSeparators(file.fileName()), file.errorString()))); + break; + } + QCryptographicHash hash(QCryptographicHash::Sha1); + hash.addData(&file); + + const QByteArray hexChecksum = hash.result().toHex(); + QFileInfo fileInfo(file.fileName()); + QFile hashFile(fileInfo.absolutePath() + QDir::separator() + + QString::fromLatin1(hexChecksum) + QLatin1String(".sha1")); + if (!hashFile.open(QIODevice::WriteOnly)) { + fi.reportException(UnzipArchiveException(MetadataJob::tr("Cannot open file \"%1\" for " + "writing: %2").arg(QDir::toNativeSeparators(hashFile.fileName()), hashFile.errorString()))); + break; + } + } } + archive->close(); + if (m_removeArchive) + QFile::remove(m_archive); + fi.reportFinished(); } private: QString m_archive; QString m_targetDir; + bool m_removeArchive; + bool m_storeChecksums; +}; + +class CacheTaskException : public QException +{ +public: + CacheTaskException() {} + explicit CacheTaskException(const QString &message) + : m_message(message) + {} + ~CacheTaskException() {} + + void raise() const override { throw *this; } + QString message() const { return m_message; } + CacheTaskException *clone() const override { return new CacheTaskException(*this); } + +private: + QString m_message; +}; + +class UpdateCacheTask : public AbstractTask<void> +{ + Q_OBJECT + Q_DISABLE_COPY(UpdateCacheTask) + +public: + UpdateCacheTask(MetadataCache &cache, QHash<QString, Metadata *> &updates) + : m_cache(&cache) + , m_updates(&updates) + {} + + void doTask(QFutureInterface<void> &fi) override + { + fi.reportStarted(); + fi.setExpectedResultCount(1); + + // Register items from current run to cache + QStringList registeredKeys; + bool success = true; + for (auto *meta : qAsConst(*m_updates)) { + if (!m_cache->registerItem(meta, true, MetadataCache::Move)) { + success = false; + break; + } + meta->setPersistentRepositoryPath(meta->repository().url()); + registeredKeys.append(m_updates->key(meta)); + } + // Remove items whose ownership was transferred to cache + for (auto &key : qAsConst(registeredKeys)) + m_updates->remove(key); + + // Bail out if there was error while registering items + if (!success) { + fi.reportException(CacheTaskException(m_cache->errorString() + u' ' + + MetadataJob::tr("Clearing the cache directory and restarting the application may solve this."))); + m_cache->sync(); + fi.reportFinished(); + return; + } + + // ...and clean up obsolete cached items + const QList<Metadata *> obsolete = m_cache->obsoleteItems(); + for (auto *meta : obsolete) + m_cache->removeItem(meta->checksum()); + + if (!m_cache->sync()) { + fi.reportException(CacheTaskException(m_cache->errorString() + u' ' + + MetadataJob::tr("Clearing the cache directory and restarting the application may solve this."))); + } + + fi.reportFinished(); + } + +private: + MetadataCache *const m_cache; + QHash<QString, Metadata *> *const m_updates; }; } // namespace QInstaller |