diff --git a/libssu/sandbox.cpp b/libssu/sandbox.cpp index fa50222..f14c549 100644 --- a/libssu/sandbox.cpp +++ b/libssu/sandbox.cpp @@ -22,9 +22,8 @@ class Sandbox::FileEngineHandler : public QAbstractFileEngineHandler { public: - FileEngineHandler(const QString &sandboxPath); + FileEngineHandler(const QString &sandboxPath, const QSet &overlayEnabledDirectories); - void enableDirectoryOverlay(const QString &path); bool isDirectoryOverlayEnabled(const QString &path) const; public: @@ -54,90 +53,21 @@ class Sandbox::FileEngineHandler : public QAbstractFileEngineHandler { * Internally it is based on QAbstractFileEngineHandler. */ -Sandbox *Sandbox::s_instance = 0; +Sandbox *Sandbox::s_activeInstance = 0; -Sandbox::Sandbox(){ - if (s_instance != 0){ - qFatal("%s: Cannot be instantiated more than once", Q_FUNC_INFO); +Sandbox::Sandbox() + : m_defaultConstructed(true), m_usage(UseDirectly), m_scopes(ThisProcess), + m_sandboxPath(QProcessEnvironment::systemEnvironment().value("SSU_TESTS_SANDBOX")), + m_prepared(false), m_handler(0){ + if (!activate()){ + qFatal("%s: Failed to activate", 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, Scopes scopes){ - 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; - } - - if (scopes & ThisProcess){ - m_handler = new FileEngineHandler(m_sandboxPath); - } - - if (scopes & ChildProcesses){ - setenv("SSU_TESTS_SANDBOX", qPrintable(m_sandboxPath), 1); - } +Sandbox::Sandbox(const QString &sandboxPath, Usage usage, Scopes scopes) + : m_defaultConstructed(false), m_usage(usage), m_scopes(scopes), + m_sandboxPath(sandboxPath), m_prepared(false), m_handler(0){ + Q_ASSERT(!sandboxPath.isEmpty()); } Sandbox::~Sandbox(){ @@ -149,11 +79,30 @@ Sandbox::~Sandbox(){ } } - s_instance = 0; + s_activeInstance = 0; } bool Sandbox::isActive() const{ - return m_handler != 0; + return s_activeInstance == this; +} + +bool Sandbox::activate(){ + Q_ASSERT_X(s_activeInstance == 0, Q_FUNC_INFO, "Only one instance can be active!"); + + if (!prepare()){ + return false; + } + + if (m_scopes & ThisProcess){ + m_handler = new FileEngineHandler(m_workingSandboxPath, m_overlayEnabledDirectories); + } + + if (m_scopes & ChildProcesses){ + setenv("SSU_TESTS_SANDBOX", qPrintable(m_workingSandboxPath), 1); + } + + s_activeInstance = this; + return true; } /** @@ -161,8 +110,9 @@ bool Sandbox::isActive() const{ * * @c QDir::NoDotAndDotDot is always added into @a filters. */ -void Sandbox::addWorldFiles(const QString &directory, QDir::Filters filters, +bool Sandbox::addWorldFiles(const QString &directory, QDir::Filters filters, const QStringList &filterNames){ + Q_ASSERT(!isActive()); Q_ASSERT(!directory.isEmpty()); Q_ASSERT(directory.startsWith('/')); Q_ASSERT(!directory.contains(':')); // separator in environment variable @@ -171,42 +121,32 @@ void Sandbox::addWorldFiles(const QString &directory, QDir::Filters filters, && !directory.contains("//")); Q_ASSERT_X(!(m_scopes & ChildProcesses), Q_FUNC_INFO, "Unimplemented case!"); - if (!isActive()){ - qDebug("%s: Sandbox is not active", Q_FUNC_INFO); - return; + if (!prepare()){ + return false; } - const QString sandboxedDirectory = m_sandboxPath + directory; - - QFSFileEngine worldDirectoryEngine(directory); - QFSFileEngine sandboxDirectoryEngine(m_sandboxPath); - QFSFileEngine sandboxedDirectoryEngine(sandboxedDirectory); + const QString sandboxedDirectory = m_workingSandboxPath + directory; - const QAbstractFileEngine::FileFlags worldDirectoryFlags = - worldDirectoryEngine.fileFlags( - QAbstractFileEngine::ExistsFlag | QAbstractFileEngine::DirectoryType); - - if (!(worldDirectoryFlags & QAbstractFileEngine::ExistsFlag)){ - qDebug("%s: Directory does not exist: '%s'", Q_FUNC_INFO, qPrintable(directory)); - return; + if (!QFileInfo(directory).exists()){ + qWarning("%s: Directory does not exist: '%s'", Q_FUNC_INFO, qPrintable(directory)); + return false; } - if (!(worldDirectoryFlags & QAbstractFileEngine::DirectoryType)){ - qFatal("%s: Is not a directory: '%s'", Q_FUNC_INFO, qPrintable(directory)); + if (!QFileInfo(directory).isDir()){ + qWarning("%s: Is not a directory: '%s'", Q_FUNC_INFO, qPrintable(directory)); + return false; } - const QAbstractFileEngine::FileFlags sandboxedDirectoryFlags = - sandboxedDirectoryEngine.fileFlags( - QAbstractFileEngine::ExistsFlag | QAbstractFileEngine::DirectoryType); - - if (!(sandboxedDirectoryFlags & QAbstractFileEngine::ExistsFlag)){ - if (!sandboxedDirectoryEngine.mkdir(sandboxedDirectory, true)){ - qFatal("%s: Failed to create sandbox directory '%s': %s", Q_FUNC_INFO, - qPrintable(sandboxedDirectory), qPrintable(sandboxedDirectoryEngine.errorString())); + if (!QFileInfo(sandboxedDirectory).exists()){ + if (!QDir().mkpath(sandboxedDirectory)){ + qWarning("%s: Failed to create sandbox directory '%s'", Q_FUNC_INFO, + qPrintable(sandboxedDirectory)); + return false; } - } else if (!(sandboxedDirectoryFlags & QAbstractFileEngine::DirectoryType)){ - qFatal("%s: Failed to create sandbox directory '%s': Is not a directory", Q_FUNC_INFO, + } else if (!QFileInfo(sandboxedDirectory).isDir()){ + qWarning("%s: Failed to create sandbox directory '%s': Is not a directory", Q_FUNC_INFO, qPrintable(sandboxedDirectory)); + return false; } if (filters == QDir::NoFilter){ @@ -215,83 +155,90 @@ void Sandbox::addWorldFiles(const QString &directory, QDir::Filters filters, filters |= QDir::NoDotAndDotDot; - foreach (const QString &entryName, worldDirectoryEngine.entryList(filters, filterNames)){ + foreach (const QFileInfo &worldEntryInfo, QDir(directory).entryInfoList(filterNames, filters)){ - QFSFileEngine worldEntryEngine(directory + '/' + entryName); - const QAbstractFileEngine::FileFlags worldEntryFlags = worldEntryEngine.fileFlags( - QAbstractFileEngine::DirectoryType | QAbstractFileEngine::FileType); + const QFileInfo sandboxEntryInfo(sandboxedDirectory + '/' + worldEntryInfo.fileName()); - QFSFileEngine sandboxEntryEngine(sandboxedDirectory + '/' + entryName); - const QAbstractFileEngine::FileFlags sandboxEntryFlags = sandboxEntryEngine.fileFlags( - QAbstractFileEngine::ExistsFlag | QAbstractFileEngine::DirectoryType); - - if (worldEntryFlags & QAbstractFileEngine::DirectoryType){ - if (!(sandboxEntryFlags & QAbstractFileEngine::ExistsFlag)){ - if (!sandboxedDirectoryEngine.mkdir(entryName, false)){ - qFatal("%s: Failed to create overlay directory '%s/%s': %s", Q_FUNC_INFO, - qPrintable(sandboxedDirectory), qPrintable(entryName), - qPrintable(sandboxedDirectoryEngine.errorString())); + if (worldEntryInfo.isDir()){ + if (!sandboxEntryInfo.exists()){ + if (!QDir(sandboxedDirectory).mkdir(worldEntryInfo.fileName())){ + qWarning("%s: Failed to create overlay directory '%s/%s'", Q_FUNC_INFO, + qPrintable(sandboxedDirectory), qPrintable(worldEntryInfo.fileName())); + return false; } - } else if (!(sandboxEntryFlags & QAbstractFileEngine::DirectoryType)){ - qFatal("%s: Failed to create sandboxed copy '%s/%s': Is not a directory", Q_FUNC_INFO, - qPrintable(sandboxedDirectory), qPrintable(entryName)); + } else if (!sandboxEntryInfo.isDir()){ + qWarning("%s: Failed to create sandboxed copy '%s': Is not a directory", Q_FUNC_INFO, + qPrintable(sandboxEntryInfo.filePath())); + return false; } - } else if (worldEntryFlags & QAbstractFileEngine::FileType){ - if (!(sandboxEntryFlags & QAbstractFileEngine::ExistsFlag)){ - if (!copyFile(&worldEntryEngine, &sandboxEntryEngine)){ - return; + } else{ + if (!sandboxEntryInfo.exists()){ + if (!QFile(worldEntryInfo.filePath()).copy(sandboxEntryInfo.filePath())){ + qWarning("%s: Failed to copy file into sandbox '%s'", Q_FUNC_INFO, + qPrintable(worldEntryInfo.filePath())); + return false; } - } else if (sandboxEntryFlags & QAbstractFileEngine::DirectoryType){ - qFatal("%s: Failed to create sandboxed copy '%s/%s': Is a directory", Q_FUNC_INFO, - qPrintable(sandboxedDirectory), qPrintable(entryName)); + } else if (sandboxEntryInfo.isDir()){ + qWarning("%s: Failed to create sandboxed copy '%s': Is a directory", Q_FUNC_INFO, + qPrintable(sandboxEntryInfo.filePath())); + return false; } - } else{ - qFatal("%s: Failed to create sandboxed copy '%s/%s': " - "Can only copy regular files and directories", Q_FUNC_INFO, - qPrintable(sandboxedDirectory), qPrintable(entryName)); } } - m_handler->enableDirectoryOverlay(directory); + m_overlayEnabledDirectories.insert(directory); + + return true; } -bool Sandbox::copyFile(QAbstractFileEngine *src, QAbstractFileEngine *dst){ - if (!src->open(QIODevice::ReadOnly)){ - qFatal("%s: Failed to create sandbox copy: '%s': Cannot open source file for reading", - Q_FUNC_INFO, qPrintable(src->fileName())); +bool Sandbox::prepare(){ + Q_ASSERT(m_defaultConstructed || !m_sandboxPath.isEmpty()); + + if (m_prepared){ + return true; + } + + if (m_sandboxPath.isEmpty()){ + return true; + } + + if (!QFileInfo(m_sandboxPath).exists()){ + qWarning("%s: Invalid sandboxPath: No such file or directory", qPrintable(m_sandboxPath)); return false; } - if (!dst->open(QIODevice::ReadWrite)){ - qFatal("%s: Failed to create sandbox copy: '%s': Cannot open file for writing", - Q_FUNC_INFO, qPrintable(dst->fileName())); + if (!QFileInfo(m_sandboxPath).isDir()){ + qWarning("%s: Invalid sandboxPath: Not a directory", qPrintable(m_sandboxPath)); return false; } - char buf[4096]; - qint64 totalRead = 0; - while (!src->atEnd()){ - qint64 read = src->read(buf, sizeof(buf)); - if (read <= 0){ - break; + if (m_usage == UseAsSkeleton){ + QProcess mktemp; + mktemp.start("mktemp", QStringList() << "-t" << "-d" << "ssu-sandbox.XXX"); + if (!mktemp.waitForFinished() || mktemp.exitCode() != 0){ + qWarning("%s: Failed to create sandbox directory", Q_FUNC_INFO); + return false; } - totalRead += read; - if (dst->write(buf, read) != read){ - qFatal("%s: Failed to create sandbox copy: '%s': Write error", Q_FUNC_INFO, - qPrintable(src->fileName())); + + m_tempDir = mktemp.readAllStandardOutput().trimmed(); + if (!QFileInfo(m_tempDir).isDir()){ + qWarning("%s: Temporary directory disappeared: '%s'", Q_FUNC_INFO, qPrintable(m_tempDir)); return false; } - } - if (totalRead != src->size()){ - qFatal("%s: Failed to create sandbox copy: '%s': Read/write error", Q_FUNC_INFO, - qPrintable(src->fileName())); + const QString sandboxCopyPath = QString("%1/configroot").arg(m_tempDir); + + if (QProcess::execute("cp", QStringList() << "-r" << m_sandboxPath << sandboxCopyPath) != 0){ + qWarning("%s: Failed to copy sandbox directory", Q_FUNC_INFO); return false; - } + } - src->close(); - dst->close(); + m_workingSandboxPath = sandboxCopyPath; + } else{ + m_workingSandboxPath = m_sandboxPath; + } + m_prepared = true; return true; } @@ -299,15 +246,12 @@ bool Sandbox::copyFile(QAbstractFileEngine *src, QAbstractFileEngine *dst){ * @class Sandbox::FileEngineHandler */ -Sandbox::FileEngineHandler::FileEngineHandler(const QString &sandboxPath): - m_sandboxPath(sandboxPath){ +Sandbox::FileEngineHandler::FileEngineHandler(const QString &sandboxPath, + const QSet &overlayEnabledDirectories): + m_sandboxPath(sandboxPath), m_overlayEnabledDirectories(overlayEnabledDirectories){ Q_ASSERT(!sandboxPath.isEmpty()); } -void Sandbox::FileEngineHandler::enableDirectoryOverlay(const QString &path){ - m_overlayEnabledDirectories.insert(path); -} - bool Sandbox::FileEngineHandler::isDirectoryOverlayEnabled(const QString &path) const{ return m_overlayEnabledDirectories.contains(path); } diff --git a/libssu/sandbox_p.h b/libssu/sandbox_p.h index ea84e19..9963812 100644 --- a/libssu/sandbox_p.h +++ b/libssu/sandbox_p.h @@ -9,6 +9,7 @@ #define _SANDBOX_P_H #include +#include #include class Sandbox { @@ -31,18 +32,25 @@ class Sandbox { Sandbox(const QString &sandboxPath, Usage usage, Scopes scopes); ~Sandbox(); + bool activate(); bool isActive() const; - void addWorldFiles(const QString &directory, QDir::Filters filters = QDir::NoFilter, + bool addWorldFiles(const QString &directory, QDir::Filters filters = QDir::NoFilter, const QStringList &filterNames = QStringList()); private: - bool copyFile(QAbstractFileEngine *src, QAbstractFileEngine *dst); + bool prepare(); private: - static Sandbox *s_instance; - QString m_sandboxPath; + static Sandbox *s_activeInstance; + const bool m_defaultConstructed; + const Usage m_usage; + const Scopes m_scopes; + const QString m_sandboxPath; + bool m_prepared; QString m_tempDir; + QString m_workingSandboxPath; + QSet m_overlayEnabledDirectories; FileEngineHandler *m_handler; }; diff --git a/ssuks/ssuks.cpp b/ssuks/ssuks.cpp index 8de0d12..9825e0b 100644 --- a/ssuks/ssuks.cpp +++ b/ssuks/ssuks.cpp @@ -50,6 +50,7 @@ void SsuKs::run(){ qout << "Using sandbox at " << sandbox << endl; Sandbox *sb = new Sandbox(sandbox, Sandbox::UseAsSkeleton, Sandbox::ThisProcess); sb->addWorldFiles(SSU_BOARD_MAPPING_CONFIGURATION_DIR); + sb->activate(); } SsuKickstarter kickstarter; diff --git a/tests/ut_rndssucli/rndssuclitest.cpp b/tests/ut_rndssucli/rndssuclitest.cpp index dee1bfd..6ac423f 100644 --- a/tests/ut_rndssucli/rndssuclitest.cpp +++ b/tests/ut_rndssucli/rndssuclitest.cpp @@ -22,6 +22,9 @@ void RndSsuCliTest::init(){ m_sandbox = new Sandbox(QString("%1/configroot").arg(TESTS_DATA_PATH), Sandbox::UseAsSkeleton, Sandbox::ChildProcesses); + if (!m_sandbox->activate()){ + QFAIL("Failed to activate sandbox"); + } setenv("LD_PRELOAD", qPrintable(QString("%1/libsandboxhook.so").arg(TESTS_PATH)), 1); } diff --git a/tests/ut_urlresolver/main.cpp b/tests/ut_urlresolver/main.cpp index 03a2490..1873572 100644 --- a/tests/ut_urlresolver/main.cpp +++ b/tests/ut_urlresolver/main.cpp @@ -11,8 +11,11 @@ #include "urlresolvertest.cpp" int main(int argc, char **argv){ - Sandbox(QString("%1/configroot").arg(TESTS_DATA_PATH), + Sandbox sandbox(QString("%1/configroot").arg(TESTS_DATA_PATH), Sandbox::UseAsSkeleton, Sandbox::ThisProcess); + if (!sandbox.activate()){ + qFatal("Failed to activate sandbox"); + } UrlResolverTest urlResolverTest;