ssu
Loading...
Searching...
No Matches
sandbox.cpp
Go to the documentation of this file.
1
7
8#include "sandbox_p.h"
9
10#include <stdlib.h>
11
12#include <QtCore/QDir>
13#include <QtCore/QDirIterator>
14#include <QtCore/QFileInfo>
15#include <QtCore/QProcessEnvironment>
16#include <QtCore/QSet>
17
19#include "constants.h"
20
55
56Sandbox *Sandbox::s_activeInstance = 0;
57
58Sandbox::Sandbox()
59 : m_defaultConstructed(true), m_usage(UseDirectly), m_scopes(ThisProcess),
60 m_sandboxPath(QProcessEnvironment::systemEnvironment().value("SSU_SANDBOX_DIR")),
61 m_prepared(false)
62{
63 if (!activate()) {
64 qFatal("%s: Failed to activate", Q_FUNC_INFO);
65 }
66}
67
68Sandbox::Sandbox(const QString &sandboxPath, Usage usage, Scopes scopes)
69 : m_defaultConstructed(false), m_usage(usage), m_scopes(scopes),
70 m_sandboxPath(sandboxPath), m_prepared(false)
71{
72 Q_ASSERT(!sandboxPath.isEmpty());
73}
74
75Sandbox::~Sandbox()
76{
77 if (isActive()) {
78 deactivate();
79 }
80
81 if (!m_tempDir.isEmpty() && QFileInfo(m_tempDir).exists()) {
82 if (!QDir(m_tempDir).removeRecursively()) {
83 qWarning("%s: Failed to remove temporary directory", Q_FUNC_INFO);
84 }
85 }
86}
87
88bool Sandbox::isActive() const
89{
90 return s_activeInstance == this;
91}
92
93bool Sandbox::activate()
94{
95 Q_ASSERT_X(s_activeInstance == 0, Q_FUNC_INFO, "Only one instance can be active!");
96
97 if (!prepare()) {
98 return false;
99 }
100
101 if (m_scopes & ChildProcesses) {
102 setenv("SSU_SANDBOX_DIR", qPrintable(m_workingSandboxDir.path()), 1);
103 }
104
105 s_activeInstance = this;
106 return true;
107}
108
109void Sandbox::deactivate()
110{
111 Q_ASSERT(isActive());
112
113 if (m_scopes & ChildProcesses) {
114 unsetenv("SSU_SANDBOX_DIR");
115 }
116
117 s_activeInstance = 0;
118}
119
120QDir Sandbox::effectiveRootDir()
121{
122 return s_activeInstance != 0 && s_activeInstance->m_scopes & ThisProcess
123 ? s_activeInstance->m_workingSandboxDir
124 : QDir::root();
125}
126
127QString Sandbox::map(const QString &fileName)
128{
129 return effectiveRootDir().filePath(
130 QDir::root().relativeFilePath(
131 QFileInfo(fileName).absoluteFilePath()));
132}
133
134QString Sandbox::map(const QString &pathName, const QString &fileName)
135{
136 return effectiveRootDir().filePath(
137 QDir::root().relativeFilePath(
138 QFileInfo(pathName + fileName).absoluteFilePath()));
139}
140
146bool Sandbox::addWorldFiles(const QString &directory, QDir::Filters filters,
147 const QStringList &filterNames, bool recurse)
148{
149 Q_ASSERT(!isActive());
150 Q_ASSERT(!directory.isEmpty());
151
152 if (!prepare()) {
153 return false;
154 }
155
156 const QString sandboxedDirectory = m_workingSandboxDir.filePath(
157 QDir::root().relativeFilePath(
158 QFileInfo(directory).absoluteFilePath()));
159
160 if (!QFileInfo(directory).exists()) {
161 // Accept missing world directory - allow to create directories inside sandbox
162 qDebug("%s: Directory does not exist - an empty one will be created instead of copied: '%s'",
163 Q_FUNC_INFO, qPrintable(directory));
164 } else if (!QFileInfo(directory).isDir()) {
165 qWarning("%s: Is not a directory: '%s'", Q_FUNC_INFO, qPrintable(directory));
166 return false;
167 }
168
169 if (!QFileInfo(sandboxedDirectory).exists()) {
170 if (!QDir().mkpath(sandboxedDirectory)) {
171 qWarning("%s: Failed to create sandbox directory '%s'", Q_FUNC_INFO,
172 qPrintable(sandboxedDirectory));
173 return false;
174 }
175 } else if (!QFileInfo(sandboxedDirectory).isDir()) {
176 qWarning("%s: Failed to create sandbox directory '%s': Is not a directory", Q_FUNC_INFO,
177 qPrintable(sandboxedDirectory));
178 return false;
179 }
180
181 if (filters == QDir::NoFilter) {
182 filters = QDir::AllEntries;
183 }
184
185 filters |= QDir::NoDotAndDotDot;
186
187 foreach (const QFileInfo &worldEntryInfo, QDir(directory).entryInfoList(filterNames, filters)) {
188
189 const QFileInfo sandboxEntryInfo(QDir(sandboxedDirectory).filePath(worldEntryInfo.fileName()));
190
191 if (worldEntryInfo.isDir()) {
192 if (!sandboxEntryInfo.exists()) {
193 if (!QDir(sandboxedDirectory).mkdir(worldEntryInfo.fileName())) {
194 qWarning("%s: Failed to create overlay directory '%s/%s'", Q_FUNC_INFO,
195 qPrintable(sandboxedDirectory), qPrintable(worldEntryInfo.fileName()));
196 return false;
197 }
198 } else if (!sandboxEntryInfo.isDir()) {
199 qWarning("%s: Failed to create sandboxed copy '%s': Is not a directory", Q_FUNC_INFO,
200 qPrintable(sandboxEntryInfo.filePath()));
201 return false;
202 }
203
204 if (recurse) {
205 if (!addWorldFiles(worldEntryInfo.absoluteFilePath(), filters, filterNames, true)) {
206 return false;
207 }
208 }
209 } else {
210 if (!sandboxEntryInfo.exists()) {
211 if (!QFile(worldEntryInfo.filePath()).copy(sandboxEntryInfo.filePath())) {
212 qWarning("%s: Failed to copy file into sandbox '%s'", Q_FUNC_INFO,
213 qPrintable(worldEntryInfo.filePath()));
214 return false;
215 }
216 } else if (sandboxEntryInfo.isDir()) {
217 qWarning("%s: Failed to create sandboxed copy '%s': Is a directory", Q_FUNC_INFO,
218 qPrintable(sandboxEntryInfo.filePath()));
219 return false;
220 }
221 }
222 }
223
224 return true;
225}
226
227bool Sandbox::addWorldFile(const QString &file)
228{
229 return addWorldFiles(QFileInfo(file).path(), QDir::NoFilter,
230 QStringList() << QFileInfo(file).fileName());
231}
232
233bool Sandbox::prepare()
234{
235 Q_ASSERT(m_defaultConstructed || !m_sandboxPath.isEmpty());
236
237 if (m_prepared) {
238 return true;
239 }
240
241 if (m_sandboxPath.isEmpty()) {
242 return true;
243 }
244
245 if (!QFileInfo(m_sandboxPath).exists()) {
246 qWarning("%s: Invalid sandboxPath: No such file or directory", qPrintable(m_sandboxPath));
247 return false;
248 }
249
250 if (!QFileInfo(m_sandboxPath).isDir()) {
251 qWarning("%s: Invalid sandboxPath: Not a directory", qPrintable(m_sandboxPath));
252 return false;
253 }
254
255 if (m_usage == UseAsSkeleton) {
256 if (m_tempDir = createTmpDir("ssu-sandbox.%1"), m_tempDir.isEmpty()) {
257 qWarning("%s: Failed to create sandbox directory", Q_FUNC_INFO);
258 return false;
259 }
260
261 const QString sandboxCopyPath = QDir(m_tempDir).filePath("configroot");
262
263 if (!copyDir(m_sandboxPath, sandboxCopyPath)) {
264 qWarning("%s: Failed to copy sandbox directory", Q_FUNC_INFO);
265 return false;
266 }
267
268 m_workingSandboxDir = QDir(sandboxCopyPath);
269 } else {
270 m_workingSandboxDir = QDir(m_sandboxPath);
271 }
272
273 m_prepared = true;
274 return true;
275}
276
277QString Sandbox::createTmpDir(const QString &nameTemplate)
278{
279 const int REASONABLE_REPEAT_COUNT = 10;
280
281 for (int i = 0; i < REASONABLE_REPEAT_COUNT; ++i) {
282 QString path;
283 int suffix = 0;
284 do {
285 path = QDir::temp().filePath(nameTemplate.arg(++suffix));
286 } while (QFileInfo(path).exists());
287
288 if (QDir().mkpath(path)) {
289 return path;
290 }
291 }
292
293 qWarning("%s: Failed to create temporary directory", Q_FUNC_INFO);
294 return QString();
295}
296
297bool Sandbox::copyDir(const QString &directory, const QString &newName)
298{
299 const QDir sourceRoot(directory);
300 const QDir destinationRoot(newName);
301
302 QDirIterator it(directory, QDir::AllEntries | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
303 while (it.hasNext()) {
304 it.next();
305
306 const QFileInfo destination = QFileInfo(destinationRoot.filePath(
307 sourceRoot.relativeFilePath(it.filePath())));
308
309 if (it.fileInfo().isDir()) {
310 if (!QDir().mkpath(destination.absoluteFilePath())) {
311 qWarning("%s: Failed to mkpath '%s'", Q_FUNC_INFO, qPrintable(destination.absolutePath()));
312 return false;
313 }
314 } else if (it.fileInfo().isFile()) {
315 if (!QDir().mkpath(destination.absolutePath())) {
316 qWarning("%s: Failed to mkpath '%s'", Q_FUNC_INFO, qPrintable(destination.absolutePath()));
317 return false;
318 }
319
320 if (!QFile::copy(it.fileInfo().absoluteFilePath(), destination.absoluteFilePath())) {
321 qWarning("%s: Failed to copy file '%s'", Q_FUNC_INFO, qPrintable(it.filePath()));
322 return false;
323 }
324 } else {
325 qWarning("%s: Cannot copy other than regular files: '%s'", Q_FUNC_INFO,
326 qPrintable(it.filePath()));
327 return false;
328 }
329 }
330
331 return true;
332}
Helps to redirect file operations into sandbox directory.
Definition sandbox_p.h:22
bool addWorldFiles(const QString &directory, QDir::Filters filters=QDir::NoFilter, const QStringList &filterNames=QStringList(), bool recurse=true)
Definition sandbox.cpp:146