From afee8527caea5e367c134ea03da0f51240942171 Mon Sep 17 00:00:00 2001 From: Arttu Tarkiainen Date: Wed, 31 Aug 2022 13:06:53 +0300 Subject: Fix typo resulting in accessing wrong operation result container Fortunately no reported issues yet that would have been caused by this. Change-Id: I0ee9cb368600f660eb7c048e8cf3df5d31e43b4f Reviewed-by: Katja Marttila --- src/libs/installer/packagemanagercore_p.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libs') diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index 571072bea..d90dfdec2 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -2311,7 +2311,7 @@ void PackageManagerCorePrivate::unpackComponents(const QList &compo runner.setType(Operation::Perform); const QHash results = runner.run(); - const OperationList performedOperations = backupResults.keys(); + const OperationList performedOperations = results.keys(); QString error; for (auto &operation : performedOperations) { -- cgit v1.2.3 From b15f069996610481a6ae8aaca9b174504ac68135 Mon Sep 17 00:00:00 2001 From: Arttu Tarkiainen Date: Wed, 31 Aug 2022 12:44:40 +0300 Subject: Windows: fix installation error with concurrent Extract operations There was an issue with the Extract operations when using the same "targetDir" argument for multiple archives. The DirectoryGuard object creating the missing leading directories would occasionally run into a race condition when multiple threads competed with creating the directories. Fix by adding installer specific implementation similar to QDir::mkpath(), but which checks if the directory was created elsewhere at every directory level. Also convert an existing similar case with the Extract operation to use the new function. Task-number: QTIFW-2752 Change-Id: I4451e931309edb536294314b11c903189dacf2f0 Reviewed-by: Katja Marttila --- src/libs/installer/directoryguard.cpp | 4 +-- src/libs/installer/extractarchiveoperation.cpp | 15 +-------- src/libs/installer/fileutils.cpp | 46 ++++++++++++++++++++++++++ src/libs/installer/fileutils.h | 1 + 4 files changed, 50 insertions(+), 16 deletions(-) (limited to 'src/libs') diff --git a/src/libs/installer/directoryguard.cpp b/src/libs/installer/directoryguard.cpp index 9c97130a4..014d213d7 100644 --- a/src/libs/installer/directoryguard.cpp +++ b/src/libs/installer/directoryguard.cpp @@ -28,6 +28,7 @@ #include "directoryguard.h" +#include "fileutils.h" #include "globals.h" #include "errors.h" @@ -92,8 +93,7 @@ QStringList DirectoryGuard::tryCreate() toCreate = QDir(p); } - QDir dir(m_path); - m_created = dir.mkpath(m_path); + m_created = QInstaller::createDirectoryWithParents(m_path); if (!m_created) { throw Error(QCoreApplication::translate("DirectoryGuard", "Cannot create directory \"%1\".").arg(QDir::toNativeSeparators(m_path))); diff --git a/src/libs/installer/extractarchiveoperation.cpp b/src/libs/installer/extractarchiveoperation.cpp index 6b9ecb687..986b9d8c8 100644 --- a/src/libs/installer/extractarchiveoperation.cpp +++ b/src/libs/installer/extractarchiveoperation.cpp @@ -193,20 +193,7 @@ bool ExtractArchiveOperation::performOperation() QFileInfo targetDirectoryInfo(fileDirectory); - // We need to create the directory structure step-by-step to avoid a rare race condition - // on Windows. QDir::mkpath() doesn't check if the leading directories were created elsewhere - // (like from within another thread) after the initial check that the given path requires - // creating also parent directories. - // - // On Unix patforms this case is handled by QFileSystemEngine though. - QDir resourcesDir(resourcesPath); - if (!resourcesDir.exists()) - resourcesDir.mkdir(resourcesPath); - - QDir resourceFileDir(targetDirectoryInfo.absolutePath()); - if (!resourceFileDir.exists()) - resourceFileDir.mkdir(targetDirectoryInfo.absolutePath()); - + QInstaller::createDirectoryWithParents(targetDirectoryInfo.absolutePath()); setDefaultFilePermissions(resourcesPath, DefaultFilePermissions::Executable); setDefaultFilePermissions(targetDirectoryInfo.absolutePath(), DefaultFilePermissions::Executable); diff --git a/src/libs/installer/fileutils.cpp b/src/libs/installer/fileutils.cpp index 5a89073fc..11ae397fd 100644 --- a/src/libs/installer/fileutils.cpp +++ b/src/libs/installer/fileutils.cpp @@ -446,6 +446,52 @@ void QInstaller::mkpath(const QString &path) } } +/*! + \internal + + Creates directory \a path including all parent directories. Return \c true on + success, \c false otherwise. + + On Windows \c QDir::mkpath() doesn't check if the leading directories were created + elsewhere (i.e. in another thread) after the initial check that the given path + requires creating also parent directories, and returns \c false. + + On Unix platforms this case is handled different by QFileSystemEngine though, + which checks for \c EEXIST error code in case any of the recursive directories + could not be created. + + Compared to \c QInstaller::mkpath() and \c QDir::mkpath() this function checks if + each parent directory to-be-created were created elsewhere. +*/ +bool QInstaller::createDirectoryWithParents(const QString &path) +{ + if (path.isEmpty()) + return false; + + QFileInfo dirInfo(path); + if (dirInfo.exists() && dirInfo.isDir()) + return true; + + // bail out if we are at the root directory + if (dirInfo.isRoot()) + return false; + + QDir dir(path); + if (dir.mkdir(path)) + return true; + + // mkdir failed, try to create the parent directory + if (!createDirectoryWithParents(dirInfo.absolutePath())) + return false; + + // now try again + if (dir.mkdir(path)) + return true; + + // directory may be have also been created elsewhere + return (dirInfo.exists() && dirInfo.isDir()); +} + /*! \internal diff --git a/src/libs/installer/fileutils.h b/src/libs/installer/fileutils.h index 8b79ce052..1114cd60c 100644 --- a/src/libs/installer/fileutils.h +++ b/src/libs/installer/fileutils.h @@ -89,6 +89,7 @@ private: void INSTALLER_EXPORT mkdir(const QString &path); void INSTALLER_EXPORT mkpath(const QString &path); + bool INSTALLER_EXPORT createDirectoryWithParents(const QString &path); #ifdef Q_OS_MACOS void INSTALLER_EXPORT mkalias(const QString &path, const QString &alias); #endif -- cgit v1.2.3 From d0e03a6ea7c545e15b24de0915e0b153be24ed51 Mon Sep 17 00:00:00 2001 From: Katja Marttila Date: Thu, 8 Sep 2022 13:57:42 +0300 Subject: Attach to squish only when the port is separately given Attaching to squish will trigger firewall questions in the installer. Changing the attach behavior so that by default no attach is done, and user can run the installer with --squish-port if the attach is needed. Task-number: QTIFW-2746 Change-Id: I89f06a52b1ef95493e99084cb6080266b4eaf1dc Reviewed-by: Arttu Tarkiainen --- src/libs/installer/commandlineparser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libs') diff --git a/src/libs/installer/commandlineparser.cpp b/src/libs/installer/commandlineparser.cpp index a04891303..b40556f6c 100644 --- a/src/libs/installer/commandlineparser.cpp +++ b/src/libs/installer/commandlineparser.cpp @@ -220,8 +220,8 @@ CommandLineParser::CommandLineParser() QLatin1String("socketname, key"))); addOption(QCommandLineOption(QStringList() << CommandLineOptions::scSquishPortShort << CommandLineOptions::scSquishPortLong, - QLatin1String("Give a port where Squish can connect to. If no port is given, default port 11233 is " - "used. Note: To enable Squish support you first need to build IFW with SQUISH_PATH " + QLatin1String("Give a port where Squish can connect to. If no port is given, attach to squish " + "not done. Note: To enable Squish support you first need to build IFW with SQUISH_PATH " "parameter where SQUISH_PATH is pointing to your Squish installation folder: " "/bin/qmake -r SQUISH_PATH="), QLatin1String("port number"))); -- cgit v1.2.3 From 8c938ede3d7c834a4f65a983a4214a894784cdff Mon Sep 17 00:00:00 2001 From: Katja Marttila Date: Thu, 1 Sep 2022 15:56:26 +0300 Subject: Fix uninstallation of needed virtual components In some rare cases, both component to be uninstalled and component to be installed has dependency to same virtual component. In such case the virtual component should not be uninstalled. Change-Id: I3b826693d4a72d6765a5ac1ee9a3957fdf7415da Reviewed-by: Arttu Tarkiainen --- src/libs/installer/uninstallercalculator.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/libs') diff --git a/src/libs/installer/uninstallercalculator.cpp b/src/libs/installer/uninstallercalculator.cpp index 3de9f5b60..d54b5c2ab 100644 --- a/src/libs/installer/uninstallercalculator.cpp +++ b/src/libs/installer/uninstallercalculator.cpp @@ -205,7 +205,8 @@ void UninstallerCalculator::appendVirtualComponentsToUninstall(const bool revers // Check if installed or about to be updated -packages are dependant on the package const QList installDependants = m_core->installDependants(virtualComponent); for (Component *dependant : installDependants) { - if (dependant->isInstalled() && !m_componentsToUninstall.contains(dependant)) { + if ((dependant->isInstalled() && !m_componentsToUninstall.contains(dependant)) + || m_core->orderedComponentsToInstall().contains(dependant)) { required = true; break; } -- cgit v1.2.3 From f23bccb3bce725041bfea050e6a4ce9a907a2af0 Mon Sep 17 00:00:00 2001 From: Arttu Tarkiainen Date: Mon, 19 Sep 2022 14:07:03 +0300 Subject: Fix installer stalling when there's only one CPU core The installer operations are run in the global QThreadPool. The Operation::performOperation() implementation from "QtPatch" operation would call the Component::operations() method, that filtered the returned operation list with QtConcurrent::blockingFilter(). This would lock the installer when the global thread pool object was initialized with maxThreadCount of 1, with the only QThread object from the global pool already running the calling Operation::performOperation() function, which is waiting the result of Component::operations(). Fix by omitting usage of QtConcurrent::blockingFilter() and populating the returned operation list with std::copy_if - the components have usually only a handful operations each so this shouldn't be too noticeable of a performance regression. Task-number: QTIFW-2786 Change-Id: Ia6be9f6697310d3f955a8199712c54f345407067 Reviewed-by: Katja Marttila --- src/libs/installer/component.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/libs') diff --git a/src/libs/installer/component.cpp b/src/libs/installer/component.cpp index c7dfa65da..37abcea8a 100644 --- a/src/libs/installer/component.cpp +++ b/src/libs/installer/component.cpp @@ -1082,10 +1082,12 @@ OperationList Component::operations(const Operation::OperationGroups &mask) cons d->m_operations.append(d->m_licenseOperation); } } - OperationList operations = d->m_operations; - QtConcurrent::blockingFilter(operations, [&](const Operation *op) { - return mask.testFlag(op->group()); - }); + OperationList operations; + std::copy_if(d->m_operations.begin(), d->m_operations.end(), std::back_inserter(operations), + [&](const Operation *op) { + return mask.testFlag(op->group()); + } + ); return operations; } -- cgit v1.2.3 From db9c61cc1d2d309c801487de22bc56499c7451ab Mon Sep 17 00:00:00 2001 From: Katja Marttila Date: Tue, 1 Nov 2022 15:50:45 +0200 Subject: Macos: Fix maintenance tool install from repository Maintenancetool can be either app bundle or executable itself. In case the maintenancetool is the executable itself, we need to create the app bundle in the code. Task-number: QTIFW-2856 Change-Id: Ib884cbd7d7f18b9503938114d56f3c396c8d3bd6 Reviewed-by: Arttu Tarkiainen --- src/libs/installer/packagemanagercore_p.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libs') diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index 64af77a98..41eccf799 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -1431,6 +1431,7 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper << error.message(); } } else { + writeMaintenanceToolAppBundle(performedOperations); QFile replacementBinary(installerBaseBinary); try { QInstaller::openForRead(&replacementBinary); -- cgit v1.2.3