ssu
sandbox.cpp
Go to the documentation of this file.
1 
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 
18 #include "libssu/ssucoreconfig_p.h"
19 #include "constants.h"
20 
56 Sandbox *Sandbox::s_activeInstance = 0;
57 
58 Sandbox::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 
68 Sandbox::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 
75 Sandbox::~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 
88 bool Sandbox::isActive() const
89 {
90  return s_activeInstance == this;
91 }
92 
93 bool 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 
109 void 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 
120 QDir Sandbox::effectiveRootDir()
121 {
122  return s_activeInstance != 0 && s_activeInstance->m_scopes & ThisProcess
123  ? s_activeInstance->m_workingSandboxDir
124  : QDir::root();
125 }
126 
127 QString Sandbox::map(const QString &fileName)
128 {
129  return effectiveRootDir().filePath(
130  QDir::root().relativeFilePath(
131  QFileInfo(fileName).absoluteFilePath()));
132 }
133 
134 QString Sandbox::map(const QString &pathName, const QString &fileName)
135 {
136  return effectiveRootDir().filePath(
137  QDir::root().relativeFilePath(
138  QFileInfo(pathName + fileName).absoluteFilePath()));
139 }
140 
146 bool 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 
227 bool Sandbox::addWorldFile(const QString &file)
228 {
229  return addWorldFiles(QFileInfo(file).path(), QDir::NoFilter,
230  QStringList() << QFileInfo(file).fileName());
231 }
232 
233 bool 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 
277 QString 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 
297 bool 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 }
Sandbox
Helps to redirect file operations into sandbox directory.
Definition: sandbox_p.h:21
ssucoreconfig_p.h
sandbox_p.h
constants.h
Sandbox::addWorldFiles
bool addWorldFiles(const QString &directory, QDir::Filters filters=QDir::NoFilter, const QStringList &filterNames=QStringList(), bool recurse=true)
Definition: sandbox.cpp:146