summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Jenssen <tim.jenssen@nokia.com>2012-04-25 14:14:56 +0200
committerTim Jenssen <tim.jenssen@nokia.com>2012-04-27 16:23:20 +0200
commit0a8755ace26f1174e9ed99e5060c4d8da0ba010d (patch)
tree7d73b3e0151b06707d8b9df5cef25be7203a420f
parentff6179ea53debd66e63738382b3af62087b81af7 (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>
-rw-r--r--src/libs/installer/packagemanagercore.cpp14
-rw-r--r--src/libs/installer/packagemanagercore.h3
-rw-r--r--src/libs/installer/packagemanagercore_p.cpp10
-rw-r--r--src/libs/installer/packagemanagercore_p.h2
-rw-r--r--src/libs/installer/packagemanagergui.cpp13
-rw-r--r--src/libs/installer/packagemanagergui.h1
-rw-r--r--src/libs/installer/settings.cpp8
-rw-r--r--src/libs/installer/settings.h1
-rw-r--r--src/libs/kdtools/kdsysinfo.h3
-rw-r--r--src/libs/kdtools/kdsysinfo_win.cpp123
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> &params);
+ 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