Mercurial > trustbridge
view ui/installwrapper.cpp @ 502:e551de11d8b6
Properly handle the case that the file does not exist.
TRUNCATE makes create file fail if the file does not exist
but we need TRUNCATE in the case that the file already exists
author | Andre Heinecke <aheinecke@intevation.de> |
---|---|
date | Mon, 28 Apr 2014 09:18:07 +0000 |
parents | a7163018de2f |
children | cef732072774 |
line wrap: on
line source
/* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik * Software engineering by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "installwrapper.h" #include <QFileInfo> #include <QProcess> #include <QTemporaryFile> #include <QApplication> #include <QDir> #include <QDebug> #include "logging.h" #define INSTALL_TIMEOUT 3600000 /* Wait up to an hour */ InstallWrapper::InstallWrapper(QObject* parent, const QString& path, const QStringList& choices): QThread(parent), mCertListFile(path), mChoices(choices) { } QFileInfo getCinstProcInfo() { QFileInfo fi(QCoreApplication::applicationFilePath()); QDir myDir = fi.absoluteDir(); QString instProcName = "cinst"; if (!fi.suffix().isEmpty()) { instProcName += "." + fi.suffix(); } return QFileInfo(myDir.absoluteFilePath(instProcName)); } bool InstallWrapper::writeChoices(QTemporaryFile* choicesFile) const { if (!choicesFile->open()) { return false; } foreach (const QString &b64data, mChoices) { if (choicesFile->write(b64data.toLatin1()) == -1) { return false; } if (choicesFile->write("\n") == -1) { return false; } } choicesFile->close(); return true; } void InstallWrapper::run() { /* TODO: We need errorcodes here so that we can see if a user * cancled the UAC elevation */ QTemporaryFile choicesFile; QFileInfo cinstProcInfo = getCinstProcInfo(); QString cinstFileName = QDir::toNativeSeparators( getCinstProcInfo().absoluteFilePath()); if (!cinstProcInfo.isExecutable()) { emit error(tr("Could not find certificate installation process.")); return; } if (!writeChoices(&choicesFile)) { emit error(tr("Failed to write temporary file.")); return; } #ifdef WIN32 /* QProcess on Windows uses CreateProcess but we have to * use the runas shell command to get the UAC prompt if necessary. * So we have to handle the process ourself. Starting with * shell execute also means that we can not have stdout and stderr * redirection. This is the reason we use command line parameters * and not a pipe for communication. In debug mode the installer * also makes use of output debug string. */ DWORD retval = 0; SHELLEXECUTEINFOW shExecInfo; memset (&shExecInfo, 0, sizeof(SHELLEXECUTEINFOW)); /* Windows needs each parameter packed in " */ QString parameters = "\"list=" + mCertListFile + "\" \"choices=" + choicesFile.fileName() + "\""; shExecInfo.cbSize = sizeof(SHELLEXECUTEINFOW); shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; shExecInfo.lpVerb = L"runas"; shExecInfo.lpFile = reinterpret_cast<LPCWSTR> (cinstFileName.utf16()); shExecInfo.lpParameters = reinterpret_cast<LPCWSTR> (parameters.utf16()); qDebug() << "Starting process " << cinstFileName <<" params: " << parameters; if (!ShellExecuteExW(&shExecInfo)) { char* errmsg = getLastErrorMsg(); QString qerrmsg = QString::fromUtf8(errmsg); free(errmsg); emit error(tr("Error executing process: %1").arg(qerrmsg)); return; } retval = WaitForSingleObject(shExecInfo.hProcess, INSTALL_TIMEOUT); if (retval != WAIT_OBJECT_0) { if (retval == WAIT_FAILED) { char* errmsg = getLastErrorMsg(); QString qerrmsg = QString::fromUtf8(errmsg); free(errmsg); emit error (tr("Error monitoring process: %1").arg(qerrmsg)); return; } else { emit error (tr("Certificate installation timed out.")); return; } } if (GetExitCodeProcess(shExecInfo.hProcess, &retval)) { if (retval == STILL_ACTIVE) { qDebug() << "Process still running, huh.."; } } else { char* errmsg = getLastErrorMsg(); QString qerrmsg = QString::fromUtf8(errmsg); free(errmsg); emit error (tr("Failed to check process status: %1").arg(qerrmsg)); CloseHandle(shExecInfo.hProcess); return; } CloseHandle(shExecInfo.hProcess); if (retval != 0) { /* TODO make this nicer */ emit error (tr("The process failed with return code. %1").arg(retval)); return; } #else /* WIN32 */ QProcess installerProcess; installerProcess.setProgram(cinstProcInfo.absoluteFilePath()); QStringList parameters; choicesFile.setAutoRemove(false); parameters << "list=" + mCertListFile << "choices=" + choicesFile.fileName(); installerProcess.setArguments(parameters); qDebug() << "Starting process " << cinstFileName <<" params: " << parameters; installerProcess.start(); if (!installerProcess.waitForStarted() || installerProcess.state() == QProcess::NotRunning) { emit error (tr("Failed to start installer process.")); return; } installerProcess.waitForFinished(); if (installerProcess.exitStatus() == QProcess::CrashExit) { /* Woops */ emit error (tr("Failed to complete installation.")); return; } else if (installerProcess.exitStatus() != QProcess::NormalExit) { /* Can not Happen. there are only those two values but maybe * qt changed.. */ emit error (tr("Failed to complete installation.")); return; } if (installerProcess.exitCode() == 0) { qDebug() << "output: " << installerProcess.readAllStandardOutput(); } else { /* TODO handle errors defined by errorcodes.h */ qDebug() << "Installer Process returned: " << installerProcess.exitCode(); qDebug() << "output: " << installerProcess.readAllStandardOutput(); return; } #endif emit installationSuccessful(); }