From ea672d4373be2df6b33b46487fa1af29b729eb60 Mon Sep 17 00:00:00 2001 From: Martin Kampas Date: Thu, 4 Apr 2013 14:01:35 +0200 Subject: [PATCH] Sandbox: add support to work on temporary copy --- libssu/libssu.pro | 4 +- libssu/sandbox.cpp | 178 ++++++++++++++++++++++++++++ libssu/sandbox_p.h | 37 ++++++ libssu/sandboxfileenginehandler.cpp | 106 ----------------- libssu/sandboxfileenginehandler_p.h | 27 ----- tests/testutils/sandboxhook.cpp | 6 +- tests/ut_urlresolver/main.cpp | 4 +- 7 files changed, 222 insertions(+), 140 deletions(-) create mode 100644 libssu/sandbox.cpp create mode 100644 libssu/sandbox_p.h delete mode 100644 libssu/sandboxfileenginehandler.cpp delete mode 100644 libssu/sandboxfileenginehandler_p.h diff --git a/libssu/libssu.pro b/libssu/libssu.pro index 67c99dd..0e8d338 100644 --- a/libssu/libssu.pro +++ b/libssu/libssu.pro @@ -7,7 +7,7 @@ public_headers = \ HEADERS = \ $${public_headers} \ - sandboxfileenginehandler_p.h \ + sandbox_p.h \ ssucoreconfig.h \ ssudeviceinfo.h \ ssulog.h \ @@ -16,7 +16,7 @@ HEADERS = \ ssurepomanager.h \ SOURCES = \ - sandboxfileenginehandler.cpp \ + sandbox.cpp \ ssu.cpp \ ssucoreconfig.cpp \ ssudeviceinfo.cpp \ diff --git a/libssu/sandbox.cpp b/libssu/sandbox.cpp new file mode 100644 index 0000000..cbbcd84 --- /dev/null +++ b/libssu/sandbox.cpp @@ -0,0 +1,178 @@ +/** + * @file sandbox.cpp + * @copyright 2013 Jolla Ltd. + * @author Martin Kampas + * @date 2013 + */ + +#include "sandbox_p.h" + +#include +#include +#include +#include +#include +#include + +#include "libssu/ssucoreconfig.h" +// TODO: rename to ssuconstants.h? +#include "constants.h" + +class Sandbox::FileEngineHandler : public QAbstractFileEngineHandler { + public: + FileEngineHandler(const QString &sandboxPath); + + QAbstractFileEngine *create(const QString &fileName) const; + + private: + const QString m_sandboxPath; +}; + +/** + * @class Sandbox + * + * Redirects all file operations on system configuration files to files under + * sandbox directory. When constructed without arguments, the directory is get + * from @c SSU_TESTS_SANDBOX environment variable. + * + * When constructed with @a usage UseAsSkeleton, it will first make temporary + * copy of @a sandboxPath to work on and files in the original directory will + * stay untouched. + * + * Internally it is based on QAbstractFileEngineHandler. + */ + +Sandbox *Sandbox::s_instance = 0; + +QSet Sandbox::s_ssuConfigFiles = QSet() + << SSU_CONFIGURATION + << SSU_REPO_CONFIGURATION + << SSU_DEFAULT_CONFIGURATION + << SSU_BOARD_MAPPING_CONFIGURATION; + +QSet Sandbox::s_ssuConfigDirectories = QSet() + << SSU_BOARD_MAPPING_CONFIGURATION_DIR; + +Sandbox::Sandbox(){ + if (s_instance != 0){ + qFatal("%s: Cannot be instantiated more than once", Q_FUNC_INFO); + } + + s_instance = this; + + m_handler = 0; + + m_sandboxPath = QProcessEnvironment::systemEnvironment().value("SSU_TESTS_SANDBOX"); + + if (m_sandboxPath.isEmpty()){ + return; + } + + if (!QFileInfo(m_sandboxPath).exists()){ + qFatal("%s: Invalid SSU_TESTS_SANDBOX value: No such file or directory", + qPrintable(m_sandboxPath)); + } + + if (!QFileInfo(m_sandboxPath).isDir()){ + qFatal("%s: Invalid SSU_TESTS_SANDBOX value: Not a directory", + qPrintable(m_sandboxPath)); + } + + m_handler = new FileEngineHandler(m_sandboxPath); +} + +Sandbox::Sandbox(const QString &sandboxPath, Usage usage){ + if (s_instance != 0){ + qFatal("%s: Cannot be instantiated more than once", Q_FUNC_INFO); + } + + s_instance = this; + + m_handler = 0; + + m_sandboxPath = sandboxPath; + + if (m_sandboxPath.isEmpty()){ + qWarning("%s: Empty sandboxPath", Q_FUNC_INFO); + return; + } + + if (!QFileInfo(m_sandboxPath).exists()){ + qFatal("%s: Invalid sandboxPath: No such file or directory", + qPrintable(m_sandboxPath)); + } + + if (!QFileInfo(m_sandboxPath).isDir()){ + qFatal("%s: Invalid sandboxPath: Not a directory", + qPrintable(m_sandboxPath)); + } + + if (usage == UseAsSkeleton){ + QProcess mktemp; + mktemp.start("mktemp", QStringList() << "-t" << "-d" << "ssu-sandbox.XXX"); + if (!mktemp.waitForFinished() || mktemp.exitCode() != 0){ + qFatal("%s: Failed to create sandbox directory", Q_FUNC_INFO); + } + + m_tempDir = mktemp.readAllStandardOutput().trimmed(); + if (!QFileInfo(m_tempDir).isDir()){ + qFatal("%s: Temporary directory disappeared: '%s'", Q_FUNC_INFO, qPrintable(m_tempDir)); + } + + const QString sandboxCopyPath = QString("%1/configroot").arg(m_tempDir); + + if (QProcess::execute("cp", QStringList() << "-r" << m_sandboxPath << sandboxCopyPath) != 0){ + qFatal("%s: Failed to copy sandbox directory", Q_FUNC_INFO); + } + + m_sandboxPath = sandboxCopyPath; + } + + m_handler = new FileEngineHandler(m_sandboxPath); +} + +Sandbox::~Sandbox(){ + delete m_handler; + + if (!m_tempDir.isEmpty() && QFileInfo(m_tempDir).exists()){ + if (QProcess::execute("rm", QStringList() << "-rf" << m_tempDir) != 0){ + qWarning("%s: Failed to remove temporary directory", Q_FUNC_INFO); + } + } + + s_instance = 0; +} + +/* + * @class Sandbox::FileEngineHandler + */ + +Sandbox::FileEngineHandler::FileEngineHandler(const QString &sandboxPath): + m_sandboxPath(sandboxPath){ + Q_ASSERT(!sandboxPath.isEmpty()); +} + +QAbstractFileEngine *Sandbox::FileEngineHandler::create(const QString &fileName) const{ + Q_ASSERT(!m_sandboxPath.isEmpty()); + + if (!fileName.startsWith('/')){ + return 0; + } + + if (!s_ssuConfigFiles.contains(fileName)){ + bool match = false; + foreach (const QString &ssuConfigDirectory, s_ssuConfigDirectories){ + if (fileName.startsWith(ssuConfigDirectory + '/')){ + match = true; + break; + } + } + if (!match){ + return 0; + } + } + + const QString fileName_ = QDir(m_sandboxPath).absoluteFilePath(QString(fileName).remove(0, 1)); + + return new QFSFileEngine(fileName_); +} diff --git a/libssu/sandbox_p.h b/libssu/sandbox_p.h new file mode 100644 index 0000000..55d2880 --- /dev/null +++ b/libssu/sandbox_p.h @@ -0,0 +1,37 @@ +/** + * @file sandbox_p.h + * @copyright 2013 Jolla Ltd. + * @author Martin Kampas + * @date 2013 + */ + +#ifndef _SANDBOX_P_H +#define _SANDBOX_P_H + +#include +#include + +class Sandbox { + class FileEngineHandler; + + public: + enum Usage { + UseDirectly, + UseAsSkeleton, + }; + + public: + Sandbox(); + Sandbox(const QString &sandboxPath, Usage usage); + ~Sandbox(); + + private: + static Sandbox *s_instance; + static QSet s_ssuConfigFiles; + static QSet s_ssuConfigDirectories; + QString m_sandboxPath; + QString m_tempDir; + FileEngineHandler *m_handler; +}; + +#endif diff --git a/libssu/sandboxfileenginehandler.cpp b/libssu/sandboxfileenginehandler.cpp deleted file mode 100644 index ab506c3..0000000 --- a/libssu/sandboxfileenginehandler.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/** - * @file sandboxfileenginehandler.cpp - * @copyright 2013 Jolla Ltd. - * @author Martin Kampas - * @date 2013 - */ - -#include "sandboxfileenginehandler_p.h" - -#include -#include -#include -#include -#include - -#include "libssu/ssucoreconfig.h" -// TODO: rename to ssuconstants.h? -#include "constants.h" - -/** - * @class SandboxFileEngineHandler - * - * Redirects all file operations on system configuration files to files under - * directory specified by SSU_TESTS_SANDBOX environment variable. - */ - -QSet SandboxFileEngineHandler::s_ssuConfigFiles = QSet() - << SSU_CONFIGURATION - << SSU_REPO_CONFIGURATION - << SSU_DEFAULT_CONFIGURATION - << SSU_BOARD_MAPPING_CONFIGURATION; - -QSet SandboxFileEngineHandler::s_ssuConfigDirectories = QSet() - << SSU_BOARD_MAPPING_CONFIGURATION_DIR; - -SandboxFileEngineHandler::SandboxFileEngineHandler(){ - m_enabled = false; - m_sandboxPath = QProcessEnvironment::systemEnvironment().value("SSU_TESTS_SANDBOX"); - - if (m_sandboxPath.isEmpty()){ - return; - } - - if (!QFileInfo(m_sandboxPath).exists()){ - qFatal("%s: Invalid SSU_TESTS_SANDBOX value: No such file or directory", - qPrintable(m_sandboxPath)); - } - - if (!QFileInfo(m_sandboxPath).isDir()){ - qFatal("%s: Invalid SSU_TESTS_SANDBOX value: Not a directory", - qPrintable(m_sandboxPath)); - } - - m_enabled = true; -} - -SandboxFileEngineHandler::SandboxFileEngineHandler(const QString &sandboxPath){ - m_enabled = false; - m_sandboxPath = sandboxPath; - - if (m_sandboxPath.isEmpty()){ - qWarning("%s: Empty sandboxPath", Q_FUNC_INFO); - return; - } - - if (!QFileInfo(m_sandboxPath).exists()){ - qFatal("%s: Invalid sandboxPath: No such file or directory", - qPrintable(m_sandboxPath)); - } - - if (!QFileInfo(m_sandboxPath).isDir()){ - qFatal("%s: Invalid sandboxPath: Not a directory", - qPrintable(m_sandboxPath)); - } - - m_enabled = true; -} - -QAbstractFileEngine *SandboxFileEngineHandler::create(const QString &fileName) const{ - Q_ASSERT(!m_enabled || !m_sandboxPath.isEmpty()); - - if (!m_enabled){ - return 0; - } - - if (!fileName.startsWith('/')){ - return 0; - } - - if (!s_ssuConfigFiles.contains(fileName)){ - bool match = false; - foreach (const QString &ssuConfigDirectory, s_ssuConfigDirectories){ - if (fileName.startsWith(ssuConfigDirectory + '/')){ - match = true; - break; - } - } - if (!match){ - return 0; - } - } - - const QString fileName_ = QDir(m_sandboxPath).absoluteFilePath(QString(fileName).remove(0, 1)); - - return new QFSFileEngine(fileName_); -} diff --git a/libssu/sandboxfileenginehandler_p.h b/libssu/sandboxfileenginehandler_p.h deleted file mode 100644 index 5c5b3f5..0000000 --- a/libssu/sandboxfileenginehandler_p.h +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @file sandboxfileenginehandler_p.h - * @copyright 2013 Jolla Ltd. - * @author Martin Kampas - * @date 2013 - */ - -#ifndef _SANDBOXINGFILEENGINEHANDLER_P_H -#define _SANDBOXINGFILEENGINEHANDLER_P_H - -#include - -class SandboxFileEngineHandler : public QAbstractFileEngineHandler { - public: - SandboxFileEngineHandler(); - SandboxFileEngineHandler(const QString &sandboxPath); - - QAbstractFileEngine *create(const QString &fileName) const; - - private: - static QSet s_ssuConfigFiles; - static QSet s_ssuConfigDirectories; - bool m_enabled; - QString m_sandboxPath; -}; - -#endif diff --git a/tests/testutils/sandboxhook.cpp b/tests/testutils/sandboxhook.cpp index 5d9e9aa..9dcc740 100644 --- a/tests/testutils/sandboxhook.cpp +++ b/tests/testutils/sandboxhook.cpp @@ -1,11 +1,11 @@ #include -#include "libssu/sandboxfileenginehandler_p.h" +#include "libssu/sandbox_p.h" extern "C" void qt_startup_hook() { - SandboxFileEngineHandler *const handler = new SandboxFileEngineHandler(); - Q_UNUSED(handler); + Sandbox *const sandbox = new Sandbox(); + Q_UNUSED(sandbox); static void(*next_qt_startup_hook)() = (void (*)()) dlsym(RTLD_NEXT, "qt_startup_hook"); next_qt_startup_hook(); diff --git a/tests/ut_urlresolver/main.cpp b/tests/ut_urlresolver/main.cpp index 8077a7b..0843627 100644 --- a/tests/ut_urlresolver/main.cpp +++ b/tests/ut_urlresolver/main.cpp @@ -7,11 +7,11 @@ #include -#include "libssu/sandboxfileenginehandler_p.h" +#include "libssu/sandbox_p.h" #include "urlresolvertest.cpp" int main(int argc, char **argv){ - SandboxFileEngineHandler h; + Sandbox s; UrlResolverTest urlResolverTest;