diff options
author | Tim Jenssen <tim.jenssen@nokia.com> | 2012-04-25 14:14:56 +0200 |
---|---|---|
committer | Tim Jenssen <tim.jenssen@nokia.com> | 2012-04-27 16:23:20 +0200 |
commit | 0a8755ace26f1174e9ed99e5060c4d8da0ba010d (patch) | |
tree | 7d73b3e0151b06707d8b9df5cef25be7203a420f /src | |
parent | ff6179ea53debd66e63738382b3af62087b81af7 (diff) |
now installer can disallow to install from a remote location
- at the moment the implementation is windows only
- in some cases it is problematically to install big installers from a
remote location: if the connection is lost -> crash
- the installer itself can have the flag DependsOnLocalInstallerBinary in the config.xml file
- or a component can request that installer.setDependsOnLocalInstallerBinary()
Change-Id: I0c8d70ca89dd55d2d0c52bf3418f11c95b5290a1
Reviewed-by: Oliver Wolff <oliver.wolff@nokia.com>
Reviewed-by: Karsten Heimrich <karsten.heimrich@nokia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/libs/installer/packagemanagercore.cpp | 14 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore.h | 3 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore_p.cpp | 10 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore_p.h | 2 | ||||
-rw-r--r-- | src/libs/installer/packagemanagergui.cpp | 13 | ||||
-rw-r--r-- | src/libs/installer/packagemanagergui.h | 1 | ||||
-rw-r--r-- | src/libs/installer/settings.cpp | 8 | ||||
-rw-r--r-- | src/libs/installer/settings.h | 1 | ||||
-rw-r--r-- | src/libs/kdtools/kdsysinfo.h | 3 | ||||
-rw-r--r-- | src/libs/kdtools/kdsysinfo_win.cpp | 123 |
10 files changed, 175 insertions, 3 deletions
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index 985fccbc7..e43033c3f 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -1106,6 +1106,19 @@ bool PackageManagerCore::isProcessRunning(const QString &name) const return PackageManagerCorePrivate::isProcessRunning(name, runningProcesses()); } +void PackageManagerCore::setDependsOnLocalInstallerBinary() +{ + d->m_dependsOnLocalInstallerBinary = true; +} + +bool PackageManagerCore::localInstallerBinaryUsed() +{ +#ifdef Q_OS_WIN + return KDUpdater::pathIsOnLocalDevice(qApp->applicationFilePath()); +#endif + return true; +} + /*! Executes a program. @@ -1116,7 +1129,6 @@ bool PackageManagerCore::isProcessRunning(const QString &name) const command as first item, the return code as second item. \note On Unix, the output is just the output to stdout, not to stderr. */ - QList<QVariant> PackageManagerCore::execute(const QString &program, const QStringList &arguments, const QString &stdIn) const { diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h index cae72c214..ec360d5db 100644 --- a/src/libs/installer/packagemanagercore.h +++ b/src/libs/installer/packagemanagercore.h @@ -112,6 +112,9 @@ public: RunMode runMode() const; void reset(const QHash<QString, QString> ¶ms); + Q_INVOKABLE void setDependsOnLocalInstallerBinary(); + Q_INVOKABLE bool localInstallerBinaryUsed(); + Q_INVOKABLE QList<QVariant> execute(const QString &program, const QStringList &arguments = QStringList(), const QString &stdIn = QString()) const; Q_INVOKABLE bool executeDetached(const QString &program, diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index 72a29e1bc..313ad3ba5 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -196,6 +196,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q , m_createLocalRepositoryFromBinary(false) , m_defaultModel(0) , m_updaterModel(0) + , m_dependsOnLocalInstallerBinary(false) { connect(this, SIGNAL(installationStarted()), m_core, SIGNAL(installationStarted())); connect(this, SIGNAL(installationFinished()), m_core, SIGNAL(installationFinished())); @@ -1358,6 +1359,15 @@ QString PackageManagerCorePrivate::registerPath() const void PackageManagerCorePrivate::runInstaller() { + if (m_dependsOnLocalInstallerBinary && !KDUpdater::pathIsOnLocalDevice(qApp->applicationFilePath())) { + setStatus(PackageManagerCore::Failure); + ProgressCoordinator::instance()->emitLabelAndDetailTextChanged(tr("\nInstallation aborted!")); + MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("installationError"), tr("Error"), tr("It is not possible to install from network location")); + emit installationFinished(); + throw; + } + bool adminRightsGained = false; try { setStatus(PackageManagerCore::Running); diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h index b8ec335a0..ecf2f38d4 100644 --- a/src/libs/installer/packagemanagercore_p.h +++ b/src/libs/installer/packagemanagercore_p.h @@ -194,6 +194,8 @@ public: OperationList m_performedOperationsOld; OperationList m_performedOperationsCurrentSession; + bool m_dependsOnLocalInstallerBinary; + private slots: void infoMessage(KDJob *, const QString &message) { emit m_core->metaJobInfoMessage(message); diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp index 884d08b47..1788452a8 100644 --- a/src/libs/installer/packagemanagergui.cpp +++ b/src/libs/installer/packagemanagergui.cpp @@ -455,6 +455,7 @@ void PackageManagerGui::showEvent(QShowEvent *event) } #endif QWizard::showEvent(event); + QMetaObject::invokeMethod(this, "dependsOnLocalInstallerBinary", Qt::QueuedConnection); } void PackageManagerGui::wizardPageInsertionRequested(QWidget *widget, @@ -652,6 +653,18 @@ void PackageManagerGui::customButtonClicked(int which) emit settingsButtonClicked(); } +void PackageManagerGui::dependsOnLocalInstallerBinary() +{ + if (m_core->settings().dependsOnLocalInstallerBinary() && !m_core->localInstallerBinaryUsed()) { + MessageBoxHandler::critical(MessageBoxHandler::currentBestSuitParent(), + QLatin1String("Installer_Needs_To_Be_Local_Error"), tr("Error"), + tr("It is not possible to install from network location.\n" + "Please copy the installer to a local drive"), QMessageBox::Ok); + rejectWithoutPrompt(); + } +} + + // -- PackageManagerPage diff --git a/src/libs/installer/packagemanagergui.h b/src/libs/installer/packagemanagergui.h index ee85c01c2..2654501b9 100644 --- a/src/libs/installer/packagemanagergui.h +++ b/src/libs/installer/packagemanagergui.h @@ -119,6 +119,7 @@ protected Q_SLOTS: private Q_SLOTS: void onLanguageChanged(); void customButtonClicked(int which); + void dependsOnLocalInstallerBinary(); protected: bool event(QEvent *event); diff --git a/src/libs/installer/settings.cpp b/src/libs/installer/settings.cpp index ace61761e..c7b1394cc 100644 --- a/src/libs/installer/settings.cpp +++ b/src/libs/installer/settings.cpp @@ -57,6 +57,7 @@ static const QLatin1String scTmpRepositories("TemporaryRepositories"); static const QLatin1String scUninstallerIniFile("UninstallerIniFile"); static const QLatin1String scRemoteRepositories("RemoteRepositories"); static const QLatin1String scSigningCertificate("SigningCertificate"); +static const QLatin1String scDependsOnLocalInstallerBinary("DependsOnLocalInstallerBinary"); static const QLatin1String scFtpProxy("FtpProxy"); static const QLatin1String scHttpProxy("HttpProxy"); @@ -230,6 +231,8 @@ Settings Settings::fromFileAndPrefix(const QString &path, const QString &prefix) s.d->m_data.insert(scTargetConfigurationFile, QLatin1String("components.xml")); if (!s.d->m_data.contains(scUninstallerIniFile)) s.d->m_data.insert(scUninstallerIniFile, s.uninstallerName() + QLatin1String(".ini")); + if (!s.d->m_data.contains(scDependsOnLocalInstallerBinary)) + s.d->m_data.insert(scDependsOnLocalInstallerBinary, false); return s; } @@ -345,6 +348,11 @@ bool Settings::allowNoneAsciiCharacters() const return d->m_data.value(scAllowNonAsciiCharacters).toBool(); } +bool Settings::dependsOnLocalInstallerBinary() const +{ + return d->m_data.value(scDependsOnLocalInstallerBinary).toBool(); +} + bool Settings::hasReplacementRepos() const { return d->m_replacementRepos; diff --git a/src/libs/installer/settings.h b/src/libs/installer/settings.h index 5fb60a7c9..12eba079b 100644 --- a/src/libs/installer/settings.h +++ b/src/libs/installer/settings.h @@ -95,6 +95,7 @@ public: QString configurationFileName() const; + bool dependsOnLocalInstallerBinary() const; bool hasReplacementRepos() const; QSet<Repository> repositories() const; diff --git a/src/libs/kdtools/kdsysinfo.h b/src/libs/kdtools/kdsysinfo.h index 6c8079fcd..810e3dbc1 100644 --- a/src/libs/kdtools/kdsysinfo.h +++ b/src/libs/kdtools/kdsysinfo.h @@ -70,6 +70,9 @@ struct ProcessInfo quint64 installedMemory(); QList<VolumeInfo> mountedVolumes(); QList<ProcessInfo> runningProcesses(); +#ifdef Q_OS_WIN +bool pathIsOnLocalDevice(const QString &path); +#endif } // namespace KDUpdater diff --git a/src/libs/kdtools/kdsysinfo_win.cpp b/src/libs/kdtools/kdsysinfo_win.cpp index 45342aee5..92d87d680 100644 --- a/src/libs/kdtools/kdsysinfo_win.cpp +++ b/src/libs/kdtools/kdsysinfo_win.cpp @@ -29,8 +29,9 @@ #include <Winnetwk.h> #pragma comment(lib, "mpr.lib") -#include <QtCore/QDir> -#include <QtCore/QLibrary> +#include <QDebug> +#include <QDir> +#include <QLibrary> const int KDSYSINFO_PROCESS_QUERY_LIMITED_INFORMATION = 0x1000; @@ -209,4 +210,122 @@ QList<ProcessInfo> runningProcesses() return param.processes; } +// REPARSE_DATA_BUFFER structure from msdn help: http://msdn.microsoft.com/en-us/library/ff552012.aspx +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; + +QString junctionTargetPath(const QString &path) +{ + HANDLE fileHandle; + fileHandle = CreateFile(path.utf16(), FILE_READ_EA, FILE_SHARE_READ | FILE_SHARE_WRITE | + FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OPEN_REPARSE_POINT, NULL); + if (fileHandle == INVALID_HANDLE_VALUE) { + qDebug() << QString::fromLatin1("Could not open: '%1'; error: %2\n").arg(path).arg(GetLastError()); + return path; + } + + REPARSE_DATA_BUFFER* reparseStructData = (REPARSE_DATA_BUFFER*)calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + + DWORD bytesReturned; + // fill the reparseStructData + BOOL isOk = DeviceIoControl(fileHandle, FSCTL_GET_REPARSE_POINT, NULL, 0, reparseStructData, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned, NULL); + if (isOk == FALSE) { + DWORD deviceIOControlError = GetLastError(); + if (deviceIOControlError == ERROR_NOT_A_REPARSE_POINT) + qDebug() << QString::fromLatin1("Could not reparse information (windows symlink) for %1").arg(path); + else { + qDebug() << QString::fromLatin1("Get DeviceIoControl for %1 failed with error: %2").arg( + path).arg(deviceIOControlError); + } + CloseHandle(fileHandle); + return path; + } + CloseHandle(fileHandle); + + QString realPath = path; + if (IsReparseTagMicrosoft(reparseStructData->ReparseTag)) { + size_t realPathLength = 0; + WCHAR *realPathWCHAR = 0; + if (reparseStructData->ReparseTag == IO_REPARSE_TAG_SYMLINK){ + realPathLength = reparseStructData->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR); + realPathWCHAR = new WCHAR[realPathLength + 1]; + wcsncpy_s(realPathWCHAR, realPathLength + 1, &reparseStructData->SymbolicLinkReparseBuffer.PathBuffer[ + reparseStructData->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)], realPathLength); + } else if (reparseStructData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + realPathLength = reparseStructData->MountPointReparseBuffer.PrintNameLength / sizeof(WCHAR); + realPathWCHAR = new WCHAR[realPathLength + 1]; + wcsncpy_s(realPathWCHAR, realPathLength + 1, &reparseStructData->MountPointReparseBuffer.PathBuffer[ + reparseStructData->MountPointReparseBuffer.PrintNameOffset / sizeof(WCHAR)], realPathLength); + } else { + qDebug() << QString::fromLatin1("Path %1 is not a symlink and not a mount point.").arg(path); + } + if (realPathLength != 0) { + realPathWCHAR[realPathLength] = 0; + realPath = QString::fromStdWString(realPathWCHAR); + delete [] realPathWCHAR; + } + + } else { + qDebug() << QString::fromLatin1("Path %1 is not reparse point.").arg(path); + } + free(reparseStructData); + return realPath; +} + +bool pathIsOnLocalDevice(const QString &path) +{ + if (!QFileInfo(path).exists()) + return false; + + if (path.startsWith(QLatin1String("\\\\"))) + return false; + + QDir dir(path); + do { + if (QFileInfo(dir, QString()).isSymLink()) { + QString currentPath = QFileInfo(dir, QString()).absoluteFilePath(); + return pathIsOnLocalDevice(junctionTargetPath(currentPath)); + } + } while (dir.cdUp()); + + const UINT DRIVE_REMOTE_TYPE = 4; + if (path.contains(QLatin1Char(':'))) { + const QLatin1Char nullTermination('\0'); + // for example "c:\" + const QString driveSearchString = path.left(3) + nullTermination; + WCHAR wCharDriveSearchArray[4]; + driveSearchString.toWCharArray(wCharDriveSearchArray); + UINT type = GetDriveType(wCharDriveSearchArray); + if (type == DRIVE_REMOTE_TYPE) + return false; + } + + return true; +} + } // namespace KDUpdater |