Commit c72cbcf1 authored by Martin Kampas's avatar Martin Kampas

Sandbox: allow to easy add world files

parent a5e22aa5
......@@ -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;
};
/**
......@@ -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
*/
......@@ -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());
......@@ -173,7 +330,9 @@ QAbstractFileEngine *Sandbox::FileEngineHandler::create(const QString &fileName)
}
if (flags & QAbstractFileEngine::DirectoryType){
return 0;
if (!isDirectoryOverlayEnabled(fileName)){
return 0;
}
}
return sandboxedFileEngine.take();
......
......@@ -8,6 +8,7 @@
#ifndef _SANDBOX_P_H
#define _SANDBOX_P_H
#include <QtCore/QDir>
#include <QtCore/QString>
class Sandbox {
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment