annotate base/TempDirectory.cpp @ 97:22494cc28c9f

* Reduce number of allocations and deallocations by keeping a spare buffer around (we were generally deallocating and then immediately allocating again, so it's much better not to have to bother as very large allocations can tie up the system)
author Chris Cannam
date Thu, 04 May 2006 20:17:28 +0000
parents e076e676439b
children 604bd4ee3ed4
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@81 17
Chris@81 18 #include <QDir>
Chris@81 19 #include <QFile>
Chris@81 20 #include <QMutexLocker>
Chris@81 21
Chris@81 22 #include <iostream>
Chris@81 23 #include <cassert>
Chris@81 24
Chris@81 25 TempDirectory *
Chris@81 26 TempDirectory::m_instance = new TempDirectory;
Chris@81 27
Chris@81 28 TempDirectory *
Chris@81 29 TempDirectory::instance()
Chris@81 30 {
Chris@81 31 return m_instance;
Chris@81 32 }
Chris@81 33
Chris@81 34 TempDirectory::DirectoryCreationFailed::DirectoryCreationFailed(QString directory) throw() :
Chris@81 35 m_directory(directory)
Chris@81 36 {
Chris@81 37 std::cerr << "ERROR: Directory creation failed for directory: "
Chris@81 38 << directory.toLocal8Bit().data() << std::endl;
Chris@81 39 }
Chris@81 40
Chris@81 41 const char *
Chris@81 42 TempDirectory::DirectoryCreationFailed::what() const throw()
Chris@81 43 {
Chris@81 44 return QString("Directory creation failed for \"%1\"")
Chris@81 45 .arg(m_directory).toLocal8Bit().data();
Chris@81 46 }
Chris@81 47
Chris@81 48 TempDirectory::TempDirectory() :
Chris@81 49 m_tmpdir("")
Chris@81 50 {
Chris@81 51 }
Chris@81 52
Chris@81 53 TempDirectory::~TempDirectory()
Chris@81 54 {
Chris@81 55 std::cerr << "TempDirectory::~TempDirectory" << std::endl;
Chris@81 56
Chris@81 57 cleanup();
Chris@81 58 }
Chris@81 59
Chris@81 60 void
Chris@81 61 TempDirectory::cleanup()
Chris@81 62 {
Chris@81 63 cleanupDirectory("");
Chris@81 64 }
Chris@81 65
Chris@81 66 QString
Chris@81 67 TempDirectory::getPath()
Chris@81 68 {
Chris@81 69 QMutexLocker locker(&m_mutex);
Chris@81 70
Chris@81 71 if (m_tmpdir != "") return m_tmpdir;
Chris@81 72
Chris@86 73 //!!! QDir tempDirBase = QDir::temp();
Chris@86 74 QDir tempDirBase = QDir::home();
Chris@81 75
Chris@81 76 // Generate a temporary directory. Qt4.1 doesn't seem to be able
Chris@81 77 // to do this for us, and mkdtemp is not standard. This method is
Chris@81 78 // based on the way glibc does mkdtemp.
Chris@81 79
Chris@81 80 static QString chars =
Chris@81 81 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Chris@81 82
Chris@81 83 QString suffix;
Chris@81 84 int padlen = 6, attempts = 100;
Chris@81 85 unsigned int r = time(0) ^ getpid();
Chris@81 86
Chris@81 87 for (int i = 0; i < padlen; ++i) {
Chris@81 88 suffix += "X";
Chris@81 89 }
Chris@81 90
Chris@81 91 for (int j = 0; j < attempts; ++j) {
Chris@81 92
Chris@81 93 unsigned int v = r;
Chris@81 94
Chris@81 95 for (int i = 0; i < padlen; ++i) {
Chris@81 96 suffix[i] = chars[v % 62];
Chris@81 97 v /= 62;
Chris@81 98 }
Chris@81 99
Chris@81 100 QString candidate = QString("sv_%1").arg(suffix);
Chris@81 101
Chris@86 102 if (tempDirBase.mkpath(candidate)) {
Chris@86 103 m_tmpdir = tempDirBase.filePath(candidate);
Chris@81 104 break;
Chris@81 105 }
Chris@81 106
Chris@81 107 r = r + 7777;
Chris@81 108 }
Chris@81 109
Chris@81 110 if (m_tmpdir == "") {
Chris@81 111 throw DirectoryCreationFailed(QString("temporary subdirectory in %1")
Chris@86 112 .arg(tempDirBase.canonicalPath()));
Chris@81 113 }
Chris@81 114
Chris@81 115 return m_tmpdir;
Chris@81 116 }
Chris@81 117
Chris@81 118 QString
Chris@81 119 TempDirectory::getSubDirectoryPath(QString subdir)
Chris@81 120 {
Chris@81 121 QString tmpdirpath = getPath();
Chris@81 122
Chris@81 123 QMutexLocker locker(&m_mutex);
Chris@81 124
Chris@81 125 QDir tmpdir(tmpdirpath);
Chris@81 126 QFileInfo fi(tmpdir.filePath(subdir));
Chris@81 127
Chris@81 128 if (!fi.exists()) {
Chris@81 129 if (!tmpdir.mkdir(subdir)) {
Chris@81 130 throw DirectoryCreationFailed(fi.filePath());
Chris@81 131 } else {
Chris@81 132 return fi.filePath();
Chris@81 133 }
Chris@81 134 } else if (fi.isDir()) {
Chris@81 135 return fi.filePath();
Chris@81 136 } else {
Chris@81 137 throw DirectoryCreationFailed(fi.filePath());
Chris@81 138 }
Chris@81 139 }
Chris@81 140
Chris@81 141 void
Chris@81 142 TempDirectory::cleanupDirectory(QString tmpdir)
Chris@81 143 {
Chris@81 144 bool isRoot = false;
Chris@81 145
Chris@81 146 if (tmpdir == "") {
Chris@81 147
Chris@81 148 m_mutex.lock();
Chris@81 149
Chris@81 150 isRoot = true;
Chris@81 151 tmpdir = m_tmpdir;
Chris@81 152
Chris@81 153 if (tmpdir == "") {
Chris@81 154 m_mutex.unlock();
Chris@81 155 return;
Chris@81 156 }
Chris@81 157 }
Chris@81 158
Chris@81 159 QDir dir(tmpdir);
Chris@83 160 dir.setFilter(QDir::Dirs | QDir::Files);
Chris@81 161
Chris@81 162 for (unsigned int i = 0; i < dir.count(); ++i) {
Chris@81 163
Chris@83 164 if (dir[i] == "." || dir[i] == "..") continue;
Chris@81 165 QFileInfo fi(dir.filePath(dir[i]));
Chris@81 166
Chris@81 167 if (fi.isDir()) {
Chris@81 168 cleanupDirectory(fi.absoluteFilePath());
Chris@81 169 } else {
Chris@81 170 if (!QFile(fi.absoluteFilePath()).remove()) {
Chris@81 171 std::cerr << "WARNING: TempDirectory::cleanup: "
Chris@81 172 << "Failed to unlink file \""
Chris@81 173 << fi.absoluteFilePath().toStdString() << "\""
Chris@81 174 << std::endl;
Chris@81 175 }
Chris@81 176 }
Chris@81 177 }
Chris@81 178
Chris@81 179 QString dirname = dir.dirName();
Chris@81 180 if (dirname != "") {
Chris@81 181 if (!dir.cdUp()) {
Chris@81 182 std::cerr << "WARNING: TempDirectory::cleanup: "
Chris@81 183 << "Failed to cd to parent directory of "
Chris@81 184 << tmpdir.toStdString() << std::endl;
Chris@81 185 return;
Chris@81 186 }
Chris@81 187 if (!dir.rmdir(dirname)) {
Chris@81 188 std::cerr << "WARNING: TempDirectory::cleanup: "
Chris@81 189 << "Failed to remove directory "
Chris@81 190 << dirname.toStdString() << std::endl;
Chris@81 191 }
Chris@81 192 }
Chris@81 193
Chris@81 194 if (isRoot) {
Chris@81 195 m_tmpdir = "";
Chris@81 196 m_mutex.unlock();
Chris@81 197 }
Chris@81 198 }