TempDirectory.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 Chris Cannam.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "TempDirectory.h"
17 #include "ResourceFinder.h"
18 #include "system/System.h"
19 #include "Exceptions.h"
20 
21 #include <QDir>
22 #include <QFile>
23 #include <QMutexLocker>
24 #include <QSettings>
25 
26 #include <iostream>
27 #include <cassert>
28 
29 #include <time.h>
30 
33 
36 {
37  return m_instance;
38 }
39 
41  m_tmpdir("")
42 {
43 }
44 
46 {
47  SVDEBUG << "TempDirectory::~TempDirectory" << endl;
48 
49  cleanup();
50 }
51 
52 void
54 {
55  cleanupDirectory("");
56 }
57 
58 QString
60 {
61  QMutexLocker locker(&m_mutex);
62 
63  QSettings settings;
64  settings.beginGroup("TempDirectory");
65  QString svDirParent = settings.value("create-in", "$HOME").toString();
66  settings.endGroup();
67 
68  QString svDir = ResourceFinder().getUserResourcePrefix();
69  if (svDirParent != "$HOME") {
71  svDir.replace(QDir::home().absolutePath(), svDirParent);
72  }
73 
74  if (!QFileInfo(svDir).exists()) {
75  if (!QDir(svDirParent).mkpath(svDir)) {
76  throw DirectoryCreationFailed(QString("%1 directory in %2")
77  .arg(svDir).arg(svDirParent));
78  }
79  } else if (!QFileInfo(svDir).isDir()) {
80  throw DirectoryCreationFailed(QString("%1 is not a directory")
81  .arg(svDir));
82  }
83 
85 
86  return svDir;
87 }
88 
89 QString
91 {
92  if (m_tmpdir != "") return m_tmpdir;
93 
95 }
96 
97 QString
99 {
100  // Entered with mutex held.
101 
102  QDir tempDirBase(dir);
103 
104  // Generate a temporary directory. Qt4.1 doesn't seem to be able
105  // to do this for us, and mkdtemp is not standard. This method is
106  // based on the way glibc does mkdtemp.
107 
108  static QString chars =
109  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
110 
111  QString suffix;
112  int padlen = 6, attempts = 100;
113  unsigned int r = (unsigned int)(time(nullptr) ^ getpid());
114 
115  for (int i = 0; i < padlen; ++i) {
116  suffix += "X";
117  }
118 
119  for (int j = 0; j < attempts; ++j) {
120 
121  unsigned int v = r;
122 
123  for (int i = 0; i < padlen; ++i) {
124  suffix[i] = chars[v % 62];
125  v /= 62;
126  }
127 
128  QString candidate = QString("sv_%1").arg(suffix);
129 
130  if (tempDirBase.mkpath(candidate)) {
131  m_tmpdir = tempDirBase.filePath(candidate);
132  break;
133  }
134 
135  r = r + 7777;
136  }
137 
138  if (m_tmpdir == "") {
139  throw DirectoryCreationFailed(QString("temporary subdirectory in %1")
140  .arg(tempDirBase.canonicalPath()));
141  }
142 
143  QString pidpath = QDir(m_tmpdir).filePath(QString("%1.pid").arg(getpid()));
144  QFile pidfile(pidpath);
145 
146  if (!pidfile.open(QIODevice::WriteOnly)) {
147  throw DirectoryCreationFailed(QString("pid file creation in %1")
148  .arg(m_tmpdir));
149  } else {
150  pidfile.close();
151  }
152 
153  return m_tmpdir;
154 }
155 
156 QString
158 {
159  QString tmpdirpath = getPath();
160 
161  QMutexLocker locker(&m_mutex);
162 
163  QDir tmpdir(tmpdirpath);
164  QFileInfo fi(tmpdir.filePath(subdir));
165 
166  if (!fi.exists()) {
167  if (!tmpdir.mkdir(subdir)) {
168  throw DirectoryCreationFailed(fi.filePath());
169  } else {
170  return fi.filePath();
171  }
172  } else if (fi.isDir()) {
173  return fi.filePath();
174  } else {
175  throw DirectoryCreationFailed(fi.filePath());
176  }
177 }
178 
179 void
181 {
182  bool isRoot = false;
183 
184  if (tmpdir == "") {
185 
186  m_mutex.lock();
187 
188  isRoot = true;
189  tmpdir = m_tmpdir;
190 
191  if (tmpdir == "") {
192  m_mutex.unlock();
193  return;
194  }
195  }
196 
197  QDir dir(tmpdir);
198  dir.setFilter(QDir::Dirs | QDir::Files);
199 
200  for (unsigned int i = 0; i < dir.count(); ++i) {
201 
202  if (dir[i] == "." || dir[i] == "..") continue;
203  QFileInfo fi(dir.filePath(dir[i]));
204 
205  if (fi.isDir()) {
206  cleanupDirectory(fi.absoluteFilePath());
207  } else {
208  if (!QFile(fi.absoluteFilePath()).remove()) {
209  cerr << "WARNING: TempDirectory::cleanup: "
210  << "Failed to unlink file \""
211  << fi.absoluteFilePath() << "\""
212  << endl;
213  }
214  }
215  }
216 
217  QString dirname = dir.dirName();
218  if (dirname != "") {
219  if (!dir.cdUp()) {
220  cerr << "WARNING: TempDirectory::cleanup: "
221  << "Failed to cd to parent directory of "
222  << tmpdir << endl;
223  return;
224  }
225  if (!dir.rmdir(dirname)) {
226  cerr << "WARNING: TempDirectory::cleanup: "
227  << "Failed to remove directory "
228  << dirname << endl;
229  }
230  }
231 
232  if (isRoot) {
233  m_tmpdir = "";
234  m_mutex.unlock();
235  }
236 }
237 
238 void
240 {
241  QDir dir(svDir, "sv_*", QDir::Name, QDir::Dirs);
242 
243  for (unsigned int i = 0; i < dir.count(); ++i) {
244 
245  QString dirpath = dir.filePath(dir[i]);
246 
247  QDir subdir(dirpath, "*.pid", QDir::Name, QDir::Files);
248 
249  if (subdir.count() == 0) {
250  cerr << "INFO: Found temporary directory with no .pid file in it!\n(directory=\""
251  << dirpath << "\"). Removing it..." << endl;
252  cleanupDirectory(dirpath);
253  cerr << "...done." << endl;
254  continue;
255  }
256 
257  for (unsigned int j = 0; j < subdir.count(); ++j) {
258 
259  bool ok = false;
260  int pid = QFileInfo(subdir[j]).baseName().toInt(&ok);
261  if (!ok) continue;
262 
263  if (GetProcessStatus(pid) == ProcessNotRunning) {
264  cerr << "INFO: Found abandoned temporary directory from "
265  << "a previous, defunct process\n(pid=" << pid
266  << ", directory=\""
267  << dirpath
268  << "\"). Removing it..." << endl;
269  cleanupDirectory(dirpath);
270  cerr << "...done." << endl;
271  break;
272  }
273  }
274  }
275 }
276 
277 
278 
QString m_tmpdir
Definition: TempDirectory.h:86
void cleanup()
Delete the temporary directory (before exiting).
ProcessStatus GetProcessStatus(int pid)
Definition: System.cpp:84
QString createTempDirectoryIn(QString inDir)
QString getPath()
Create the root temporary directory if necessary, and return its path.
A class that manages the creation and removal of a temporary directory tree to store data during the ...
Definition: TempDirectory.h:33
static TempDirectory * getInstance()
static TempDirectory * m_instance
Definition: TempDirectory.h:89
void cleanupDirectory(QString tmpDir)
void cleanupAbandonedDirectories(QString svDir)
#define SVDEBUG
Definition: Debug.h:106
QString getSubDirectoryPath(QString subdir)
Create an immediate subdirectory of the root temporary directory of the given name, if it doesn&#39;t already exist, and return its path.
QString getUserResourcePrefix()
Return the root path for user-specific resource installation for this application (i...
virtual ~TempDirectory()
QString getContainingPath()
Return the path of the directory in which the temporary directory has been or will be created...