annotate base/TempDirectory.cpp @ 498:fdf5930b7ccc

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