diff options
Diffstat (limited to 'tools/devtool/binaryreplace.cpp')
-rw-r--r-- | tools/devtool/binaryreplace.cpp | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/tools/devtool/binaryreplace.cpp b/tools/devtool/binaryreplace.cpp new file mode 100644 index 000000000..b4a797f0f --- /dev/null +++ b/tools/devtool/binaryreplace.cpp @@ -0,0 +1,167 @@ +/************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Installer Framework. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +**************************************************************************/ + +#include "binaryreplace.h" + +#include <copyfiletask.h> +#include <downloadfiletask.h> +#include <errors.h> +#include <fileio.h> +#include <fileutils.h> +#include <lib7z_facade.h> + +#include <QFutureWatcher> + +#include <iostream> + +BinaryReplace::BinaryReplace(const QInstaller::BinaryLayout &layout) + : m_binaryLayout(layout) +{} + +int BinaryReplace::replace(const QString &source, const QString &target) +{ + const QUrl url = QUrl::fromUserInput(source); + QFutureWatcher<QInstaller::FileTaskResult> taskWatcher; + if (url.isLocalFile()) { + taskWatcher.setFuture(QtConcurrent::run(&QInstaller::CopyFileTask::doTask, + new QInstaller::CopyFileTask(QInstaller::FileTaskItem(url.toLocalFile())))); + } else { + taskWatcher.setFuture(QtConcurrent::run(&QInstaller::DownloadFileTask::doTask, + new QInstaller::DownloadFileTask(QInstaller::FileTaskItem(url.toString())))); + } + + bool result = EXIT_FAILURE; + try { + taskWatcher.waitForFinished(); // throws on error + const QFuture<QInstaller::FileTaskResult> future = taskWatcher.future(); + if (future.resultCount() <= 0) + return result; + + QString newInstallerBasePath = future.result().target(); + if (Lib7z::isSupportedArchive(newInstallerBasePath)) { + QFile archive(newInstallerBasePath); + if (archive.open(QIODevice::ReadOnly)) { + try { + Lib7z::extractArchive(&archive, QDir::tempPath()); + const QVector<Lib7z::File> files = Lib7z::listArchive(&archive); + newInstallerBasePath = QDir::tempPath() + QLatin1Char('/') + files.value(0) + .path; + result = EXIT_SUCCESS; + } catch (const Lib7z::SevenZipException& e) { + std::cerr << qPrintable(QString::fromLatin1("Error while extracting '%1': %2.") + .arg(newInstallerBasePath, e.message())) << std::endl; + } catch (...) { + std::cerr << qPrintable(QString::fromLatin1("Unknown exception caught while " + "extracting '%1'.").arg(newInstallerBasePath)) << std::endl; + } + } else { + std::cerr << qPrintable(QString::fromLatin1("Could not open '%1' for reading: %2.") + .arg(newInstallerBasePath, archive.errorString())) << std::endl; + } + if (!archive.remove()) { + std::cerr << qPrintable(QString::fromLatin1("Could not delete file '%1': %2.") + .arg(newInstallerBasePath, archive.errorString())) << std::endl; + } + if (result != EXIT_SUCCESS) + return result; + } + + result = EXIT_FAILURE; + try { + QFile installerBaseNew(newInstallerBasePath); +#ifndef Q_OS_OSX + QFile installerBaseOld(target); + QInstaller::openForAppend(&installerBaseNew); + + installerBaseNew.seek(installerBaseNew.size()); + if (m_binaryLayout.magicMarker == QInstaller::MagicInstallerMarker) { + QInstaller::openForRead(&installerBaseOld); + installerBaseOld.seek(m_binaryLayout.metadataResourceSegments.first().start()); + QInstaller::appendData(&installerBaseNew, &installerBaseOld, installerBaseOld + .size() - installerBaseOld.pos()); + installerBaseOld.close(); + } else { + QInstaller::appendInt64(&installerBaseNew, 0); + QInstaller::appendInt64(&installerBaseNew, 4 * sizeof(qint64)); + QInstaller::appendInt64(&installerBaseNew, QInstaller::MagicUninstallerMarker); + QInstaller::appendInt64(&installerBaseNew, QInstaller::MagicCookie); + } + installerBaseNew.close(); +#else + QString bundlePath; + QInstaller::isInBundle(target, &bundlePath); + QFile installerBaseOld(QDir(bundlePath).filePath(bundlePath + + QLatin1String("/Contents/MacOS/") + QFileInfo(bundlePath).completeBaseName())); +#endif + installerBaseNew.setPermissions(installerBaseOld.permissions()); + + QFile backup(installerBaseOld.fileName() + QLatin1String(".bak")); + if (backup.exists() && (!backup.remove())) { + std::cerr << qPrintable(QString::fromLatin1("Could not delete '%1'. %2") + .arg(backup.fileName(), backup.errorString())) << std::endl; + } + + const QString oldBasePath = installerBaseOld.fileName(); + if (!installerBaseOld.rename(oldBasePath + QLatin1String(".bak"))) { + std::cerr << qPrintable(QString::fromLatin1("Could not rename '%1' to '%2'. %3") + .arg(oldBasePath, oldBasePath + QLatin1String(".bak"), + installerBaseOld.errorString())) << std::endl; + } + + if (!installerBaseNew.rename(oldBasePath)) { + std::cerr << qPrintable(QString::fromLatin1("Could not copy '%1' to '%2'. %3") + .arg(installerBaseNew.fileName(), oldBasePath, installerBaseNew.errorString())) + << std::endl; + } else { + result = EXIT_SUCCESS; + } + } catch (const QInstaller::Error &error) { + std::cerr << qPrintable(error.message()) << std::endl; + } + } catch (const QInstaller::FileTaskException &e) { + std::cerr << qPrintable(e.message()) << std::endl; + } catch (const QUnhandledException &e) { + std::cerr << e.what() << std::endl; + } catch (...) { + std::cerr << "Unknown exception caught."<< std::endl; + } + return result; +} |