00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "TempDirectory.h"
00017 #include "system/System.h"
00018 #include "Exceptions.h"
00019
00020 #include <QDir>
00021 #include <QFile>
00022 #include <QMutexLocker>
00023 #include <QSettings>
00024
00025 #include <iostream>
00026 #include <cassert>
00027
00028 TempDirectory *
00029 TempDirectory::m_instance = new TempDirectory;
00030
00031 TempDirectory *
00032 TempDirectory::getInstance()
00033 {
00034 return m_instance;
00035 }
00036
00037 TempDirectory::TempDirectory() :
00038 m_tmpdir("")
00039 {
00040 }
00041
00042 TempDirectory::~TempDirectory()
00043 {
00044 std::cerr << "TempDirectory::~TempDirectory" << std::endl;
00045
00046 cleanup();
00047 }
00048
00049 void
00050 TempDirectory::cleanup()
00051 {
00052 cleanupDirectory("");
00053 }
00054
00055 QString
00056 TempDirectory::getPath()
00057 {
00058 QMutexLocker locker(&m_mutex);
00059
00060 if (m_tmpdir != "") return m_tmpdir;
00061
00062 QSettings settings;
00063 settings.beginGroup("TempDirectory");
00064 QString svDirParent = settings.value("create-in", "$HOME").toString();
00065 settings.endGroup();
00066
00067 svDirParent.replace("$HOME", QDir::home().absolutePath());
00068
00069 QString svDirBase = ".sv1";
00070 QString svDir = QDir(svDirParent).filePath(svDirBase);
00071 if (!QFileInfo(svDir).exists()) {
00072 if (!QDir(svDirParent).mkdir(svDirBase)) {
00073 throw DirectoryCreationFailed(QString("%1 directory in %2")
00074 .arg(svDirBase).arg(svDirParent));
00075 }
00076 } else if (!QFileInfo(svDir).isDir()) {
00077 throw DirectoryCreationFailed(QString("%1/%2 is not a directory")
00078 .arg(svDirParent).arg(svDirBase));
00079 }
00080
00081 cleanupAbandonedDirectories(svDir);
00082
00083 return createTempDirectoryIn(svDir);
00084 }
00085
00086 QString
00087 TempDirectory::createTempDirectoryIn(QString dir)
00088 {
00089
00090
00091 QDir tempDirBase(dir);
00092
00093
00094
00095
00096
00097 static QString chars =
00098 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
00099
00100 QString suffix;
00101 int padlen = 6, attempts = 100;
00102 unsigned int r = time(0) ^ getpid();
00103
00104 for (int i = 0; i < padlen; ++i) {
00105 suffix += "X";
00106 }
00107
00108 for (int j = 0; j < attempts; ++j) {
00109
00110 unsigned int v = r;
00111
00112 for (int i = 0; i < padlen; ++i) {
00113 suffix[i] = chars[v % 62];
00114 v /= 62;
00115 }
00116
00117 QString candidate = QString("sv_%1").arg(suffix);
00118
00119 if (tempDirBase.mkpath(candidate)) {
00120 m_tmpdir = tempDirBase.filePath(candidate);
00121 break;
00122 }
00123
00124 r = r + 7777;
00125 }
00126
00127 if (m_tmpdir == "") {
00128 throw DirectoryCreationFailed(QString("temporary subdirectory in %1")
00129 .arg(tempDirBase.canonicalPath()));
00130 }
00131
00132 QString pidpath = QDir(m_tmpdir).filePath(QString("%1.pid").arg(getpid()));
00133 QFile pidfile(pidpath);
00134
00135 if (!pidfile.open(QIODevice::WriteOnly)) {
00136 throw DirectoryCreationFailed(QString("pid file creation in %1")
00137 .arg(m_tmpdir));
00138 } else {
00139 pidfile.close();
00140 }
00141
00142 return m_tmpdir;
00143 }
00144
00145 QString
00146 TempDirectory::getSubDirectoryPath(QString subdir)
00147 {
00148 QString tmpdirpath = getPath();
00149
00150 QMutexLocker locker(&m_mutex);
00151
00152 QDir tmpdir(tmpdirpath);
00153 QFileInfo fi(tmpdir.filePath(subdir));
00154
00155 if (!fi.exists()) {
00156 if (!tmpdir.mkdir(subdir)) {
00157 throw DirectoryCreationFailed(fi.filePath());
00158 } else {
00159 return fi.filePath();
00160 }
00161 } else if (fi.isDir()) {
00162 return fi.filePath();
00163 } else {
00164 throw DirectoryCreationFailed(fi.filePath());
00165 }
00166 }
00167
00168 void
00169 TempDirectory::cleanupDirectory(QString tmpdir)
00170 {
00171 bool isRoot = false;
00172
00173 if (tmpdir == "") {
00174
00175 m_mutex.lock();
00176
00177 isRoot = true;
00178 tmpdir = m_tmpdir;
00179
00180 if (tmpdir == "") {
00181 m_mutex.unlock();
00182 return;
00183 }
00184 }
00185
00186 QDir dir(tmpdir);
00187 dir.setFilter(QDir::Dirs | QDir::Files);
00188
00189 for (unsigned int i = 0; i < dir.count(); ++i) {
00190
00191 if (dir[i] == "." || dir[i] == "..") continue;
00192 QFileInfo fi(dir.filePath(dir[i]));
00193
00194 if (fi.isDir()) {
00195 cleanupDirectory(fi.absoluteFilePath());
00196 } else {
00197 if (!QFile(fi.absoluteFilePath()).remove()) {
00198 std::cerr << "WARNING: TempDirectory::cleanup: "
00199 << "Failed to unlink file \""
00200 << fi.absoluteFilePath().toStdString() << "\""
00201 << std::endl;
00202 }
00203 }
00204 }
00205
00206 QString dirname = dir.dirName();
00207 if (dirname != "") {
00208 if (!dir.cdUp()) {
00209 std::cerr << "WARNING: TempDirectory::cleanup: "
00210 << "Failed to cd to parent directory of "
00211 << tmpdir.toStdString() << std::endl;
00212 return;
00213 }
00214 if (!dir.rmdir(dirname)) {
00215 std::cerr << "WARNING: TempDirectory::cleanup: "
00216 << "Failed to remove directory "
00217 << dirname.toStdString() << std::endl;
00218 }
00219 }
00220
00221 if (isRoot) {
00222 m_tmpdir = "";
00223 m_mutex.unlock();
00224 }
00225 }
00226
00227 void
00228 TempDirectory::cleanupAbandonedDirectories(QString svDir)
00229 {
00230 QDir dir(svDir, "sv_*", QDir::Name, QDir::Dirs);
00231
00232 for (unsigned int i = 0; i < dir.count(); ++i) {
00233
00234 QDir subdir(dir.filePath(dir[i]), "*.pid", QDir::Name, QDir::Files);
00235
00236 for (unsigned int j = 0; j < subdir.count(); ++j) {
00237
00238 bool ok = false;
00239 int pid = QFileInfo(subdir[j]).baseName().toInt(&ok);
00240 if (!ok) continue;
00241
00242 if (GetProcessStatus(pid) == ProcessNotRunning) {
00243 std::cerr << "INFO: Found abandoned temporary directory from "
00244 << "a previous, defunct process\n(pid=" << pid
00245 << ", directory=\""
00246 << dir.filePath(dir[i]).toStdString()
00247 << "\"). Removing it..." << std::endl;
00248 cleanupDirectory(dir.filePath(dir[i]));
00249 std::cerr << "...done." << std::endl;
00250 break;
00251 }
00252 }
00253 }
00254 }
00255
00256
00257