summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKatja Marttila <katja.marttila@qt.io>2019-11-20 07:53:09 +0200
committerKatja Marttila <katja.marttila@qt.io>2019-11-20 07:53:09 +0200
commite238e764331197ec48e9b8b6c29368ee40efe82c (patch)
treed42cbdcd9b09fc7a047528ca7414bf3de5db0489 /src
parent48a43de0be59639b16962ec04f1a4e07141abaf0 (diff)
parent7bac504eb60c9783f29632c4f405eb61ca9236c5 (diff)
Merge remote-tracking branch 'origin/3.1' into master
Diffstat (limited to 'src')
-rw-r--r--src/libs/installer/component.cpp12
-rw-r--r--src/libs/installer/componentselectionpage_p.cpp28
-rw-r--r--src/libs/installer/componentselectionpage_p.h3
-rw-r--r--src/libs/installer/createdesktopentryoperation.cpp3
-rw-r--r--src/libs/installer/createlocalrepositoryoperation.cpp3
-rw-r--r--src/libs/installer/environmentvariablesoperation.cpp14
-rw-r--r--src/libs/installer/extractarchiveoperation.cpp96
-rw-r--r--src/libs/installer/extractarchiveoperation.h5
-rw-r--r--src/libs/installer/extractarchiveoperation_p.h8
-rw-r--r--src/libs/installer/fileutils.cpp33
-rw-r--r--src/libs/installer/fileutils.h10
-rw-r--r--src/libs/installer/installercalculator.cpp8
-rw-r--r--src/libs/installer/link.cpp11
-rw-r--r--src/libs/installer/packagemanagercore.cpp9
-rw-r--r--src/libs/installer/packagemanagercore.h1
-rw-r--r--src/libs/installer/packagemanagercore_p.cpp45
-rw-r--r--src/libs/installer/packagemanagercore_p.h1
-rw-r--r--src/libs/installer/utils.cpp3
-rw-r--r--src/libs/kdtools/localpackagehub.cpp6
-rw-r--r--src/sdk/installerbase.cpp28
20 files changed, 241 insertions, 86 deletions
diff --git a/src/libs/installer/component.cpp b/src/libs/installer/component.cpp
index 5a508f118..cd40d4a7b 100644
--- a/src/libs/installer/component.cpp
+++ b/src/libs/installer/component.cpp
@@ -1255,6 +1255,18 @@ bool Component::isAutoDependOn(const QSet<QString> &componentsToInstall) const
if (autoDependOnList.isEmpty())
return false;
+ // If there is an essential update and autodepend on is not for essential
+ // update component, do not add the autodependency to an installed component as
+ // essential updates needs to be installed first, otherwise non-essential components
+ // will be installed
+ if (packageManagerCore()->foundEssentialUpdate()) {
+ const QSet<QString> autoDependOnSet = autoDependOnList.toSet();
+ if (autoDependOnSet.intersects(componentsToInstall)) {
+ return true;
+ }
+ return false;
+ }
+
QSet<QString> components = componentsToInstall;
const QStringList installedPackages = d->m_core->localInstalledPackages().keys();
foreach (const QString &name, installedPackages)
diff --git a/src/libs/installer/componentselectionpage_p.cpp b/src/libs/installer/componentselectionpage_p.cpp
index 84349e4ad..917dae4c1 100644
--- a/src/libs/installer/componentselectionpage_p.cpp
+++ b/src/libs/installer/componentselectionpage_p.cpp
@@ -85,6 +85,7 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
m_descriptionVLayout->addWidget(m_descriptionScrollArea);
m_sizeLabel = new QLabel(q);
+ m_sizeLabel->setMargin(5);
m_sizeLabel->setWordWrap(true);
m_sizeLabel->setObjectName(QLatin1String("ComponentSizeLabel"));
m_descriptionVLayout->addWidget(m_sizeLabel);
@@ -128,8 +129,6 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
m_uncheckAll->setText(ComponentSelectionPage::tr("&Deselect All"));
buttonHLayout->addWidget(m_uncheckAll);
- m_treeViewVLayout->addLayout(buttonHLayout);
-
m_metadataProgressLabel = new QLabel();
m_metadataProgressLabel->hide();
m_treeViewVLayout->addWidget(m_metadataProgressLabel);
@@ -151,9 +150,12 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP
connect(q, &ComponentSelectionPage::left,
m_core, &PackageManagerCore::clearComponentsToInstallCalculated);
- m_mainHLayout = new QHBoxLayout(q);
- m_mainHLayout->addLayout(m_treeViewVLayout, 3);
- m_mainHLayout->addLayout(m_descriptionVLayout, 2);
+ m_mainGLayout = new QGridLayout(q);
+ m_mainGLayout->addLayout(buttonHLayout, 0, 1);
+ m_mainGLayout->addLayout(m_treeViewVLayout, 1, 1);
+ m_mainGLayout->addLayout(m_descriptionVLayout, 1, 2);
+ m_mainGLayout->setColumnStretch(1, 3);
+ m_mainGLayout->setColumnStretch(2, 2);
#ifdef INSTALLCOMPRESSED
allowCompressedRepositoryInstall();
@@ -200,6 +202,7 @@ void ComponentSelectionPagePrivate::setupCategoryLayout()
return;
m_categoryWidget = new QWidget();
QVBoxLayout *vLayout = new QVBoxLayout;
+ vLayout->setContentsMargins(0, 0, 0, 0);
m_categoryWidget->setLayout(vLayout);
m_categoryGroupBox = new QGroupBox(q);
m_categoryGroupBox->setTitle(m_core->settings().repositoryCategoryDisplayName());
@@ -224,7 +227,7 @@ void ComponentSelectionPagePrivate::setupCategoryLayout()
vLayout->addWidget(m_categoryGroupBox);
vLayout->addStretch();
- m_mainHLayout->insertWidget(0, m_categoryWidget);
+ m_mainGLayout->addWidget(m_categoryWidget, 1, 0);
}
void ComponentSelectionPagePrivate::showCategoryLayout(bool show)
@@ -372,19 +375,19 @@ void ComponentSelectionPagePrivate::updateWidgetVisibility(bool show)
QSpacerItem *verticalSpacer2 = new QSpacerItem(0, 0, QSizePolicy::Minimum,
QSizePolicy::Expanding);
m_treeViewVLayout->addSpacerItem(verticalSpacer2);
- m_mainHLayout->removeItem(m_descriptionVLayout);
+ m_mainGLayout->removeItem(m_descriptionVLayout);
//Hide next button during category fetch
QPushButton *const b = qobject_cast<QPushButton *>(q->gui()->button(QWizard::NextButton));
b->setEnabled(!show);
} else {
QSpacerItem *item = m_treeViewVLayout->spacerItem();
m_treeViewVLayout->removeItem(item);
- m_mainHLayout->addLayout(m_descriptionVLayout, 2);
+ m_mainGLayout->addLayout(m_descriptionVLayout, 1, 2);
//Call completeChanged() to determine if NextButton should be shown or not after category fetch.
q->completeChanged();
}
if (m_categoryWidget)
- m_categoryWidget->setDisabled(show);
+ m_categoryWidget->setVisible(!show);
m_progressBar->setVisible(show);
m_metadataProgressLabel->setVisible(show);
@@ -392,11 +395,16 @@ void ComponentSelectionPagePrivate::updateWidgetVisibility(bool show)
m_checkDefault->setVisible(!show);
m_checkAll->setVisible(!show);
m_uncheckAll->setVisible(!show);
- m_descriptionLabel->setVisible(!show);
+ m_descriptionScrollArea->setVisible(!show);
m_sizeLabel->setVisible(!show);
if (QAbstractButton *bspButton = q->gui()->button(QWizard::CustomButton2))
bspButton->setEnabled(!show);
+
+ // In macOS 10.12 the widgets are not hidden if those are not updated immediately
+#ifdef Q_OS_MACOS
+ q->repaint();
+#endif
}
void ComponentSelectionPagePrivate::fetchRepositoryCategories()
diff --git a/src/libs/installer/componentselectionpage_p.h b/src/libs/installer/componentselectionpage_p.h
index 6169a06f5..591cd08f7 100644
--- a/src/libs/installer/componentselectionpage_p.h
+++ b/src/libs/installer/componentselectionpage_p.h
@@ -44,6 +44,7 @@ class QListWidgetItem;
class QProgressBar;
class QVBoxLayout;
class QHBoxLayout;
+class QGridLayout;
namespace QInstaller {
@@ -98,7 +99,7 @@ private:
QGroupBox *m_categoryGroupBox;
QLabel *m_metadataProgressLabel;
QProgressBar *m_progressBar;
- QHBoxLayout *m_mainHLayout;
+ QGridLayout *m_mainGLayout;
QVBoxLayout *m_treeViewVLayout;
bool m_allowCompressedRepositoryInstall;
ComponentModel *m_allModel;
diff --git a/src/libs/installer/createdesktopentryoperation.cpp b/src/libs/installer/createdesktopentryoperation.cpp
index 17e165777..e6d3b16e7 100644
--- a/src/libs/installer/createdesktopentryoperation.cpp
+++ b/src/libs/installer/createdesktopentryoperation.cpp
@@ -137,8 +137,7 @@ bool CreateDesktopEntryOperation::performOperation()
return false;
}
- QFile::setPermissions(filename, QFile::ReadOwner | QFile::WriteOwner | QFile::ReadUser | QFile::ReadGroup
- | QFile::ReadOther | QFile::ExeOwner | QFile::ExeGroup | QFile::ExeOther);
+ setDefaultFilePermissions(filename, DefaultFilePermissions::Executable);
QTextStream stream(&file);
stream.setCodec("UTF-8");
diff --git a/src/libs/installer/createlocalrepositoryoperation.cpp b/src/libs/installer/createlocalrepositoryoperation.cpp
index 0eabc8c35..8f9aa1ddb 100644
--- a/src/libs/installer/createlocalrepositoryoperation.cpp
+++ b/src/libs/installer/createlocalrepositoryoperation.cpp
@@ -82,8 +82,7 @@ static void fixPermissions(const QString &repoPath)
if (!it.fileInfo().isFile())
continue;
- if (!QFile::setPermissions(it.filePath(), QFile::ReadOwner | QFile::WriteOwner
- | QFile::ReadUser | QFile::WriteUser | QFile::ReadGroup | QFile::ReadOther)) {
+ if (!setDefaultFilePermissions(it.filePath(), DefaultFilePermissions::NonExecutable)) {
throw Error(CreateLocalRepositoryOperation::tr("Cannot set permissions for file \"%1\".")
.arg(QDir::toNativeSeparators(it.filePath())));
}
diff --git a/src/libs/installer/environmentvariablesoperation.cpp b/src/libs/installer/environmentvariablesoperation.cpp
index 006ea3762..1f3b56d52 100644
--- a/src/libs/installer/environmentvariablesoperation.cpp
+++ b/src/libs/installer/environmentvariablesoperation.cpp
@@ -152,8 +152,18 @@ UpdateOperation::Error undoSetting(const QString &regPath,
SettingsType registry(regPath, QSettingsWrapper::NativeFormat);
actual = registry.value(name).toString();
}
- if (actual != value) //key changed, don't undo
- return UpdateOperation::UserDefinedError;
+
+ if (actual != value)
+ {
+ //For unknown reason paths with @TargetDir@ variable get modified
+ //so that Windows file separators get replaced with unix style separators,
+ //fix separators before matching to actual value in register
+ QString tempValue = value;
+ QString fixedValue = tempValue.replace(QLatin1Char('/'), QLatin1Char('\\'));
+
+ if (actual != fixedValue) //key changed, don't undo
+ return UpdateOperation::UserDefinedError;
+ }
bool error = false;
if (handleRegExpandSz(regPath, name, oldValue, errorString, &error))
diff --git a/src/libs/installer/extractarchiveoperation.cpp b/src/libs/installer/extractarchiveoperation.cpp
index 12608a0d1..e790920d1 100644
--- a/src/libs/installer/extractarchiveoperation.cpp
+++ b/src/libs/installer/extractarchiveoperation.cpp
@@ -28,6 +28,8 @@
#include "extractarchiveoperation_p.h"
+#include "constants.h"
+
#include <QEventLoop>
#include <QThreadPool>
#include <QFileInfo>
@@ -57,7 +59,6 @@ bool ExtractArchiveOperation::performOperation()
Receiver receiver;
Callback callback;
- connect(&callback, &Callback::currentFileChanged, this, &ExtractArchiveOperation::fileFinished);
connect(&callback, &Callback::progressChanged, this, &ExtractArchiveOperation::progressChanged);
if (PackageManagerCore *core = packageManager()) {
@@ -68,8 +69,6 @@ bool ExtractArchiveOperation::performOperation()
connect(runnable, &Runnable::finished, &receiver, &Receiver::runnableFinished,
Qt::QueuedConnection);
- m_files.clear();
-
QFileInfo fileInfo(archivePath);
emit outputTextChanged(tr("Extracting \"%1\"").arg(fileInfo.fileName()));
@@ -83,7 +82,46 @@ bool ExtractArchiveOperation::performOperation()
receiver.runnableFinished(true, QString());
}
- setValue(QLatin1String("files"), m_files);
+ // Write all file names which belongs to a package to a separate file and only the separate
+ // filename to a .dat file. There can be enormous amount of files in a package, which makes
+ // the dat file very slow to read and write. The .dat file is read into memory in startup,
+ // writing the file names to a separate file we don't need to load all the file names into
+ // memory as we need those only in uninstall. This will save a lot of memory.
+ // Parse a file and directorory structure using archivepath syntax
+ // installer://<component_name>/<filename>.7z Resulting structure is:
+ // -installerResources (dir)
+ // -<component_name> (dir)
+ // -<filename>.txt (file)
+
+ QStringList files = callback.extractedFiles();
+
+ QString fileDirectory = targetDir + QLatin1String("/installerResources/") +
+ archivePath.section(QLatin1Char('/'), 1, 1, QString::SectionSkipEmpty) + QLatin1Char('/');
+ QString archiveFileName = archivePath.section(QLatin1Char('/'), 2, 2, QString::SectionSkipEmpty);
+ QFileInfo fileInfo2(archiveFileName);
+ QString suffix = fileInfo2.suffix();
+ archiveFileName.chop(suffix.length() + 1); // removes suffix (e.g. '.7z') from archive filename
+ QString fileName = archiveFileName + QLatin1String(".txt");
+
+ QFileInfo targetDirectoryInfo(fileDirectory);
+
+ QDir dir(targetDirectoryInfo.absolutePath());
+ if (!dir.exists()) {
+ dir.mkpath(targetDirectoryInfo.absolutePath());
+ }
+ QFile file(targetDirectoryInfo.absolutePath() + QLatin1Char('/') + fileName);
+ if (file.open(QIODevice::WriteOnly)) {
+ setDefaultFilePermissions(file.fileName(), DefaultFilePermissions::NonExecutable);
+ QDataStream out (&file);
+ for (int i = 0; i < files.count(); ++i) {
+ files[i] = replacePath(files.at(i), targetDir, QLatin1String(scRelocatable));
+ }
+ out << files;
+ setValue(QLatin1String("files"), file.fileName());
+ file.close();
+ } else {
+ qWarning() << "Cannot open file for writing " << file.fileName() << ":" << file.errorString();
+ }
// TODO: Use backups for rollback, too? Doesn't work for uninstallation though.
@@ -102,8 +140,46 @@ bool ExtractArchiveOperation::performOperation()
bool ExtractArchiveOperation::undoOperation()
{
Q_ASSERT(arguments().count() == 2);
- const QStringList files = value(QLatin1String("files")).toStringList();
+ // For backward compatibility, check if "files" can be converted to QStringList.
+ // If yes, files are listed in .dat instead of in a separate file.
+ bool useStringListType(value(QLatin1String("files")).type() == QVariant::StringList);
+ QStringList files;
+ if (useStringListType) {
+ files = value(QLatin1String("files")).toStringList();
+ startUndoProcess(files);
+ } else {
+ const QString filePath = value(QLatin1String("files")).toString();
+ QString targetDir = arguments().at(1);
+ // Does not change target on non macOS platforms.
+ if (QInstaller::isInBundle(targetDir, &targetDir))
+ targetDir = QDir::cleanPath(targetDir + QLatin1String("/.."));
+ QString fileName = replacePath(filePath, QLatin1String(scRelocatable), targetDir);
+ QFile file(fileName);
+
+ if (file.open(QIODevice::ReadOnly)) {
+ QDataStream in(&file);
+ in >> files;
+ for (int i = 0; i < files.count(); ++i)
+ files[i] = replacePath(files.at(i), QLatin1String(scRelocatable), targetDir);
+ startUndoProcess(files);
+ QFileInfo fileInfo(file);
+ file.remove();
+ QDir directory(fileInfo.absoluteDir());
+ if (directory.exists() && directory.isEmpty())
+ directory.rmdir(directory.path());
+ } else {
+ setError(UserDefinedError);
+ setErrorString(tr("Cannot open file \"%1\" for reading: %2")
+ .arg(QDir::toNativeSeparators(file.fileName())).arg(file.errorString()));
+ return false;
+ }
+ }
+ return true;
+}
+
+void ExtractArchiveOperation::startUndoProcess(const QStringList &files)
+{
WorkerThread *const thread = new WorkerThread(this, files);
connect(thread, &WorkerThread::currentFileChanged, this,
&ExtractArchiveOperation::outputTextChanged);
@@ -115,7 +191,6 @@ bool ExtractArchiveOperation::undoOperation()
thread->start();
loop.exec();
thread->deleteLater();
- return true;
}
bool ExtractArchiveOperation::testOperation()
@@ -123,13 +198,4 @@ bool ExtractArchiveOperation::testOperation()
return true;
}
-/*!
- This slot is direct connected to the caller so please don't call it from another thread in the
- same time.
-*/
-void ExtractArchiveOperation::fileFinished(const QString &filename)
-{
- m_files.prepend(filename);
-}
-
} // namespace QInstaller
diff --git a/src/libs/installer/extractarchiveoperation.h b/src/libs/installer/extractarchiveoperation.h
index 3e75a9bb9..e706159ed 100644
--- a/src/libs/installer/extractarchiveoperation.h
+++ b/src/libs/installer/extractarchiveoperation.h
@@ -52,11 +52,10 @@ Q_SIGNALS:
void outputTextChanged(const QString &progress);
void progressChanged(double);
-private Q_SLOTS:
- void fileFinished(const QString &progress);
+private:
+ void startUndoProcess(const QStringList &files);
private:
- QStringList m_files;
class Callback;
class Runnable;
class Receiver;
diff --git a/src/libs/installer/extractarchiveoperation_p.h b/src/libs/installer/extractarchiveoperation_p.h
index f333da366..9cc07246f 100644
--- a/src/libs/installer/extractarchiveoperation_p.h
+++ b/src/libs/installer/extractarchiveoperation_p.h
@@ -97,6 +97,10 @@ public:
return m_backupFiles;
}
+ QStringList extractedFiles() const {
+ return m_extractedFiles;
+ }
+
public slots:
void statusChanged(QInstaller::PackageManagerCore::Status status)
{
@@ -113,13 +117,12 @@ public slots:
}
signals:
- void currentFileChanged(const QString &filename);
void progressChanged(double progress);
private:
void setCurrentFile(const QString &filename) Q_DECL_OVERRIDE
{
- emit currentFileChanged(QDir::toNativeSeparators(filename));
+ m_extractedFiles.prepend(QDir::toNativeSeparators(filename));
}
static QString generateBackupName(const QString &fn)
@@ -157,6 +160,7 @@ private:
private:
HRESULT m_state = S_OK;
BackupFiles m_backupFiles;
+ QStringList m_extractedFiles;
};
class ExtractArchiveOperation::Runnable : public QObject, public QRunnable
diff --git a/src/libs/installer/fileutils.cpp b/src/libs/installer/fileutils.cpp
index 18c5f90fd..b11768494 100644
--- a/src/libs/installer/fileutils.cpp
+++ b/src/libs/installer/fileutils.cpp
@@ -293,6 +293,39 @@ void QInstaller::removeSystemGeneratedFiles(const QString &path)
#endif
}
+/*!
+ Sets permissions of file or directory specified by \a fileName to \c 644 or \c 755
+ based by the value of \a permissions.
+*/
+bool QInstaller::setDefaultFilePermissions(const QString &fileName, DefaultFilePermissions permissions)
+{
+ QFile file(fileName);
+ return setDefaultFilePermissions(&file, permissions);
+}
+
+/*!
+ Sets permissions of file or directory specified by \a file to \c 644 or \c 755
+ based by the value of \a permissions. This is effective only on Unix platforms
+ as \c setPermissions() does not manipulate ACLs. On Windows NTFS volumes this
+ only unsets the legacy read-only flag regardless of the value of \a permissions.
+*/
+bool QInstaller::setDefaultFilePermissions(QFile *file, DefaultFilePermissions permissions)
+{
+ if (!file->exists()) {
+ qWarning() << "Target" << file->fileName() << "does not exists.";
+ return false;
+ }
+ if (file->permissions() == static_cast<QFileDevice::Permission>(permissions))
+ return true;
+
+ if (!file->setPermissions(static_cast<QFileDevice::Permission>(permissions))) {
+ qWarning() << "Cannot set default permissions for target"
+ << file->fileName() << ":" << file->errorString();
+ return false;
+ }
+ return true;
+}
+
void QInstaller::copyDirectoryContents(const QString &sourceDir, const QString &targetDir)
{
Q_ASSERT(QFileInfo(sourceDir).isDir());
diff --git a/src/libs/installer/fileutils.h b/src/libs/installer/fileutils.h
index ae08f5ff3..3607a189b 100644
--- a/src/libs/installer/fileutils.h
+++ b/src/libs/installer/fileutils.h
@@ -36,10 +36,17 @@
QT_BEGIN_NAMESPACE
class QFileInfo;
+class QFile;
class QUrl;
QT_END_NAMESPACE
namespace QInstaller {
+
+enum DefaultFilePermissions {
+ NonExecutable = 0x6644,
+ Executable = 0x7755
+};
+
class INSTALLER_EXPORT TempDirDeleter
{
public:
@@ -80,6 +87,9 @@ private:
void INSTALLER_EXPORT removeDirectoryThreaded(const QString &path, bool ignoreErrors = false);
void INSTALLER_EXPORT removeSystemGeneratedFiles(const QString &path);
+ bool INSTALLER_EXPORT setDefaultFilePermissions(const QString &fileName, DefaultFilePermissions permissions);
+ bool INSTALLER_EXPORT setDefaultFilePermissions(QFile *file, DefaultFilePermissions permissions);
+
QString INSTALLER_EXPORT generateTemporaryFileName(const QString &templ=QString());
void INSTALLER_EXPORT moveDirectoryContents(const QString &sourceDir, const QString &targetDir);
diff --git a/src/libs/installer/installercalculator.cpp b/src/libs/installer/installercalculator.cpp
index db1f88563..a35cb99fb 100644
--- a/src/libs/installer/installercalculator.cpp
+++ b/src/libs/installer/installercalculator.cpp
@@ -158,6 +158,14 @@ bool InstallerCalculator::appendComponentsToInstall(const QList<Component *> &co
bool InstallerCalculator::appendComponentToInstall(Component *component, const QString &version)
{
QSet<QString> allDependencies = component->dependencies().toSet();
+ // All parents are kind of dependencies as well. If we select sub item in treeview, parent gets
+ // checked or partially checked as well. When adding component as dependency in script or
+ // config.xml we need to add the parent as dependency so the behavior is the same as in visual UI.
+ if (component->parentComponent() &&
+ !allDependencies.contains(component->parentComponent()->name()) &&
+ !m_visitedComponents.contains(component->parentComponent())) {
+ allDependencies.insert(component->parentComponent()->name());
+ }
QString requiredDependencyVersion = version;
foreach (const QString &dependencyComponentName, allDependencies) {
// PackageManagerCore::componentByName returns 0 if dependencyComponentName contains a
diff --git a/src/libs/installer/link.cpp b/src/libs/installer/link.cpp
index 62ba06cb2..0c79ec4c9 100644
--- a/src/libs/installer/link.cpp
+++ b/src/libs/installer/link.cpp
@@ -146,9 +146,12 @@ Link createJunction(const QString &linkPath, const QString &targetPath)
return Link(linkPath);
}
- const QString szDestDir = QString::fromLatin1("\\??\\").arg(targetPath).replace(QLatin1Char('/'),
+ const QString szDestDir = QString::fromLatin1("\\??\\%1").arg(targetPath).replace(QLatin1Char('/'),
QLatin1Char('\\'));
+ // Get string length in bytes, not in characters count
+ const size_t destDirBytes = szDestDir.size() * sizeof(ushort);
+
// Allocates a block of memory for an array of num elements(1) and initializes all its bits to zero.
REPARSE_DATA_BUFFER* reparseStructData = (REPARSE_DATA_BUFFER*)calloc(1,
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
@@ -156,11 +159,11 @@ Link createJunction(const QString &linkPath, const QString &targetPath)
reparseStructData->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
reparseStructData->MountPointReparseBuffer.PrintNameLength = 0;
reparseStructData->MountPointReparseBuffer.SubstituteNameOffset = 0;
- reparseStructData->MountPointReparseBuffer.SubstituteNameLength = szDestDir.length();
- reparseStructData->MountPointReparseBuffer.PrintNameOffset = szDestDir.length() + sizeof(WCHAR);
+ reparseStructData->MountPointReparseBuffer.SubstituteNameLength = destDirBytes;
+ reparseStructData->MountPointReparseBuffer.PrintNameOffset = destDirBytes + sizeof(WCHAR);
uint spaceAfterGeneralData = sizeof(USHORT) * 5 + sizeof(WCHAR); //should be 12
- reparseStructData->ReparseDataLength = szDestDir.length() + spaceAfterGeneralData;
+ reparseStructData->ReparseDataLength = destDirBytes + spaceAfterGeneralData;
#ifndef Q_CC_MINGW
StringCchCopy(reparseStructData->MountPointReparseBuffer.PathBuffer, 1024, (wchar_t*)szDestDir.utf16());
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp
index 4ae994a6d..8d4e3ddc4 100644
--- a/src/libs/installer/packagemanagercore.cpp
+++ b/src/libs/installer/packagemanagercore.cpp
@@ -1586,16 +1586,15 @@ Component *PackageManagerCore::componentByName(const QString &name, const QList<
return nullptr;
}
+/*!
+ Returns \c true if directory specified by \a path is writable by
+ the current user.
+*/
bool PackageManagerCore::directoryWritable(const QString &path) const
{
return d->directoryWritable(path);
}
-bool PackageManagerCore::subdirectoriesWritable(const QString &path) const
-{
- return d->subdirectoriesWritable(path);
-}
-
/*!
Returns a list of components that are marked for installation. The list can
be empty.
diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h
index 45bb27286..cba1592fc 100644
--- a/src/libs/installer/packagemanagercore.h
+++ b/src/libs/installer/packagemanagercore.h
@@ -122,7 +122,6 @@ public:
static Component *componentByName(const QString &name, const QList<Component *> &components);
bool directoryWritable(const QString &path) const;
- bool subdirectoriesWritable(const QString &path) const;
bool fetchLocalPackagesTree();
LocalPackagesHash localInstalledPackages();
diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp
index 63b39ed76..f990a1907 100644
--- a/src/libs/installer/packagemanagercore_p.cpp
+++ b/src/libs/installer/packagemanagercore_p.cpp
@@ -215,6 +215,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core)
, m_updaterModel(nullptr)
, m_guiObject(nullptr)
, m_remoteFileEngineHandler(nullptr)
+ , m_foundEssentialUpdate(false)
{
}
@@ -245,6 +246,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q
, m_updaterModel(nullptr)
, m_guiObject(nullptr)
, m_remoteFileEngineHandler(new RemoteFileEngineHandler)
+ , m_foundEssentialUpdate(false)
{
foreach (const OperationBlob &operation, performedOperations) {
QScopedPointer<QInstaller::Operation> op(KDUpdater::UpdateOperationFactory::instance()
@@ -347,23 +349,8 @@ QString PackageManagerCorePrivate::targetDir() const
bool PackageManagerCorePrivate::directoryWritable(const QString &path) const
{
- QTemporaryFile tempFile(path + QStringLiteral("/tempFile") + QString::number(qrand() % 1000));
- if (!tempFile.open() || !tempFile.isWritable())
- return false;
- else
- return true;
-}
-
-bool PackageManagerCorePrivate::subdirectoriesWritable(const QString &path) const
-{
- // Iterate over target directory subdirectories for writing access
- QDirIterator iterator(path, QDir::AllDirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
- while (iterator.hasNext()) {
- QTemporaryFile tempFile(iterator.next() + QLatin1String("/tempFile"));
- if (!tempFile.open() || !tempFile.isWritable())
- return false;
- }
- return true;
+ QTemporaryFile tempFile(path + QLatin1String("/tempFile.XXXXXX"));
+ return (tempFile.open() && tempFile.isWritable());
}
QString PackageManagerCorePrivate::configurationFileName() const
@@ -805,6 +792,7 @@ void PackageManagerCorePrivate::writeMaintenanceConfigFiles()
: tr("Format error");
throw Error(tr("Cannot write installer configuration to %1: %2").arg(iniPath, reason));
}
+ setDefaultFilePermissions(iniPath, DefaultFilePermissions::NonExecutable);
QFile file(targetDir() + QLatin1Char('/') + QLatin1String("network.xml"));
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
@@ -842,6 +830,7 @@ void PackageManagerCorePrivate::writeMaintenanceConfigFiles()
writer.writeEndElement();
writer.writeEndElement();
}
+ setDefaultFilePermissions(&file, DefaultFilePermissions::NonExecutable);
}
void PackageManagerCorePrivate::readMaintenanceConfigFiles(const QString &targetDir)
@@ -1073,8 +1062,7 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q
throw Error(tr("Cannot write maintenance tool data to %1: %2").arg(dataOut.fileName(),
dataOut.errorString()));
}
- dataOut.setPermissions(dataOut.permissions() | QFile::WriteUser | QFile::ReadGroup
- | QFile::ReadOther);
+ setDefaultFilePermissions(&dataOut, DefaultFilePermissions::NonExecutable);
}
{
@@ -1091,12 +1079,10 @@ void PackageManagerCorePrivate::writeMaintenanceToolBinary(QFile *const input, q
}
QFile mt(maintenanceToolRenamedName);
- if (mt.setPermissions(out.permissions() | QFile::WriteUser | QFile::ReadGroup | QFile::ReadOther
- | QFile::ExeOther | QFile::ExeGroup | QFile::ExeUser)) {
+ if (setDefaultFilePermissions(&mt, DefaultFilePermissions::Executable))
qDebug() << "Wrote permissions for maintenance tool.";
- } else {
+ else
qDebug() << "Failed to write permissions for maintenance tool.";
- }
if (out.exists() && !out.remove()) {
qWarning() << tr("Cannot remove temporary data file \"%1\": %2")
@@ -1386,8 +1372,7 @@ void PackageManagerCorePrivate::writeMaintenanceTool(OperationList performedOper
throw Error(tr("Cannot write maintenance tool binary data to %1: %2")
.arg(file.fileName(), file.errorString()));
}
- file.setPermissions(file.permissions() | QFile::WriteUser | QFile::ReadGroup
- | QFile::ReadOther);
+ setDefaultFilePermissions(&file, DefaultFilePermissions::NonExecutable);
} catch (const Error &/*error*/) {
if (!newBinaryWritten) {
newBinaryWritten = true;
@@ -1494,6 +1479,8 @@ bool PackageManagerCorePrivate::runInstaller()
if (!performOperationThreaded(mkdirOp))
throw Error(mkdirOp->errorString());
}
+ setDefaultFilePermissions(target, DefaultFilePermissions::Executable);
+
const QString remove = m_core->value(scRemoveTargetDir);
if (QVariant(remove).toBool())
addPerformed(takeOwnedOperation(mkdirOp));
@@ -1643,16 +1630,10 @@ bool PackageManagerCorePrivate::runPackageUpdater()
//to have some progress for the cleanup/write component.xml step
ProgressCoordinator::instance()->addReservePercentagePoints(1);
-#if defined(Q_OS_LINUX) || defined(Q_OS_MACOS)
- // check if we need admin rights and ask before the action happens
- // on Linux and macOS also check target directory subdirectories
- if (!directoryWritable(targetDir()) || !subdirectoriesWritable(targetDir()))
- adminRightsGained = m_core->gainAdminRights();
-#else
// check if we need admin rights and ask before the action happens
if (!directoryWritable(targetDir()))
adminRightsGained = m_core->gainAdminRights();
-#endif
+
const QList<Component *> componentsToInstall = m_core->orderedComponentsToInstall();
qDebug() << "Install size:" << componentsToInstall.size() << "components";
diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h
index ace941ced..814ed333a 100644
--- a/src/libs/installer/packagemanagercore_p.h
+++ b/src/libs/installer/packagemanagercore_p.h
@@ -93,7 +93,6 @@ public:
QString registerPath();
bool directoryWritable(const QString &path) const;
- bool subdirectoriesWritable(const QString &path) const;
QString maintenanceToolName() const;
QString installerBinaryPath() const;
diff --git a/src/libs/installer/utils.cpp b/src/libs/installer/utils.cpp
index e4e3212ac..dae5f8d34 100644
--- a/src/libs/installer/utils.cpp
+++ b/src/libs/installer/utils.cpp
@@ -28,6 +28,8 @@
#include "utils.h"
+#include "fileutils.h"
+
#include <QCoreApplication>
#include <QDateTime>
#include <QDir>
@@ -277,6 +279,7 @@ bool QInstaller::PlainVerboseWriterOutput::write(const QString &fileName, QIODev
QFile output(fileName);
if (output.open(openMode)) {
output.write(data);
+ setDefaultFilePermissions(&output, DefaultFilePermissions::NonExecutable);
return true;
}
return false;
diff --git a/src/libs/kdtools/localpackagehub.cpp b/src/libs/kdtools/localpackagehub.cpp
index 11ff36a88..14e6b5738 100644
--- a/src/libs/kdtools/localpackagehub.cpp
+++ b/src/libs/kdtools/localpackagehub.cpp
@@ -28,6 +28,7 @@
****************************************************************************/
#include "localpackagehub.h"
+#include "fileutils.h"
#include "globals.h"
#include "constants.h"
@@ -431,6 +432,11 @@ void LocalPackageHub::writeToDisk()
file.write(doc.toByteArray(4));
file.close();
+
+ // Write permissions for installation information file
+ QInstaller::setDefaultFilePermissions(
+ &file, DefaultFilePermissions::NonExecutable);
+
d->modified = false;
}
}
diff --git a/src/sdk/installerbase.cpp b/src/sdk/installerbase.cpp
index 1cf5765e1..8ae6861a5 100644
--- a/src/sdk/installerbase.cpp
+++ b/src/sdk/installerbase.cpp
@@ -95,6 +95,22 @@ int InstallerBase::run()
}
}
+ QFile binary(binaryFile());
+
+#ifdef Q_OS_WIN
+ // On some admin user installations it is possible that the installer.dat
+ // file is left without reading permissions for non-administrator users,
+ // we should check this and prompt the user to run the executable as admin if needed.
+ if (!binary.open(QIODevice::ReadOnly)) {
+ QFileInfo binaryInfo(binary.fileName());
+ QInstaller::MessageBoxHandler::information(nullptr, QLatin1String("NoReadingPermissions"),
+ tr("Cannot open file \"%1\" for reading").arg(binaryInfo.fileName()),
+ tr("Please make sure that the current user has reading access "
+ "to file \"%1\" or try running %2 as an administrator.").arg(binaryInfo.fileName(), qAppName()));
+ return EXIT_FAILURE;
+ }
+ binary.close();
+#endif
QString fileName = datFile(binaryFile());
quint64 cookie = QInstaller::BinaryContent::MagicCookieDat;
if (fileName.isEmpty()) {
@@ -102,7 +118,7 @@ int InstallerBase::run()
cookie = QInstaller::BinaryContent::MagicCookie;
}
- QFile binary(fileName);
+ binary.setFileName(fileName);
QInstaller::openForRead(&binary);
qint64 magicMarker;
@@ -177,11 +193,11 @@ int InstallerBase::run()
// From Qt5.8 onwards a separate command line option --proxy is not needed as system
// proxy is used by default. If Qt is built with QT_USE_SYSTEM_PROXIES false
// then system proxies are not used by default.
- if ((parser.isSet(QLatin1String(CommandLineOptions::Proxy))
-#if QT_VERSION > 0x050800
- || QNetworkProxyFactory::usesSystemConfiguration()
-#endif
- ) && !parser.isSet(QLatin1String(CommandLineOptions::NoProxy))) {
+ if (parser.isSet(QLatin1String(CommandLineOptions::NoProxy))) {
+ m_core->settings().setProxyType(QInstaller::Settings::NoProxy);
+ KDUpdater::FileDownloaderFactory::instance().setProxyFactory(m_core->proxyFactory());
+ } else if ((parser.isSet(QLatin1String(CommandLineOptions::Proxy))
+ || QNetworkProxyFactory::usesSystemConfiguration())) {
m_core->settings().setProxyType(QInstaller::Settings::SystemProxy);
KDUpdater::FileDownloaderFactory::instance().setProxyFactory(m_core->proxyFactory());
}