annotate base/TempDirectory.cpp @ 282:d9319859a4cf tip

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