From ecb616a739d04dace54f9c6afd04c6ed34aa5479 Mon Sep 17 00:00:00 2001 From: Katja Marttila Date: Fri, 15 Oct 2021 10:35:49 +0300 Subject: Fix dependencies example exception Dependencies example creates a local repository. The example was failing in Windows because QFile was not able to rename the file when creating a local repository as it was open by Lib7zArchive. Task-number: QTIFW-2362 Change-Id: I7d118707c0d770e67b5a71167b9818fbcccc599f Reviewed-by: Arttu Tarkiainen --- src/libs/installer/createlocalrepositoryoperation.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libs/installer') diff --git a/src/libs/installer/createlocalrepositoryoperation.cpp b/src/libs/installer/createlocalrepositoryoperation.cpp index a40838178..576e4fa3d 100644 --- a/src/libs/installer/createlocalrepositoryoperation.cpp +++ b/src/libs/installer/createlocalrepositoryoperation.cpp @@ -129,6 +129,7 @@ static QString createArchive(const QString repoPath, const QString &sourceDir, c throw Error(CreateLocalRepositoryOperation::tr("Cannot create archive \"%1\": %2") .arg(QDir::toNativeSeparators(archive.fileName()), archiveFile.errorString())); } + archiveFile.close(); removeFiles(sourceDir, helper); // cleanup the files we compressed if (!archive.rename(sourceDir + fileName)) { throw Error(CreateLocalRepositoryOperation::tr("Cannot move file \"%1\" to \"%2\": %3") -- cgit v1.2.3 From f8bebde7599a12becffac6c6dbfa58f0d584bc01 Mon Sep 17 00:00:00 2001 From: Arttu Tarkiainen Date: Mon, 18 Oct 2021 09:57:38 +0000 Subject: Revert "Show messages from lcPackageInfo logging category regardless of verbosity" This reverts commit fae6c9901645d6ae6acdeaf843e542385318a1d8. Reason for revert: updateinfo plugin also sets QT_LOGGING_RULES=*=false, meaning the printing is still suppressed. Change-Id: I5f14d471221a32c58d028be5f06a199422dca7d4 Reviewed-by: Katja Marttila --- src/libs/installer/loggingutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libs/installer') diff --git a/src/libs/installer/loggingutils.cpp b/src/libs/installer/loggingutils.cpp index 6e7bff44a..45f7aab1b 100644 --- a/src/libs/installer/loggingutils.cpp +++ b/src/libs/installer/loggingutils.cpp @@ -160,7 +160,7 @@ void LoggingHandler::messageHandler(QtMsgType type, const QMessageLogContext &co if (VerboseWriter *log = VerboseWriter::instance()) log->appendLine(ba); - if (type != QtDebugMsg || isVerbose() || context.category == lcPackageInfo().categoryName()) + if (type != QtDebugMsg || isVerbose()) std::cout << qPrintable(ba) << std::endl; if (type == QtFatalMsg) { -- cgit v1.2.3 From 4066fbebcabbdf591c2fc525343f8f78486457d2 Mon Sep 17 00:00:00 2001 From: Arttu Tarkiainen Date: Mon, 18 Oct 2021 17:28:49 +0300 Subject: Print essential component information with std::cout Do not use our own message handler for printing XML-formatted component information (from 'list', 'search', 'check-updates') that is expected to be included in output regardless of the current verbosity level or logging rules. Higher verbosity can still add more information to be included in output. Also: - Modify auto-tests to pass and check the output correctly. - Remove now orphaned 'ifw.package.info' logging category. - Rename 'LoggingHandler::printComponentInformation()' to 'printUpdateInformation()' to better match the intended purpose. Task-number: QTIFW-2349 Change-Id: Id1a868f8f824c606825cd6168974a7e3845383e6 Reviewed-by: Katja Marttila --- src/libs/installer/globals.cpp | 7 ------- src/libs/installer/globals.h | 1 - src/libs/installer/loggingutils.cpp | 15 ++++++--------- src/libs/installer/loggingutils.h | 2 +- 4 files changed, 7 insertions(+), 18 deletions(-) (limited to 'src/libs/installer') diff --git a/src/libs/installer/globals.cpp b/src/libs/installer/globals.cpp index 0da4bc3b6..adf1d2f6e 100644 --- a/src/libs/installer/globals.cpp +++ b/src/libs/installer/globals.cpp @@ -33,7 +33,6 @@ const char IFW_SERVER[] = "ifw.server"; const char IFW_INSTALLER_INSTALLLOG[] = "ifw.installer.installlog"; const char IFW_DEVELOPER_BUILD[] = "ifw.developer.build"; -const char IFW_PACKAGE_INFO[] = "ifw.package.info"; // Internal-only, hidden in --help text const char IFW_PROGRESS_INDICATOR[] = "ifw.progress.indicator"; @@ -61,16 +60,10 @@ namespace QInstaller \internal */ -/*! - \fn QInstaller::lcPackageInfo() - \internal -*/ - Q_LOGGING_CATEGORY(lcServer, IFW_SERVER) Q_LOGGING_CATEGORY(lcInstallerInstallLog, IFW_INSTALLER_INSTALLLOG) Q_LOGGING_CATEGORY(lcProgressIndicator, IFW_PROGRESS_INDICATOR) Q_LOGGING_CATEGORY(lcDeveloperBuild, IFW_DEVELOPER_BUILD) -Q_LOGGING_CATEGORY(lcPackageInfo, IFW_PACKAGE_INFO) /*! Returns available logging categories. diff --git a/src/libs/installer/globals.h b/src/libs/installer/globals.h index 5053f6d9f..b22331e2c 100644 --- a/src/libs/installer/globals.h +++ b/src/libs/installer/globals.h @@ -40,7 +40,6 @@ INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcInstallerInstallLog) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcProgressIndicator) INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcDeveloperBuild) -INSTALLER_EXPORT Q_DECLARE_LOGGING_CATEGORY(lcPackageInfo) QStringList INSTALLER_EXPORT loggingCategories(); diff --git a/src/libs/installer/loggingutils.cpp b/src/libs/installer/loggingutils.cpp index 45f7aab1b..a2b561c53 100644 --- a/src/libs/installer/loggingutils.cpp +++ b/src/libs/installer/loggingutils.cpp @@ -145,10 +145,7 @@ void LoggingHandler::messageHandler(QtMsgType type, const QMessageLogContext &co static Uptime uptime; - QString ba; - if (context.category != lcPackageInfo().categoryName()) { - ba = QLatin1Char('[') + QString::number(uptime.elapsed()) + QStringLiteral("] "); - } + QString ba = QLatin1Char('[') + QString::number(uptime.elapsed()) + QStringLiteral("] "); ba += trimAndPrepend(type, msg); if (type != QtDebugMsg && context.file) { @@ -251,9 +248,9 @@ bool LoggingHandler::outputRedirected() const } /*! - Prints basic information about \a components. + Prints update information from \a components. */ -void LoggingHandler::printComponentInfo(const QList components) const +void LoggingHandler::printUpdateInformation(const QList components) const { QDomDocument doc; QDomElement root = doc.createElement(QLatin1String("updates")); @@ -267,7 +264,7 @@ void LoggingHandler::printComponentInfo(const QList components) con update.setAttribute(QLatin1String("id"), component->value(scName)); root.appendChild(update); } - qCDebug(lcPackageInfo) << qPrintable(doc.toString(4)); + std::cout << qPrintable(doc.toString(4)); } /*! @@ -297,7 +294,7 @@ void LoggingHandler::printLocalPackageInformation(const QList components) const; + void printUpdateInformation(const QList components) const; void printLocalPackageInformation(const QList &packages) const; void printPackageInformation(const PackagesList &matchedPackages, const LocalPackagesHash &installedPackages) const; -- cgit v1.2.3 From 9cf92b4cd273be55c056253b8e4a3a57e13195a8 Mon Sep 17 00:00:00 2001 From: Arttu Tarkiainen Date: Mon, 25 Oct 2021 15:28:09 +0300 Subject: Add support for seeking files handled with libarchive This fixes losing executable bits of files in Zip archives when extracted. Zip archives store file metadata in two ways, partial metadata per-entry and full metadata at the end of archive. IFW's read implementation previously did only streaming without support for seeking archives, which is required to obtain full metadata - meaning the partial metadata was used instead by libarchive's Zip reader. The extracted entries between the two metadata types are not consistent. This change also enables usage of archive formats that cannot be accurately handled with a streaming model, like 7zip which needs to read key data from the end of the file before reading file data from the beginning. Task-number: QTIFW-2372 Change-Id: Ie4ed33040fc52de073546e46d9da726816f47a81 Reviewed-by: Katja Marttila --- src/libs/installer/libarchivearchive.cpp | 116 ++++++++++++++++++++++++-- src/libs/installer/libarchivearchive.h | 11 +++ src/libs/installer/libarchivewrapper_p.cpp | 47 +++++++++++ src/libs/installer/libarchivewrapper_p.h | 3 + src/libs/installer/protocol.h | 2 + src/libs/installer/remoteserverconnection.cpp | 4 + src/libs/installer/remoteserverconnection_p.h | 10 +++ 7 files changed, 188 insertions(+), 5 deletions(-) (limited to 'src/libs/installer') diff --git a/src/libs/installer/libarchivearchive.cpp b/src/libs/installer/libarchivearchive.cpp index ad5609490..0d2619c7d 100644 --- a/src/libs/installer/libarchivearchive.cpp +++ b/src/libs/installer/libarchivearchive.cpp @@ -32,6 +32,8 @@ #include "errors.h" #include "globals.h" +#include + #include #include #include @@ -93,7 +95,11 @@ void ExtractWorker::extract(const QString &dirPath, const quint64 totalFiles) foreach (const QString &directory, createdDirs) emit currentEntryChanged(directory); - int status = archive_read_open(reader.get(), this, nullptr, readCallback, nullptr); + archive_read_set_read_callback(reader.get(), readCallback); + archive_read_set_callback_data(reader.get(), this); + archive_read_set_seek_callback(reader.get(), seekCallback); + + int status = archive_read_open1(reader.get()); if (status != ARCHIVE_OK) { m_status = Failure; emit finished(QLatin1String(archive_error_string(reader.get()))); @@ -142,6 +148,12 @@ void ExtractWorker::addDataBlock(const QByteArray buffer) emit dataReadyForRead(); } +void ExtractWorker::onFilePositionChanged(qint64 pos) +{ + m_lastPos = pos; + emit seekReady(); +} + void ExtractWorker::cancel() { m_status = Canceled; @@ -177,6 +189,26 @@ ssize_t ExtractWorker::readCallback(archive *reader, void *caller, const void ** return buffer->size(); } +la_int64_t ExtractWorker::seekCallback(archive *reader, void *caller, la_int64_t offset, int whence) +{ + Q_UNUSED(reader) + + ExtractWorker *obj; + if (!(obj = static_cast(caller))) + return ARCHIVE_FATAL; + + emit obj->seekRequested(static_cast(offset), whence); + + { + QEventLoop loop; + QTimer::singleShot(30000, &loop, &QEventLoop::quit); + connect(obj, &ExtractWorker::seekReady, &loop, &QEventLoop::quit); + loop.exec(); + } + + return static_cast(obj->m_lastPos); +} + bool ExtractWorker::writeEntry(archive *reader, archive *writer, archive_entry *entry) { int status; @@ -234,6 +266,13 @@ bool ExtractWorker::writeEntry(archive *reader, archive *writer, archive_entry * Emitted when the worker object requires more data to continue extracting. */ +/*! + \fn QInstaller::LibArchiveArchive::seekRequested(qint64 offset, int whence) + + Emitted when the worker object requires a seek to \a offset to continue extracting. + The \a whence value defines the starting position for \a offset. +*/ + /*! \fn QInstaller::LibArchiveArchive::workerFinished() @@ -266,6 +305,12 @@ bool ExtractWorker::writeEntry(archive *reader, archive *writer, archive_entry * Emitted when the worker object is about to cancel extracting. */ +/*! + \fn QInstaller::LibArchiveArchive::workerAboutToSetFilePosition(qint64 pos) + + Emitted when the worker object is about to set new file position \a pos. +*/ + /*! Constructs an archive object representing an archive file specified by \a filename with \a parent as the parent object. @@ -377,7 +422,7 @@ bool LibArchiveArchive::extract(const QString &dirPath, const quint64 totalFiles foreach (const QString &directory, createdDirs) emit currentEntryChanged(directory); - int status = archive_read_open(reader.get(), m_data, nullptr, readCallback, nullptr); + int status = archiveReadOpenWithCallbacks(reader.get()); if (status != ARCHIVE_OK) throw Error(QLatin1String(archive_error_string(reader.get()))); @@ -496,7 +541,7 @@ QVector LibArchiveArchive::list() QVector entries; try { - int status = archive_read_open(reader.get(), m_data, nullptr, readCallback, nullptr); + int status = archiveReadOpenWithCallbacks(reader.get()); if (status != ARCHIVE_OK) throw Error(QLatin1String(archive_error_string(reader.get()))); @@ -537,7 +582,7 @@ bool LibArchiveArchive::isSupported() configureReader(reader.get()); try { - const int status = archive_read_open(reader.get(), m_data, nullptr, readCallback, nullptr); + const int status = archiveReadOpenWithCallbacks(reader.get()); if (status != ARCHIVE_OK) throw Error(QLatin1String(archive_error_string(reader.get()))); } catch (const Error &e) { @@ -574,6 +619,14 @@ void LibArchiveArchive::workerSetDataAtEnd() emit workerAboutToSetDataAtEnd(); } +/*! + Signals the worker object that the client file position changed to \a pos. +*/ +void LibArchiveArchive::workerSetFilePosition(qint64 pos) +{ + emit workerAboutToSetFilePosition(pos); +} + /*! Cancels the extract in progress for the worker object. */ @@ -672,9 +725,11 @@ void LibArchiveArchive::initExtractWorker() connect(this, &LibArchiveArchive::workerAboutToExtract, &m_worker, &ExtractWorker::extract); connect(this, &LibArchiveArchive::workerAboutToAddDataBlock, &m_worker, &ExtractWorker::addDataBlock); connect(this, &LibArchiveArchive::workerAboutToSetDataAtEnd, &m_worker, &ExtractWorker::dataAtEnd); + connect(this, &LibArchiveArchive::workerAboutToSetFilePosition, &m_worker, &ExtractWorker::onFilePositionChanged); connect(this, &LibArchiveArchive::workerAboutToCancel, &m_worker, &ExtractWorker::cancel); connect(&m_worker, &ExtractWorker::dataBlockRequested, this, &LibArchiveArchive::dataBlockRequested); + connect(&m_worker, &ExtractWorker::seekRequested, this, &LibArchiveArchive::seekRequested); connect(&m_worker, &ExtractWorker::finished, this, &LibArchiveArchive::onWorkerFinished); connect(&m_worker, &ExtractWorker::currentEntryChanged, this, &LibArchiveArchive::currentEntryChanged); @@ -683,6 +738,20 @@ void LibArchiveArchive::initExtractWorker() m_workerThread.start(); } +/*! + \internal + + Sets default callbacks for archive \a reader and opens for reading. +*/ +int LibArchiveArchive::archiveReadOpenWithCallbacks(archive *reader) +{ + archive_read_set_read_callback(reader, readCallback); + archive_read_set_callback_data(reader, m_data); + archive_read_set_seek_callback(reader, seekCallback); + + return archive_read_open1(reader); +} + /*! Writes the current \a entry header, then pulls data from the archive \a reader and writes it to the \a writer handle. @@ -766,6 +835,43 @@ ssize_t LibArchiveArchive::readCallback(archive *reader, void *archiveData, cons return readData(&data->file, data->buffer.data(), data->buffer.size()); } +/*! + \internal + + Seeks to specified \a offset in the file device in \a archiveData and returns the position. + Possible \a whence values are \c SEEK_SET, \c SEEK_CUR, and \c SEEK_END. Returns + \c ARCHIVE_FATAL if the seek fails. +*/ +la_int64_t LibArchiveArchive::seekCallback(archive *reader, void *archiveData, la_int64_t offset, int whence) +{ + Q_UNUSED(reader) + + ArchiveData *data; + if (!(data = static_cast(archiveData))) + return ARCHIVE_FATAL; + + if (!data->file.isOpen() || data->file.isSequential()) + return ARCHIVE_FATAL; + + switch (whence) { + case SEEK_SET: // moves file pointer position to the beginning of the file + if (!data->file.seek(offset)) + return ARCHIVE_FATAL; + break; + case SEEK_CUR: // moves file pointer position to given location + if (!data->file.seek(data->file.pos() + offset)) + return ARCHIVE_FATAL; + break; + case SEEK_END: // moves file pointer position to the end of file + if (!data->file.seek(data->file.size() + offset)) + return ARCHIVE_FATAL; + break; + default: + return ARCHIVE_FATAL; + } + return data->file.pos(); +} + /*! Returns the \a path to a file or directory, without the Win32 namespace prefix. On Unix platforms, the \a path is returned unaltered. @@ -794,7 +900,7 @@ quint64 LibArchiveArchive::totalFiles() configureReader(reader.get()); try { - int status = archive_read_open(reader.get(), m_data, nullptr, readCallback, nullptr); + int status = archiveReadOpenWithCallbacks(reader.get()); if (status != ARCHIVE_OK) throw Error(QLatin1String(archive_error_string(reader.get()))); diff --git a/src/libs/installer/libarchivearchive.h b/src/libs/installer/libarchivearchive.h index e0281e655..796069ed1 100644 --- a/src/libs/installer/libarchivearchive.h +++ b/src/libs/installer/libarchivearchive.h @@ -64,12 +64,15 @@ public: public Q_SLOTS: void extract(const QString &dirPath, const quint64 totalFiles); void addDataBlock(const QByteArray buffer); + void onFilePositionChanged(qint64 pos); void cancel(); Q_SIGNALS: void dataBlockRequested(); void dataAtEnd(); void dataReadyForRead(); + void seekRequested(qint64 offset, int whence); + void seekReady(); void finished(const QString &errorString = QString()); void currentEntryChanged(const QString &filename); @@ -77,10 +80,12 @@ Q_SIGNALS: private: static ssize_t readCallback(archive *reader, void *caller, const void **buff); + static la_int64_t seekCallback(archive *reader, void *caller, la_int64_t offset, int whence); bool writeEntry(archive *reader, archive *writer, archive_entry *entry); private: QByteArray m_buffer; + qint64 m_lastPos = 0; Status m_status; }; @@ -107,16 +112,19 @@ public: void workerExtract(const QString &dirPath, const quint64 totalFiles); void workerAddDataBlock(const QByteArray buffer); void workerSetDataAtEnd(); + void workerSetFilePosition(qint64 pos); void workerCancel(); ExtractWorker::Status workerStatus() const; Q_SIGNALS: void dataBlockRequested(); + void seekRequested(qint64 offset, int whence); void workerFinished(); void workerAboutToExtract(const QString &dirPath, const quint64 totalFiles); void workerAboutToAddDataBlock(const QByteArray buffer); void workerAboutToSetDataAtEnd(); + void workerAboutToSetFilePosition(qint64 pos); void workerAboutToCancel(); public Q_SLOTS: @@ -133,11 +141,14 @@ private: void initExtractWorker(); + int archiveReadOpenWithCallbacks(archive *reader); bool writeEntry(archive *reader, archive *writer, archive_entry *entry); static qint64 readData(QFile *file, char *data, qint64 maxSize); static ssize_t readCallback(archive *reader, void *archiveData, const void **buff); + static la_int64_t seekCallback(archive *reader, void *archiveData, la_int64_t offset, int whence); + static QString pathWithoutNamespace(const QString &path); quint64 totalFiles(); diff --git a/src/libs/installer/libarchivewrapper_p.cpp b/src/libs/installer/libarchivewrapper_p.cpp index 5509812cf..942e948e8 100644 --- a/src/libs/installer/libarchivewrapper_p.cpp +++ b/src/libs/installer/libarchivewrapper_p.cpp @@ -247,6 +247,10 @@ void LibArchiveWrapperPrivate::processSignals() emit completedChanged(completed, total); } else if (name == QLatin1String(Protocol::AbstractArchiveSignalDataBlockRequested)) { emit dataBlockRequested(); + } else if (name == QLatin1String(Protocol::AbstractArchiveSignalSeekRequested)) { + const qint64 offset = receivedSignals.takeFirst().value(); + const int whence = receivedSignals.takeFirst().value(); + emit seekRequested(offset, whence); } else if (name == QLatin1String(Protocol::AbstractArchiveSignalWorkerFinished)) { emit remoteWorkerFinished(); } @@ -293,6 +297,35 @@ void LibArchiveWrapperPrivate::onDataBlockRequested() addDataBlock(*buff); } +/*! + Seeks to specified \a offset in the underlying file device. Possible \a whence + values are \c SEEK_SET, \c SEEK_CUR, and \c SEEK_END. +*/ +void LibArchiveWrapperPrivate::onSeekRequested(qint64 offset, int whence) +{ + QFile *const file = &m_archive.m_data->file; + if (!file->isOpen() || file->isSequential()) { + qCWarning(QInstaller::lcInstallerInstallLog) << file->errorString(); + setClientFilePosition(ARCHIVE_FATAL); + return; + } + bool success = false; + switch (whence) { + case SEEK_SET: // moves file pointer position to the beginning of the file + success = file->seek(offset); + break; + case SEEK_CUR: // moves file pointer position to given location + success = file->seek(file->pos() + offset); + break; + case SEEK_END: // moves file pointer position to the end of file + success = file->seek(file->size() + offset); + break; + default: + break; + } + setClientFilePosition(success ? file->pos() : ARCHIVE_FATAL); +} + /*! Starts the timer to process server-side signals and connects handler signals for the matching signals of the wrapper object. @@ -310,6 +343,8 @@ void LibArchiveWrapperPrivate::init() QObject::connect(this, &LibArchiveWrapperPrivate::dataBlockRequested, this, &LibArchiveWrapperPrivate::onDataBlockRequested); + QObject::connect(this, &LibArchiveWrapperPrivate::seekRequested, + this, &LibArchiveWrapperPrivate::onSeekRequested); } /*! @@ -337,6 +372,18 @@ void LibArchiveWrapperPrivate::setClientDataAtEnd() } } +/*! + Calls a remote method to set new file position \a pos. +*/ +void LibArchiveWrapperPrivate::setClientFilePosition(qint64 pos) +{ + if (connectToServer()) { + m_lock.lockForWrite(); + callRemoteMethod(QLatin1String(Protocol::AbstractArchiveSetFilePosition), pos, dummy); + m_lock.unlock(); + } +} + /*! Calls a remote method to retrieve and return the status of the extract worker on a server process. diff --git a/src/libs/installer/libarchivewrapper_p.h b/src/libs/installer/libarchivewrapper_p.h index ea8409da0..722c91f17 100644 --- a/src/libs/installer/libarchivewrapper_p.h +++ b/src/libs/installer/libarchivewrapper_p.h @@ -66,6 +66,7 @@ Q_SIGNALS: void currentEntryChanged(const QString &filename); void completedChanged(const quint64 completed, const quint64 total); void dataBlockRequested(); + void seekRequested(qint64 offset, int whence); void remoteWorkerFinished(); public Q_SLOTS: @@ -74,12 +75,14 @@ public Q_SLOTS: private Q_SLOTS: void processSignals(); void onDataBlockRequested(); + void onSeekRequested(qint64 offset, int whence); private: void init(); void addDataBlock(const QByteArray &buffer); void setClientDataAtEnd(); + void setClientFilePosition(qint64 pos); ExtractWorker::Status workerStatus() const; private: diff --git a/src/libs/installer/protocol.h b/src/libs/installer/protocol.h index c7eb9a308..65241e00b 100644 --- a/src/libs/installer/protocol.h +++ b/src/libs/installer/protocol.h @@ -177,6 +177,7 @@ const char AbstractArchiveIsSupported[] = "AbstractArchive::isSupported"; const char AbstractArchiveSetCompressionLevel[] = "AbstractArchive::setCompressionLevel"; const char AbstractArchiveAddDataBlock[] = "AbstractArchive::addDataBlock"; const char AbstractArchiveSetClientDataAtEnd[] = "AbstractArchive::setClientDataAtEnd"; +const char AbstractArchiveSetFilePosition[] = "AbstractArchive::setFilePosition"; const char AbstractArchiveWorkerStatus[] = "AbstractArchive::workerStatus"; const char AbstractArchiveCancel[] = "AbstractArchive::cancel"; @@ -184,6 +185,7 @@ const char GetAbstractArchiveSignals[] = "GetAbstractArchiveSignals"; const char AbstractArchiveSignalCurrentEntryChanged[] = "AbstractArchive::currentEntryChanged"; const char AbstractArchiveSignalCompletedChanged[] = "AbstractArchive::completedChanged"; const char AbstractArchiveSignalDataBlockRequested[] = "AbstractArchive::dataBlockRequested"; +const char AbstractArchiveSignalSeekRequested[] = "AbstractArchive::seekRequested"; const char AbstractArchiveSignalWorkerFinished[] = "AbstractArchive::workerFinished"; } // namespace Protocol diff --git a/src/libs/installer/remoteserverconnection.cpp b/src/libs/installer/remoteserverconnection.cpp index 5d72f834d..9e141ea48 100644 --- a/src/libs/installer/remoteserverconnection.cpp +++ b/src/libs/installer/remoteserverconnection.cpp @@ -596,6 +596,10 @@ void RemoteServerConnection::handleArchive(QIODevice *socket, const QString &com archive->workerAddDataBlock(buff); } else if (command == QLatin1String(Protocol::AbstractArchiveSetClientDataAtEnd)) { archive->workerSetDataAtEnd(); + } else if (command == QLatin1String(Protocol::AbstractArchiveSetFilePosition)) { + qint64 pos; + data >> pos; + archive->workerSetFilePosition(pos); } else if (command == QLatin1String(Protocol::AbstractArchiveWorkerStatus)) { sendData(socket, static_cast(archive->workerStatus())); } else if (command == QLatin1String(Protocol::AbstractArchiveCancel)) { diff --git a/src/libs/installer/remoteserverconnection_p.h b/src/libs/installer/remoteserverconnection_p.h index dc6d794b6..977a64711 100644 --- a/src/libs/installer/remoteserverconnection_p.h +++ b/src/libs/installer/remoteserverconnection_p.h @@ -143,6 +143,8 @@ private: this, &AbstractArchiveSignalReceiver::onCompletedChanged); connect(archive, &LibArchiveArchive::dataBlockRequested, this, &AbstractArchiveSignalReceiver::onDataBlockRequested); + connect(archive, &LibArchiveArchive::seekRequested, + this, &AbstractArchiveSignalReceiver::onSeekRequested); connect(archive, &LibArchiveArchive::workerFinished, this, &AbstractArchiveSignalReceiver::onWorkerFinished); } @@ -169,6 +171,14 @@ private Q_SLOTS: m_receivedSignals.append(QLatin1String(Protocol::AbstractArchiveSignalDataBlockRequested)); } + void onSeekRequested(qint64 offset, int whence) + { + QMutexLocker _(&m_lock); + m_receivedSignals.append(QLatin1String(Protocol::AbstractArchiveSignalSeekRequested)); + m_receivedSignals.append(offset); + m_receivedSignals.append(whence); + } + void onWorkerFinished() { QMutexLocker _(&m_lock); -- cgit v1.2.3 From 6cfd80664a8db1549db61bc090eba7d40d6c8360 Mon Sep 17 00:00:00 2001 From: Arttu Tarkiainen Date: Tue, 26 Oct 2021 12:50:05 +0300 Subject: Fix qdoc warnings introduced by the archive handling changes Change-Id: I47d24c72317bed594b22b234be75d0359f2e2b98 Reviewed-by: Katja Marttila Reviewed-by: Leena Miettinen --- src/libs/installer/abstractarchive.cpp | 2 +- src/libs/installer/lib7z_facade.cpp | 18 ++++++++++++------ src/libs/installer/libarchivewrapper.cpp | 13 ------------- src/libs/installer/libarchivewrapper_p.cpp | 4 ++-- 4 files changed, 15 insertions(+), 22 deletions(-) (limited to 'src/libs/installer') diff --git a/src/libs/installer/abstractarchive.cpp b/src/libs/installer/abstractarchive.cpp index dd9b8e625..f2b4300c4 100644 --- a/src/libs/installer/abstractarchive.cpp +++ b/src/libs/installer/abstractarchive.cpp @@ -65,7 +65,7 @@ namespace QInstaller { */ /*! - \fn QInstaller::AbstractArchive::completedChanged(quint64 completed, quint64 total) + \fn QInstaller::AbstractArchive::completedChanged(const quint64 completed, const quint64 total) The ratio of \a completed entries from \a total changed. Subclasses should emit this whenever the progress changes. diff --git a/src/libs/installer/lib7z_facade.cpp b/src/libs/installer/lib7z_facade.cpp index 17176d7b0..6d1b6a57d 100644 --- a/src/libs/installer/lib7z_facade.cpp +++ b/src/libs/installer/lib7z_facade.cpp @@ -188,12 +188,6 @@ namespace Lib7z { Prints string \a s. */ -/*! - \fn bool Lib7z::operator==(const File &lhs, const File &rhs); - - Returns \c true if \a lhs and \a rhs are equal; otherwise returns \c false. -*/ - // -- 7z init codecs, archives std::once_flag gOnceFlag; @@ -769,6 +763,18 @@ STDMETHODIMP ExtractCallback::SetOperationResult(Int32 /*resultEOperationResult* File is a tmp file. */ +/*! + \typedef Lib7z::Compression + + Synonym for QInstaller::CompressionLevel +*/ + +/*! + \typedef Lib7z::File + + Synonym for QInstaller::ArchiveEntry +*/ + /*! \namespace Lib7z \inmodule QtInstallerFramework diff --git a/src/libs/installer/libarchivewrapper.cpp b/src/libs/installer/libarchivewrapper.cpp index c259678ca..9fbbeb889 100644 --- a/src/libs/installer/libarchivewrapper.cpp +++ b/src/libs/installer/libarchivewrapper.cpp @@ -44,19 +44,6 @@ namespace QInstaller { where the object was created. */ -/*! - \fn QInstaller::LibArchiveWrapper::currentEntryChanged(const QString &filename) - - Current entry changed to \a filename. Emitted when the entry to process is changed. -*/ - -/*! - \fn QInstaller::LibArchiveWrapper::completedChanged(quint64 completed, quint64 total) - - The ratio of \a completed entries from \a total changed. - Emitted when the progress changes. -*/ - /*! Constructs an archive object representing an archive file specified by \a filename with \a parent as the parent object. diff --git a/src/libs/installer/libarchivewrapper_p.cpp b/src/libs/installer/libarchivewrapper_p.cpp index 942e948e8..75bbddbe8 100644 --- a/src/libs/installer/libarchivewrapper_p.cpp +++ b/src/libs/installer/libarchivewrapper_p.cpp @@ -41,13 +41,13 @@ namespace QInstaller { */ /*! - \fn QInstaller::ArchiveWrapper::dataBlockRequested() + \fn QInstaller::LibArchiveWrapperPrivate::dataBlockRequested() Emitted when the server process has requested another data block. */ /*! - \fn QInstaller::ArchiveWrapper::remoteWorkerFinished() + \fn QInstaller::LibArchiveWrapperPrivate::remoteWorkerFinished() Emitted when the server process has finished extracting an archive. */ -- cgit v1.2.3 From 8bd9037a6be6dbea7940ac54b4aba9ec3df4b732 Mon Sep 17 00:00:00 2001 From: Arttu Tarkiainen Date: Wed, 27 Oct 2021 13:39:52 +0300 Subject: Fix symlink handling when packaging Zip archives archive_write_header() will write the complete symlink to the archive, the client application should not try to write any data for symlinks or if archive_entry_size() is zero. The tar.* archives were not affected by this. Task-number: QTIFW-2382 Change-Id: I6a5e62ef4c7e650ad806f183556e39ac8ae8cdc3 Reviewed-by: Katja Marttila --- src/libs/installer/libarchivearchive.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libs/installer') diff --git a/src/libs/installer/libarchivearchive.cpp b/src/libs/installer/libarchivearchive.cpp index 0d2619c7d..4147214a8 100644 --- a/src/libs/installer/libarchivearchive.cpp +++ b/src/libs/installer/libarchivearchive.cpp @@ -500,7 +500,7 @@ bool LibArchiveArchive::create(const QStringList &data) if (status < ARCHIVE_OK) throw Error(QLatin1String(archive_error_string(writer.get()))); - if (fileOrDir.isDir()) + if (fileOrDir.isDir() || fileOrDir.isSymLink() || archive_entry_size(entry.get()) == 0) continue; // nothing to copy QFile file(pathWithoutNamespace(QLatin1String(archive_entry_sourcepath(entry.get())))); -- cgit v1.2.3 From 002b2e15d05a1a6784595855408c331531f03746 Mon Sep 17 00:00:00 2001 From: Arttu Tarkiainen Date: Wed, 27 Oct 2021 15:42:14 +0300 Subject: LibArchiveWrapper: use local zero-timer for processing server signals Now that the server process may request file seeks in addition to reads for archive formats supporting them, the interval which we process the requests will have a big impact on the extracting speed. Also shrink the read buffer as its size isn't as significant for the performance after this change. Task-number: QTIFW-2384 Change-Id: Iaf296833c6ff1acfc666a6e82f661e1a40c77b61 Reviewed-by: Katja Marttila --- src/libs/installer/libarchivewrapper_p.cpp | 15 +++++++-------- src/libs/installer/libarchivewrapper_p.h | 1 - 2 files changed, 7 insertions(+), 9 deletions(-) (limited to 'src/libs/installer') diff --git a/src/libs/installer/libarchivewrapper_p.cpp b/src/libs/installer/libarchivewrapper_p.cpp index 75bbddbe8..30f81554a 100644 --- a/src/libs/installer/libarchivewrapper_p.cpp +++ b/src/libs/installer/libarchivewrapper_p.cpp @@ -77,7 +77,6 @@ LibArchiveWrapperPrivate::LibArchiveWrapperPrivate() */ LibArchiveWrapperPrivate::~LibArchiveWrapperPrivate() { - m_timer.stop(); } /*! @@ -140,6 +139,10 @@ QString LibArchiveWrapperPrivate::errorString() const bool LibArchiveWrapperPrivate::extract(const QString &dirPath, const quint64 totalFiles) { if (connectToServer()) { + QTimer timer; + connect(&timer, &QTimer::timeout, this, &LibArchiveWrapperPrivate::processSignals); + timer.start(); + m_lock.lockForWrite(); callRemoteMethod(QLatin1String(Protocol::AbstractArchiveExtract), dirPath, totalFiles); m_lock.unlock(); @@ -148,6 +151,7 @@ bool LibArchiveWrapperPrivate::extract(const QString &dirPath, const quint64 tot connect(this, &LibArchiveWrapperPrivate::remoteWorkerFinished, &loop, &QEventLoop::quit); loop.exec(); } + timer.stop(); return (workerStatus() == ExtractWorker::Success); } return m_archive.extract(dirPath, totalFiles); @@ -262,7 +266,7 @@ void LibArchiveWrapperPrivate::processSignals() */ void LibArchiveWrapperPrivate::onDataBlockRequested() { - constexpr quint64 blockSize = 10 * 1024 * 1024; // 10MB + constexpr quint64 blockSize = 1024 * 1024; // 1MB QFile *const file = &m_archive.m_data->file; if (!file->isOpen() || file->isSequential()) { @@ -327,15 +331,10 @@ void LibArchiveWrapperPrivate::onSeekRequested(qint64 offset, int whence) } /*! - Starts the timer to process server-side signals and connects handler - signals for the matching signals of the wrapper object. + Connects handler signals for the matching signals of the wrapper object. */ void LibArchiveWrapperPrivate::init() { - m_timer.start(250); - QObject::connect(&m_timer, &QTimer::timeout, - this, &LibArchiveWrapperPrivate::processSignals); - QObject::connect(&m_archive, &LibArchiveArchive::currentEntryChanged, this, &LibArchiveWrapperPrivate::currentEntryChanged); QObject::connect(&m_archive, &LibArchiveArchive::completedChanged, diff --git a/src/libs/installer/libarchivewrapper_p.h b/src/libs/installer/libarchivewrapper_p.h index 722c91f17..4277cd4f9 100644 --- a/src/libs/installer/libarchivewrapper_p.h +++ b/src/libs/installer/libarchivewrapper_p.h @@ -86,7 +86,6 @@ private: ExtractWorker::Status workerStatus() const; private: - QTimer m_timer; mutable QReadWriteLock m_lock; LibArchiveArchive m_archive; -- cgit v1.2.3 From 6cd1ff494d4d7aadc12204789407679aa065b4a6 Mon Sep 17 00:00:00 2001 From: Arttu Tarkiainen Date: Thu, 28 Oct 2021 12:32:54 +0300 Subject: Fix creating archives containing Windows shortcuts On Windows, QFileInfo::isSymLink() returns true for *.lnk files, which unlike symlinks contain data - when creating an archive the writing was incorrectly skipped. Also add test case for creating and extracting archives containing either symlinks or shortcuts. Change-Id: I3ebbd28e889ffa17ece7378c3812244a55df20d5 Reviewed-by: Qt CI Bot Reviewed-by: Katja Marttila --- src/libs/installer/libarchivearchive.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libs/installer') diff --git a/src/libs/installer/libarchivearchive.cpp b/src/libs/installer/libarchivearchive.cpp index 4147214a8..46200560b 100644 --- a/src/libs/installer/libarchivearchive.cpp +++ b/src/libs/installer/libarchivearchive.cpp @@ -500,7 +500,7 @@ bool LibArchiveArchive::create(const QStringList &data) if (status < ARCHIVE_OK) throw Error(QLatin1String(archive_error_string(writer.get()))); - if (fileOrDir.isDir() || fileOrDir.isSymLink() || archive_entry_size(entry.get()) == 0) + if (fileOrDir.isDir() || archive_entry_size(entry.get()) == 0) continue; // nothing to copy QFile file(pathWithoutNamespace(QLatin1String(archive_entry_sourcepath(entry.get())))); -- cgit v1.2.3 From d02dcbd47530ce7415668ba35a2f378bf12aef15 Mon Sep 17 00:00:00 2001 From: Arttu Tarkiainen Date: Tue, 2 Nov 2021 17:12:05 +0200 Subject: Libarchive: Fix extracting hard links pointing to files in archive Since we already adjust the output path for archive entries, libarchive would fail with the error string "Hard-link target '...' does not exist" for hard links referring to extracted files. Fix by also adjusting the hard link target paths. Task-number: QTIFW-2403 Change-Id: I8f78117c5b0707a70c76433ca1c1483ea49b432b Reviewed-by: Katja Marttila --- src/libs/installer/libarchivearchive.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/libs/installer') diff --git a/src/libs/installer/libarchivearchive.cpp b/src/libs/installer/libarchivearchive.cpp index 46200560b..d3a79bd40 100644 --- a/src/libs/installer/libarchivearchive.cpp +++ b/src/libs/installer/libarchivearchive.cpp @@ -123,6 +123,12 @@ void ExtractWorker::extract(const QString &dirPath, const quint64 totalFiles) const QString outputPath = dirPath + QDir::separator() + QString::fromLocal8Bit(current); archive_entry_set_pathname(entry, outputPath.toLocal8Bit()); + const char *hardlink = archive_entry_hardlink(entry); + if (hardlink) { + const QString hardLinkPath = dirPath + QDir::separator() + QString::fromLocal8Bit(hardlink); + archive_entry_set_hardlink(entry, hardLinkPath.toLocal8Bit()); + } + emit currentEntryChanged(outputPath); if (!writeEntry(reader.get(), writer.get(), entry)) return; @@ -440,6 +446,12 @@ bool LibArchiveArchive::extract(const QString &dirPath, const quint64 totalFiles const QString outputPath = dirPath + QDir::separator() + QString::fromLocal8Bit(current); archive_entry_set_pathname(entry, outputPath.toLocal8Bit()); + const char *hardlink = archive_entry_hardlink(entry); + if (hardlink) { + const QString hardLinkPath = dirPath + QDir::separator() + QString::fromLocal8Bit(hardlink); + archive_entry_set_hardlink(entry, hardLinkPath.toLocal8Bit()); + } + emit currentEntryChanged(outputPath); if (!writeEntry(reader.get(), writer.get(), entry)) throw Error(errorString()); // appropriate error string set in writeEntry() -- cgit v1.2.3