annotate base/TempDirectory.cpp @ 167:665342c6ec57

* Add a bit of resistance to pane dragging so as to make it harder to inadvertently drag in the other axis from the one you intended
author Chris Cannam
date Fri, 22 Sep 2006 16:46:10 +0000
parents 4b2ea82fd0ed
children b23eea68357e
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@81 23
Chris@81 24 #include <iostream>
Chris@81 25 #include <cassert>
Chris@81 26
Chris@81 27 TempDirectory *
Chris@81 28 TempDirectory::m_instance = new TempDirectory;
Chris@81 29
Chris@81 30 TempDirectory *
Chris@145 31 TempDirectory::getInstance()
Chris@81 32 {
Chris@81 33 return m_instance;
Chris@81 34 }
Chris@81 35
Chris@81 36 TempDirectory::TempDirectory() :
Chris@81 37 m_tmpdir("")
Chris@81 38 {
Chris@81 39 }
Chris@81 40
Chris@81 41 TempDirectory::~TempDirectory()
Chris@81 42 {
Chris@81 43 std::cerr << "TempDirectory::~TempDirectory" << std::endl;
Chris@81 44
Chris@81 45 cleanup();
Chris@81 46 }
Chris@81 47
Chris@81 48 void
Chris@81 49 TempDirectory::cleanup()
Chris@81 50 {
Chris@81 51 cleanupDirectory("");
Chris@81 52 }
Chris@81 53
Chris@81 54 QString
Chris@81 55 TempDirectory::getPath()
Chris@81 56 {
Chris@81 57 QMutexLocker locker(&m_mutex);
Chris@81 58
Chris@81 59 if (m_tmpdir != "") return m_tmpdir;
Chris@81 60
Chris@126 61 QString svDirBase = ".sv1";
Chris@98 62 QString svDir = QDir::home().filePath(svDirBase);
Chris@98 63 if (!QFileInfo(svDir).exists()) {
Chris@98 64 if (!QDir::home().mkdir(svDirBase)) {
Chris@98 65 throw DirectoryCreationFailed(QString("%1 directory in $HOME")
Chris@98 66 .arg(svDirBase));
Chris@98 67 }
Chris@98 68 } else if (!QFileInfo(svDir).isDir()) {
Chris@98 69 throw DirectoryCreationFailed(QString("$HOME/%1 is not a directory")
Chris@98 70 .arg(svDirBase));
Chris@98 71 }
Chris@98 72
Chris@98 73 cleanupAbandonedDirectories(svDir);
Chris@98 74
Chris@98 75 return createTempDirectoryIn(svDir);
Chris@98 76 }
Chris@98 77
Chris@98 78 QString
Chris@98 79 TempDirectory::createTempDirectoryIn(QString dir)
Chris@98 80 {
Chris@98 81 // Entered with mutex held.
Chris@98 82
Chris@98 83 QDir tempDirBase(dir);
Chris@81 84
Chris@81 85 // Generate a temporary directory. Qt4.1 doesn't seem to be able
Chris@81 86 // to do this for us, and mkdtemp is not standard. This method is
Chris@81 87 // based on the way glibc does mkdtemp.
Chris@81 88
Chris@81 89 static QString chars =
Chris@81 90 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Chris@81 91
Chris@81 92 QString suffix;
Chris@81 93 int padlen = 6, attempts = 100;
Chris@81 94 unsigned int r = time(0) ^ getpid();
Chris@81 95
Chris@81 96 for (int i = 0; i < padlen; ++i) {
Chris@81 97 suffix += "X";
Chris@81 98 }
Chris@81 99
Chris@81 100 for (int j = 0; j < attempts; ++j) {
Chris@81 101
Chris@81 102 unsigned int v = r;
Chris@81 103
Chris@81 104 for (int i = 0; i < padlen; ++i) {
Chris@81 105 suffix[i] = chars[v % 62];
Chris@81 106 v /= 62;
Chris@81 107 }
Chris@81 108
Chris@81 109 QString candidate = QString("sv_%1").arg(suffix);
Chris@81 110
Chris@86 111 if (tempDirBase.mkpath(candidate)) {
Chris@86 112 m_tmpdir = tempDirBase.filePath(candidate);
Chris@81 113 break;
Chris@81 114 }
Chris@81 115
Chris@81 116 r = r + 7777;
Chris@81 117 }
Chris@81 118
Chris@81 119 if (m_tmpdir == "") {
Chris@81 120 throw DirectoryCreationFailed(QString("temporary subdirectory in %1")
Chris@86 121 .arg(tempDirBase.canonicalPath()));
Chris@81 122 }
Chris@81 123
Chris@98 124 QString pidpath = QDir(m_tmpdir).filePath(QString("%1.pid").arg(getpid()));
Chris@98 125 QFile pidfile(pidpath);
Chris@98 126
Chris@98 127 if (!pidfile.open(QIODevice::WriteOnly)) {
Chris@98 128 throw DirectoryCreationFailed(QString("pid file creation in %1")
Chris@98 129 .arg(m_tmpdir));
Chris@98 130 } else {
Chris@98 131 pidfile.close();
Chris@98 132 }
Chris@98 133
Chris@81 134 return m_tmpdir;
Chris@81 135 }
Chris@81 136
Chris@81 137 QString
Chris@81 138 TempDirectory::getSubDirectoryPath(QString subdir)
Chris@81 139 {
Chris@81 140 QString tmpdirpath = getPath();
Chris@81 141
Chris@81 142 QMutexLocker locker(&m_mutex);
Chris@81 143
Chris@81 144 QDir tmpdir(tmpdirpath);
Chris@81 145 QFileInfo fi(tmpdir.filePath(subdir));
Chris@81 146
Chris@81 147 if (!fi.exists()) {
Chris@81 148 if (!tmpdir.mkdir(subdir)) {
Chris@81 149 throw DirectoryCreationFailed(fi.filePath());
Chris@81 150 } else {
Chris@81 151 return fi.filePath();
Chris@81 152 }
Chris@81 153 } else if (fi.isDir()) {
Chris@81 154 return fi.filePath();
Chris@81 155 } else {
Chris@81 156 throw DirectoryCreationFailed(fi.filePath());
Chris@81 157 }
Chris@81 158 }
Chris@81 159
Chris@81 160 void
Chris@81 161 TempDirectory::cleanupDirectory(QString tmpdir)
Chris@81 162 {
Chris@81 163 bool isRoot = false;
Chris@81 164
Chris@81 165 if (tmpdir == "") {
Chris@81 166
Chris@81 167 m_mutex.lock();
Chris@81 168
Chris@81 169 isRoot = true;
Chris@81 170 tmpdir = m_tmpdir;
Chris@81 171
Chris@81 172 if (tmpdir == "") {
Chris@81 173 m_mutex.unlock();
Chris@81 174 return;
Chris@81 175 }
Chris@81 176 }
Chris@81 177
Chris@81 178 QDir dir(tmpdir);
Chris@83 179 dir.setFilter(QDir::Dirs | QDir::Files);
Chris@81 180
Chris@81 181 for (unsigned int i = 0; i < dir.count(); ++i) {
Chris@81 182
Chris@83 183 if (dir[i] == "." || dir[i] == "..") continue;
Chris@81 184 QFileInfo fi(dir.filePath(dir[i]));
Chris@81 185
Chris@81 186 if (fi.isDir()) {
Chris@81 187 cleanupDirectory(fi.absoluteFilePath());
Chris@81 188 } else {
Chris@81 189 if (!QFile(fi.absoluteFilePath()).remove()) {
Chris@81 190 std::cerr << "WARNING: TempDirectory::cleanup: "
Chris@81 191 << "Failed to unlink file \""
Chris@81 192 << fi.absoluteFilePath().toStdString() << "\""
Chris@81 193 << std::endl;
Chris@81 194 }
Chris@81 195 }
Chris@81 196 }
Chris@81 197
Chris@81 198 QString dirname = dir.dirName();
Chris@81 199 if (dirname != "") {
Chris@81 200 if (!dir.cdUp()) {
Chris@81 201 std::cerr << "WARNING: TempDirectory::cleanup: "
Chris@81 202 << "Failed to cd to parent directory of "
Chris@81 203 << tmpdir.toStdString() << std::endl;
Chris@81 204 return;
Chris@81 205 }
Chris@81 206 if (!dir.rmdir(dirname)) {
Chris@81 207 std::cerr << "WARNING: TempDirectory::cleanup: "
Chris@81 208 << "Failed to remove directory "
Chris@81 209 << dirname.toStdString() << std::endl;
Chris@81 210 }
Chris@81 211 }
Chris@81 212
Chris@81 213 if (isRoot) {
Chris@81 214 m_tmpdir = "";
Chris@81 215 m_mutex.unlock();
Chris@81 216 }
Chris@81 217 }
Chris@98 218
Chris@98 219 void
Chris@98 220 TempDirectory::cleanupAbandonedDirectories(QString svDir)
Chris@98 221 {
Chris@98 222 QDir dir(svDir, "sv_*", QDir::Name, QDir::Dirs);
Chris@98 223
Chris@98 224 for (unsigned int i = 0; i < dir.count(); ++i) {
Chris@98 225
Chris@98 226 QDir subdir(dir.filePath(dir[i]), "*.pid", QDir::Name, QDir::Files);
Chris@98 227
Chris@98 228 for (unsigned int j = 0; j < subdir.count(); ++j) {
Chris@98 229
Chris@98 230 bool ok = false;
Chris@98 231 int pid = QFileInfo(subdir[j]).baseName().toInt(&ok);
Chris@98 232 if (!ok) continue;
Chris@98 233
Chris@98 234 if (GetProcessStatus(pid) == ProcessNotRunning) {
Chris@98 235 std::cerr << "INFO: Found abandoned temporary directory from "
Chris@98 236 << "an old Sonic Visualiser process\n(pid=" << pid
Chris@98 237 << ", directory=\""
Chris@98 238 << dir.filePath(dir[i]).toStdString()
Chris@98 239 << "\"). Removing it..." << std::endl;
Chris@98 240 cleanupDirectory(dir.filePath(dir[i]));
Chris@98 241 std::cerr << "...done." << std::endl;
Chris@98 242 break;
Chris@98 243 }
Chris@98 244 }
Chris@98 245 }
Chris@98 246 }
Chris@98 247
Chris@98 248
Chris@98 249