summaryrefslogtreecommitdiffstats
path: root/src/libs/installer/fsengineserver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/installer/fsengineserver.cpp')
-rw-r--r--src/libs/installer/fsengineserver.cpp595
1 files changed, 595 insertions, 0 deletions
diff --git a/src/libs/installer/fsengineserver.cpp b/src/libs/installer/fsengineserver.cpp
new file mode 100644
index 000000000..19539334c
--- /dev/null
+++ b/src/libs/installer/fsengineserver.cpp
@@ -0,0 +1,595 @@
+/**************************************************************************
+**
+** This file is part of Installer Framework
+**
+** Copyright (c) 2011-2012 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**************************************************************************/
+#include "fsengineserver.h"
+
+#include "utils.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QFSFileEngine>
+#include <QtCore/QProcess>
+#include <QtCore/QSettings>
+#include <QtCore/QStringList>
+#include <QtCore/QThread>
+
+#include <QtNetwork/QTcpSocket>
+
+typedef int descriptor_t;
+
+#ifdef Q_WS_WIN
+# include <windows.h>
+#endif
+
+bool startDetached(const QString &program, const QStringList &args, const QString &workingDirectory,
+ qint64 *pid)
+{
+#ifdef Q_WS_WIN
+ PROCESS_INFORMATION pinfo;
+ STARTUPINFOW startupInfo = { sizeof(STARTUPINFO), 0, 0, 0,
+ static_cast<ulong>(CW_USEDEFAULT), static_cast<ulong>(CW_USEDEFAULT),
+ static_cast<ulong>(CW_USEDEFAULT), static_cast<ulong>(CW_USEDEFAULT),
+ 0, 0, 0, STARTF_USESHOWWINDOW, SW_HIDE, 0, 0, 0, 0, 0
+ };
+
+ const QString arguments = QInstaller::createCommandline(program, args);
+ const bool success = CreateProcess(0, const_cast<wchar_t *>(static_cast<const wchar_t *>(arguments.utf16())),
+ 0, 0, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE,
+ 0, (wchar_t*)workingDirectory.utf16(),
+ &startupInfo, &pinfo);
+
+ if (success) {
+ CloseHandle(pinfo.hThread);
+ CloseHandle(pinfo.hProcess);
+ if (pid)
+ *pid = pinfo.dwProcessId;
+ }
+
+ return success;
+#else
+ return QProcess::startDetached(program, args, workingDirectory, pid);
+#endif
+}
+
+
+class QProcessSignalReceiver : public QObject
+{
+ Q_OBJECT
+
+public:
+ QProcessSignalReceiver(QObject *parent = 0)
+ : QObject(parent)
+ {
+ connect(parent, SIGNAL(finished(int, QProcess::ExitStatus)), this,
+ SLOT(processFinished(int, QProcess::ExitStatus)));
+ connect(parent, SIGNAL(error(QProcess::ProcessError)), this,
+ SLOT(processError(QProcess::ProcessError)));
+ connect(parent, SIGNAL(readyRead()), this, SLOT(processReadyRead()));
+ connect(parent, SIGNAL(started()), this, SLOT(processStarted()));
+ connect(parent, SIGNAL(stateChanged(QProcess::ProcessState)), this,
+ SLOT(processStateChanged(QProcess::ProcessState)));
+ }
+
+ QList<QVariant> receivedSignals;
+
+private Q_SLOTS:
+ void processError(QProcess::ProcessError error);
+ void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
+ void processReadyRead();
+ void processStarted();
+ void processStateChanged(QProcess::ProcessState newState);
+};
+
+/*!
+ \internal
+*/
+class FSEngineConnectionThread : public QThread
+{
+ Q_OBJECT
+public:
+ FSEngineConnectionThread(descriptor_t socketDescriptor, QObject *parent)
+ : QThread(parent),
+ descriptor(socketDescriptor),
+ settings(0),
+ process(0),
+ signalReceiver(0)
+ {}
+
+protected:
+ void run();
+
+private:
+ QByteArray handleCommand(const QString &command);
+
+ QFSFileEngine engine;
+ const descriptor_t descriptor;
+ QDataStream receivedStream;
+ QSettings *settings;
+
+ QProcess *process;
+ QProcessSignalReceiver *signalReceiver;
+};
+
+
+FSEngineServer::FSEngineServer(quint16 port, QObject *parent)
+ : QTcpServer(parent)
+{
+ listen(QHostAddress::LocalHost, port);
+ connect(&watchdog, SIGNAL(timeout()), qApp, SLOT(quit()));
+ watchdog.setSingleShot(true);
+ watchdog.setInterval(30000);
+ watchdog.start();
+}
+
+FSEngineServer::FSEngineServer(const QHostAddress &address, quint16 port, QObject *parent)
+ : QTcpServer(parent)
+{
+ listen(address, port);
+ connect(&watchdog, SIGNAL(timeout()), qApp, SLOT(quit()));
+ watchdog.setSingleShot(true);
+ watchdog.setInterval(30000);
+ watchdog.start();
+}
+
+/*!
+ Destroys the FSEngineServer.
+*/
+FSEngineServer::~FSEngineServer()
+{
+ const QList<QThread *> threads = findChildren<QThread *>();
+ foreach (QThread *thread, threads)
+ thread->wait();
+}
+
+/*!
+ \reimp
+*/
+void FSEngineServer::incomingConnection(int socketDescriptor)
+{
+ qApp->processEvents();
+ QThread *const thread = new FSEngineConnectionThread(socketDescriptor, this);
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
+ watchdog.start();
+}
+
+void FSEngineServer::enableTestMode()
+{
+ setAuthorizationKey(QLatin1String("testAuthorizationKey"));
+ //we don't want to kill the server,
+ //maybe we should introduce a call where the client can kill the server
+ watchdog.disconnect();
+}
+
+
+/*!
+ Sets the authorization key this server is asking the clients for to \a authorizationKey.
+*/
+void FSEngineServer::setAuthorizationKey(const QString &authorizationKey)
+{
+ key = authorizationKey;
+}
+
+QString FSEngineServer::authorizationKey() const
+{
+ return key;
+}
+
+void QProcessSignalReceiver::processError(QProcess::ProcessError error)
+{
+ receivedSignals.push_back(QLatin1String("error"));
+ receivedSignals.push_back(static_cast<int> (error));
+}
+
+void QProcessSignalReceiver::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ receivedSignals.push_back(QLatin1String("finished"));
+ receivedSignals.push_back(exitCode);
+ receivedSignals.push_back(static_cast<int> (exitStatus));
+}
+
+void QProcessSignalReceiver::processStarted()
+{
+ receivedSignals.push_back(QLatin1String("started"));
+}
+
+void QProcessSignalReceiver::processReadyRead()
+{
+ receivedSignals.push_back(QLatin1String("readyRead"));
+}
+
+void QProcessSignalReceiver::processStateChanged(QProcess::ProcessState newState)
+{
+ receivedSignals.push_back(QLatin1String("stateChanged"));
+ receivedSignals.push_back(static_cast<int>(newState));
+}
+
+/*!
+ \reimp
+*/
+void FSEngineConnectionThread::run()
+{
+ QTcpSocket socket;
+ socket.setSocketDescriptor(descriptor);
+
+ receivedStream.setDevice(&socket);
+ receivedStream.setVersion(QDataStream::Qt_4_2);
+
+ bool authorized = false;
+
+ while (static_cast<QAbstractSocket::SocketState>(socket.state()) == QAbstractSocket::ConnectedState) {
+ if (!socket.bytesAvailable() && !socket.waitForReadyRead(250))
+ continue;
+
+ QString command;
+ receivedStream >> command;
+
+ if (authorized && command == QLatin1String("shutdown")) {
+ // this is a graceful shutdown
+ socket.close();
+ parent()->deleteLater();
+ return;
+ } else if (command == QLatin1String("authorize")) {
+ QString k;
+ receivedStream >> k;
+ if (k != dynamic_cast<FSEngineServer*> (parent())->authorizationKey()) {
+ // this is closing the connection... auth failed
+ socket.close();
+ return;
+ }
+ authorized = true;
+ } else if (authorized) {
+ if (command.isEmpty())
+ continue;
+ const QByteArray result = handleCommand(command);
+ receivedStream << static_cast<quint32> (result.size());
+ if (!result.isEmpty())
+ receivedStream.writeRawData(result.data(), result.size());
+ } else {
+ // authorization failed, connection not wanted
+ socket.close();
+ return;
+ }
+ }
+}
+
+static QDataStream &operator<<(QDataStream &stream, const QSettings::Status &status)
+{
+ return stream << static_cast<int>(status);
+}
+
+/*!
+ Handles \a command and returns a QByteArray which has the result streamed into it.
+*/
+QByteArray FSEngineConnectionThread::handleCommand(const QString &command)
+{
+ QByteArray block;
+ QDataStream returnStream(&block, QIODevice::WriteOnly);
+ returnStream.setVersion(QDataStream::Qt_4_2);
+
+ // first, QSettings handling
+ if (command == QLatin1String("createQSettings")) {
+ QString fileName;
+ receivedStream >> fileName;
+ settings = new QSettings(fileName, QSettings::NativeFormat);
+ } else if (command == QLatin1String("destroyQSettings")) {
+ delete settings;
+ settings = 0;
+ } else if (command == QLatin1String("QSettings::allKeys")) {
+ returnStream << settings->allKeys();
+ } else if (command == QLatin1String("QSettings::beginGroup")) {
+ QString prefix;
+ receivedStream >> prefix;
+ settings->beginGroup(prefix);
+ } else if (command == QLatin1String("QSettings::beginReadArray")) {
+ QString prefix;
+ int size;
+ receivedStream >> prefix;
+ receivedStream >> size;
+ settings->beginWriteArray(prefix, size);
+ } else if (command == QLatin1String("QSettings::beginWriteArray")) {
+ QString prefix;
+ receivedStream >> prefix;
+ returnStream << settings->beginReadArray(prefix);
+ } else if (command == QLatin1String("QSettings::childGroups")) {
+ returnStream << settings->childGroups();
+ } else if (command == QLatin1String("QSettings::childKeys")) {
+ returnStream << settings->childKeys();
+ } else if (command == QLatin1String("QSettings::clear")) {
+ settings->clear();
+ } else if (command == QLatin1String("QSettings::contains")) {
+ QString key;
+ receivedStream >> key;
+ returnStream << settings->contains(key);
+ } else if (command == QLatin1String("QSettings::endArray")) {
+ settings->endArray();
+ } else if (command == QLatin1String("QSettings::endGroup")) {
+ settings->endGroup();
+ } else if (command == QLatin1String("QSettings::fallbacksEnabled")) {
+ returnStream << settings->fallbacksEnabled();
+ } else if (command == QLatin1String("QSettings::fileName")) {
+ returnStream << settings->fileName();
+ } else if (command == QLatin1String("QSettings::group")) {
+ returnStream << settings->group();
+ } else if (command == QLatin1String("QSettings::isWritable")) {
+ returnStream << settings->isWritable();
+ } else if (command == QLatin1String("QSettings::remove")) {
+ QString key;
+ receivedStream >> key;
+ settings->remove(key);
+ } else if (command == QLatin1String("QSettings::setArrayIndex")) {
+ int i;
+ receivedStream >> i;
+ settings->setArrayIndex(i);
+ } else if (command == QLatin1String("QSettings::setFallbacksEnabled")) {
+ bool b;
+ receivedStream >> b;
+ settings->setFallbacksEnabled(b);
+ } else if (command == QLatin1String("QSettings::status")) {
+ returnStream << settings->status();
+ } else if (command == QLatin1String("QSettings::sync")) {
+ settings->sync();
+ } else if (command == QLatin1String("QSettings::setValue")) {
+ QString key;
+ QVariant value;
+ receivedStream >> key;
+ receivedStream >> value;
+ settings->setValue(key, value);
+ } else if (command == QLatin1String("QSettings::value")) {
+ QString key;
+ QVariant defaultValue;
+ receivedStream >> key;
+ receivedStream >> defaultValue;
+ returnStream << settings->value(key, defaultValue);
+ }
+
+ // from here, QProcess handling
+ else if (command == QLatin1String("createQProcess")) {
+ process = new QProcess;
+ signalReceiver = new QProcessSignalReceiver(process);
+ } else if (command == QLatin1String("destroyQProcess")) {
+ signalReceiver->receivedSignals.clear();
+ process->deleteLater();
+ process = 0;
+ } else if (command == QLatin1String("getQProcessSignals")) {
+ returnStream << signalReceiver->receivedSignals;
+ signalReceiver->receivedSignals.clear();
+ qApp->processEvents();
+ } else if (command == QLatin1String("QProcess::closeWriteChannel")) {
+ process->closeWriteChannel();
+ } else if (command == QLatin1String("QProcess::exitCode")) {
+ returnStream << process->exitCode();
+ } else if (command == QLatin1String("QProcess::exitStatus")) {
+ returnStream << static_cast<int> (process->exitStatus());
+ } else if (command == QLatin1String("QProcess::kill")) {
+ process->kill();
+ } else if (command == QLatin1String("QProcess::readAll")) {
+ returnStream << process->readAll();
+ } else if (command == QLatin1String("QProcess::readAllStandardOutput")) {
+ returnStream << process->readAllStandardOutput();
+ } else if (command == QLatin1String("QProcess::startDetached")) {
+ QString program;
+ QStringList arguments;
+ QString workingDirectory;
+ receivedStream >> program;
+ receivedStream >> arguments;
+ receivedStream >> workingDirectory;
+ qint64 pid;
+ const bool result = startDetached(program, arguments, workingDirectory, &pid);
+ returnStream << qMakePair< bool, qint64> (result, pid);
+ } else if (command == QLatin1String("QProcess::setWorkingDirectory")) {
+ QString dir;
+ receivedStream >> dir;
+ process->setWorkingDirectory(dir);
+ } else if (command == QLatin1String("QProcess::setEnvironment")) {
+ QStringList env;
+ receivedStream >> env;
+ process->setEnvironment(env);
+ } else if (command == QLatin1String("QProcess::start")) {
+ QString program;
+ QStringList arguments;
+ int mode;
+ receivedStream >> program;
+ receivedStream >> arguments;
+ receivedStream >> mode;
+ process->start(program, arguments, static_cast<QIODevice::OpenMode> (mode));
+ } else if (command == QLatin1String("QProcess::state")) {
+ returnStream << static_cast<int> (process->state());
+ } else if (command == QLatin1String("QProcess::terminate")) {
+ process->terminate();
+ } else if (command == QLatin1String("QProcess::waitForFinished")) {
+ int msecs;
+ receivedStream >> msecs;
+ returnStream << process->waitForFinished(msecs);
+ } else if (command == QLatin1String("QProcess::waitForStarted")) {
+ int msecs;
+ receivedStream >> msecs;
+ returnStream << process->waitForStarted(msecs);
+ } else if (command == QLatin1String("QProcess::workingDirectory")) {
+ returnStream << process->workingDirectory();
+ } else if (command == QLatin1String("QProcess::write")) {
+ QByteArray byteArray;
+ receivedStream >> byteArray;
+ returnStream << process->write(byteArray);
+ } else if (command == QLatin1String("QProcess::readChannel")) {
+ returnStream << static_cast<int> (process->readChannel());
+ } else if (command == QLatin1String("QProcess::setReadChannel")) {
+ int processChannel;
+ receivedStream >> processChannel;
+ process->setReadChannel(static_cast<QProcess::ProcessChannel>(processChannel));
+ } else if (command == QLatin1String("QProcess::write")) {
+ QByteArray byteArray;
+ receivedStream >> byteArray;
+ returnStream << process->write(byteArray);
+ }
+
+ // from here, QFSEngine handling
+ else if (command == QLatin1String("QFSFileEngine::atEnd")) {
+ returnStream << engine.atEnd();
+ } else if (command == QLatin1String("QFSFileEngine::caseSensitive")) {
+ returnStream << engine.caseSensitive();
+ } else if (command == QLatin1String("QFSFileEngine::close")) {
+ returnStream << engine.close();
+ } else if (command == QLatin1String("QFSFileEngine::copy")) {
+ QString newName;
+ receivedStream >> newName;
+ returnStream << engine.copy(newName);
+ } else if (command == QLatin1String("QFSFileEngine::entryList")) {
+ int filters;
+ QStringList filterNames;
+ receivedStream >> filters;
+ receivedStream >> filterNames;
+ returnStream << engine.entryList(static_cast<QDir::Filters> (filters), filterNames);
+ } else if (command == QLatin1String("QFSFileEngine::error")) {
+ returnStream << static_cast<int> (engine.error());
+ } else if (command == QLatin1String("QFSFileEngine::errorString")) {
+ returnStream << engine.errorString();
+ }
+ // extension
+ else if (command == QLatin1String("QFSFileEngine::fileFlags")) {
+ int flags;
+ receivedStream >> flags;
+ returnStream << static_cast<int>(engine.fileFlags(static_cast<QAbstractFileEngine::FileFlags>(flags)));
+ } else if (command == QLatin1String("QFSFileEngine::fileName")) {
+ int file;
+ receivedStream >> file;
+ returnStream << engine.fileName(static_cast<QAbstractFileEngine::FileName> (file));
+ } else if (command == QLatin1String("QFSFileEngine::flush")) {
+ returnStream << engine.flush();
+ } else if (command == QLatin1String("QFSFileEngine::handle")) {
+ returnStream << engine.handle();
+ } else if (command == QLatin1String("QFSFileEngine::isRelativePath")) {
+ returnStream << engine.isRelativePath();
+ } else if (command == QLatin1String("QFSFileEngine::isSequential")) {
+ returnStream << engine.isSequential();
+ } else if (command == QLatin1String("QFSFileEngine::link")) {
+ QString newName;
+ receivedStream >> newName;
+ returnStream << engine.link(newName);
+ } else if (command == QLatin1String("QFSFileEngine::mkdir")) {
+ QString dirName;
+ bool createParentDirectories;
+ receivedStream >> dirName;
+ receivedStream >> createParentDirectories;
+ returnStream << engine.mkdir(dirName, createParentDirectories);
+ } else if (command == QLatin1String("QFSFileEngine::open")) {
+ int openMode;
+ receivedStream >> openMode;
+ returnStream << engine.open(static_cast<QIODevice::OpenMode> (openMode));
+ } else if (command == QLatin1String("QFSFileEngine::owner")) {
+ int owner;
+ receivedStream >> owner;
+ returnStream << engine.owner(static_cast<QAbstractFileEngine::FileOwner> (owner));
+ } else if (command == QLatin1String("QFSFileEngine::ownerId")) {
+ int owner;
+ receivedStream >> owner;
+ returnStream << engine.ownerId(static_cast<QAbstractFileEngine::FileOwner> (owner));
+ } else if (command == QLatin1String("QFSFileEngine::pos")) {
+ returnStream << engine.pos();
+ } else if (command == QLatin1String("QFSFileEngine::read")) {
+ qint64 maxlen;
+ receivedStream >> maxlen;
+ QByteArray ba(maxlen, '\0');
+ const qint64 result = engine.read(ba.data(), maxlen);
+ returnStream << result;
+ int written = 0;
+ while (written < result)
+ written += returnStream.writeRawData(ba.data() + written, result - written);
+ } else if (command == QLatin1String("QFSFileEngine::readLine")) {
+ qint64 maxlen;
+ receivedStream >> maxlen;
+ QByteArray ba(maxlen, '\0');
+ const qint64 result = engine.readLine(ba.data(), maxlen);
+ returnStream << result;
+ int written = 0;
+ while (written < result)
+ written += returnStream.writeRawData(ba.data() + written, result - written);
+ } else if (command == QLatin1String("QFSFileEngine::remove")) {
+ returnStream << engine.remove();
+ } else if (command == QLatin1String("QFSFileEngine::rename")) {
+ QString newName;
+ receivedStream >> newName;
+ returnStream << engine.rename(newName);
+ } else if (command == QLatin1String("QFSFileEngine::rmdir")) {
+ QString dirName;
+ bool recurseParentDirectories;
+ receivedStream >> dirName;
+ receivedStream >> recurseParentDirectories;
+ returnStream << engine.rmdir(dirName, recurseParentDirectories);
+ } else if (command == QLatin1String("QFSFileEngine::seek")) {
+ quint64 offset;
+ receivedStream >> offset;
+ returnStream << engine.seek(offset);
+ } else if (command == QLatin1String("QFSFileEngine::setFileName")) {
+ QString fileName;
+ receivedStream >> fileName;
+ engine.setFileName(fileName);
+ } else if (command == QLatin1String("QFSFileEngine::setPermissions")) {
+ uint perms;
+ receivedStream >> perms;
+ returnStream << engine.setPermissions(perms);
+ } else if (command == QLatin1String("QFSFileEngine::setSize")) {
+ qint64 size;
+ receivedStream >> size;
+ returnStream << engine.setSize(size);
+ } else if (command == QLatin1String("QFSFileEngine::size")) {
+ returnStream << engine.size();
+ } else if (command == QLatin1String("QFSFileEngine::supportsExtension")) {
+ int extension;
+ receivedStream >> extension;
+ //returnStream << engine.supportsExtension(static_cast<QAbstractFileEngine::Extension> (extension));
+ returnStream << false;
+ } else if (command == QLatin1String("QFSFileEngine::write")) {
+ qint64 length;
+ receivedStream >> length;
+ qint64 read = 0;
+ qint64 written = 0;
+ QByteArray buffer(65536, '\0');
+ while (read < length) {
+ if (!receivedStream.device()->bytesAvailable())
+ receivedStream.device()->waitForReadyRead(-1);
+ const qint64 r = receivedStream.readRawData(buffer.data(), qMin(length - read,
+ static_cast<qint64> (buffer.length())));
+ read += r;
+ qint64 w = 0;
+ while (w < r)
+ w += engine.write(buffer.data(), r);
+ written += r;
+ }
+ returnStream << written;
+ } else if (!command.isEmpty()) {
+ qDebug() << "unknown command:" << command;
+ }
+
+ return block;
+}
+
+#include "fsengineserver.moc"
+#include "moc_fsengineserver.cpp"