Skip to content

Commit

Permalink
Sandbox: allow to easy add world files
Browse files Browse the repository at this point in the history
  • Loading branch information
martyone committed Apr 5, 2013
1 parent a5e22aa commit c72cbcf
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 0 deletions.
159 changes: 159 additions & 0 deletions libssu/sandbox.cpp
Expand Up @@ -24,10 +24,16 @@ class Sandbox::FileEngineHandler : public QAbstractFileEngineHandler {
public:
FileEngineHandler(const QString &sandboxPath);

void enableDirectoryOverlay(const QString &path);
bool isDirectoryOverlayEnabled(const QString &path) const;

public:
// QAbstractFileEngineHandler
QAbstractFileEngine *create(const QString &fileName) const;

private:
const QString m_sandboxPath;
QSet<QString> m_overlayEnabledDirectories;
};

/**
Expand Down Expand Up @@ -146,6 +152,149 @@ Sandbox::~Sandbox(){
s_instance = 0;
}

bool Sandbox::isActive() const{
return m_handler != 0;
}

/**
* Copies selected files into sandbox. Existing files in sandbox are not overwriten.
*
* @c QDir::NoDotAndDotDot is always added into @a filters.
*/
void Sandbox::addWorldFiles(const QString &directory, QDir::Filters filters,
const QStringList &filterNames){
Q_ASSERT(!directory.isEmpty());
Q_ASSERT(directory.startsWith('/'));
Q_ASSERT(!directory.contains(':')); // separator in environment variable
Q_ASSERT(!directory.contains("/./") && !directory.endsWith("/.")
&& !directory.contains("/../") && !directory.endsWith("/..")
&& !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;
}

const QString sandboxedDirectory = m_sandboxPath + directory;

QFSFileEngine worldDirectoryEngine(directory);
QFSFileEngine sandboxDirectoryEngine(m_sandboxPath);
QFSFileEngine sandboxedDirectoryEngine(sandboxedDirectory);

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 (!(worldDirectoryFlags & QAbstractFileEngine::DirectoryType)){
qFatal("%s: Is not a directory: '%s'", Q_FUNC_INFO, qPrintable(directory));
}

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()));
}
} else if (!(sandboxedDirectoryFlags & QAbstractFileEngine::DirectoryType)){
qFatal("%s: Failed to create sandbox directory '%s': Is not a directory", Q_FUNC_INFO,
qPrintable(sandboxedDirectory));
}

if (filters == QDir::NoFilter){
filters = QDir::AllEntries;
}

filters |= QDir::NoDotAndDotDot;

foreach (const QString &entryName, worldDirectoryEngine.entryList(filters, filterNames)){

QFSFileEngine worldEntryEngine(directory + '/' + entryName);
const QAbstractFileEngine::FileFlags worldEntryFlags = worldEntryEngine.fileFlags(
QAbstractFileEngine::DirectoryType | QAbstractFileEngine::FileType);

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()));
}
} 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 (worldEntryFlags & QAbstractFileEngine::FileType){
if (!(sandboxEntryFlags & QAbstractFileEngine::ExistsFlag)){
if (!copyFile(&worldEntryEngine, &sandboxEntryEngine)){
return;
}
} 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{
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);
}

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()));
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()));
return false;
}

char buf[4096];
qint64 totalRead = 0;
while (!src->atEnd()){
qint64 read = src->read(buf, sizeof(buf));
if (read <= 0){
break;
}
totalRead += read;
if (dst->write(buf, read) != read){
qFatal("%s: Failed to create sandbox copy: '%s': Write error", Q_FUNC_INFO,
qPrintable(src->fileName()));
return false;
}
}

if (totalRead != src->size()){
qFatal("%s: Failed to create sandbox copy: '%s': Read/write error", Q_FUNC_INFO,
qPrintable(src->fileName()));
return false;
}

src->close();
dst->close();

return true;
}

/*
* @class Sandbox::FileEngineHandler
*/
Expand All @@ -155,6 +304,14 @@ Sandbox::FileEngineHandler::FileEngineHandler(const QString &sandboxPath):
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);
}

QAbstractFileEngine *Sandbox::FileEngineHandler::create(const QString &fileName) const{
Q_ASSERT(!m_sandboxPath.isEmpty());

Expand All @@ -173,8 +330,10 @@ QAbstractFileEngine *Sandbox::FileEngineHandler::create(const QString &fileName)
}

if (flags & QAbstractFileEngine::DirectoryType){
if (!isDirectoryOverlayEnabled(fileName)){
return 0;
}
}

return sandboxedFileEngine.take();
}
9 changes: 9 additions & 0 deletions libssu/sandbox_p.h
Expand Up @@ -8,6 +8,7 @@
#ifndef _SANDBOX_P_H
#define _SANDBOX_P_H

#include <QtCore/QDir>
#include <QtCore/QString>

class Sandbox {
Expand All @@ -30,6 +31,14 @@ class Sandbox {
Sandbox(const QString &sandboxPath, Usage usage, Scopes scopes);
~Sandbox();

bool isActive() const;

void addWorldFiles(const QString &directory, QDir::Filters filters = QDir::NoFilter,
const QStringList &filterNames = QStringList());

private:
bool copyFile(QAbstractFileEngine *src, QAbstractFileEngine *dst);

private:
static Sandbox *s_instance;
QString m_sandboxPath;
Expand Down

0 comments on commit c72cbcf

Please sign in to comment.