Chris@81: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@81: Chris@81: /* Chris@81: Sonic Visualiser Chris@81: An audio file viewer and annotation editor. Chris@81: Centre for Digital Music, Queen Mary, University of London. Chris@81: This file copyright 2006 Chris Cannam. Chris@81: Chris@81: This program is free software; you can redistribute it and/or Chris@81: modify it under the terms of the GNU General Public License as Chris@81: published by the Free Software Foundation; either version 2 of the Chris@81: License, or (at your option) any later version. See the file Chris@81: COPYING included with this distribution for more information. Chris@81: */ Chris@81: Chris@81: #include "TempDirectory.h" Chris@81: Chris@81: #include Chris@81: #include Chris@81: #include Chris@81: Chris@81: #include Chris@81: #include Chris@81: Chris@81: TempDirectory * Chris@81: TempDirectory::m_instance = new TempDirectory; Chris@81: Chris@81: TempDirectory * Chris@81: TempDirectory::instance() Chris@81: { Chris@81: return m_instance; Chris@81: } Chris@81: Chris@81: TempDirectory::DirectoryCreationFailed::DirectoryCreationFailed(QString directory) throw() : Chris@81: m_directory(directory) Chris@81: { Chris@81: std::cerr << "ERROR: Directory creation failed for directory: " Chris@81: << directory.toLocal8Bit().data() << std::endl; Chris@81: } Chris@81: Chris@81: const char * Chris@81: TempDirectory::DirectoryCreationFailed::what() const throw() Chris@81: { Chris@81: return QString("Directory creation failed for \"%1\"") Chris@81: .arg(m_directory).toLocal8Bit().data(); Chris@81: } Chris@81: Chris@81: TempDirectory::TempDirectory() : Chris@81: m_tmpdir("") Chris@81: { Chris@81: } Chris@81: Chris@81: TempDirectory::~TempDirectory() Chris@81: { Chris@81: std::cerr << "TempDirectory::~TempDirectory" << std::endl; Chris@81: Chris@81: cleanup(); Chris@81: } Chris@81: Chris@81: void Chris@81: TempDirectory::cleanup() Chris@81: { Chris@81: cleanupDirectory(""); Chris@81: } Chris@81: Chris@81: QString Chris@81: TempDirectory::getPath() Chris@81: { Chris@81: QMutexLocker locker(&m_mutex); Chris@81: Chris@81: if (m_tmpdir != "") return m_tmpdir; Chris@81: Chris@81: QDir systemTempDir = QDir::temp(); Chris@81: Chris@81: // Generate a temporary directory. Qt4.1 doesn't seem to be able Chris@81: // to do this for us, and mkdtemp is not standard. This method is Chris@81: // based on the way glibc does mkdtemp. Chris@81: Chris@81: static QString chars = Chris@81: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; Chris@81: Chris@81: QString suffix; Chris@81: int padlen = 6, attempts = 100; Chris@81: unsigned int r = time(0) ^ getpid(); Chris@81: Chris@81: for (int i = 0; i < padlen; ++i) { Chris@81: suffix += "X"; Chris@81: } Chris@81: Chris@81: for (int j = 0; j < attempts; ++j) { Chris@81: Chris@81: unsigned int v = r; Chris@81: Chris@81: for (int i = 0; i < padlen; ++i) { Chris@81: suffix[i] = chars[v % 62]; Chris@81: v /= 62; Chris@81: } Chris@81: Chris@81: QString candidate = QString("sv_%1").arg(suffix); Chris@81: Chris@81: if (QDir::temp().mkpath(candidate)) { Chris@81: m_tmpdir = systemTempDir.filePath(candidate); Chris@81: break; Chris@81: } Chris@81: Chris@81: r = r + 7777; Chris@81: } Chris@81: Chris@81: if (m_tmpdir == "") { Chris@81: throw DirectoryCreationFailed(QString("temporary subdirectory in %1") Chris@81: .arg(systemTempDir.canonicalPath())); Chris@81: } Chris@81: Chris@81: return m_tmpdir; Chris@81: } Chris@81: Chris@81: QString Chris@81: TempDirectory::getSubDirectoryPath(QString subdir) Chris@81: { Chris@81: QString tmpdirpath = getPath(); Chris@81: Chris@81: QMutexLocker locker(&m_mutex); Chris@81: Chris@81: QDir tmpdir(tmpdirpath); Chris@81: QFileInfo fi(tmpdir.filePath(subdir)); Chris@81: Chris@81: if (!fi.exists()) { Chris@81: if (!tmpdir.mkdir(subdir)) { Chris@81: throw DirectoryCreationFailed(fi.filePath()); Chris@81: } else { Chris@81: return fi.filePath(); Chris@81: } Chris@81: } else if (fi.isDir()) { Chris@81: return fi.filePath(); Chris@81: } else { Chris@81: throw DirectoryCreationFailed(fi.filePath()); Chris@81: } Chris@81: } Chris@81: Chris@81: void Chris@81: TempDirectory::cleanupDirectory(QString tmpdir) Chris@81: { Chris@81: bool isRoot = false; Chris@81: Chris@81: if (tmpdir == "") { Chris@81: Chris@81: m_mutex.lock(); Chris@81: Chris@81: isRoot = true; Chris@81: tmpdir = m_tmpdir; Chris@81: Chris@81: if (tmpdir == "") { Chris@81: m_mutex.unlock(); Chris@81: return; Chris@81: } Chris@81: } Chris@81: Chris@81: QDir dir(tmpdir); Chris@81: dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); Chris@81: Chris@81: for (unsigned int i = 0; i < dir.count(); ++i) { Chris@81: Chris@81: QFileInfo fi(dir.filePath(dir[i])); Chris@81: Chris@81: if (fi.isDir()) { Chris@81: cleanupDirectory(fi.absoluteFilePath()); Chris@81: } else { Chris@81: if (!QFile(fi.absoluteFilePath()).remove()) { Chris@81: std::cerr << "WARNING: TempDirectory::cleanup: " Chris@81: << "Failed to unlink file \"" Chris@81: << fi.absoluteFilePath().toStdString() << "\"" Chris@81: << std::endl; Chris@81: } Chris@81: } Chris@81: } Chris@81: Chris@81: QString dirname = dir.dirName(); Chris@81: if (dirname != "") { Chris@81: if (!dir.cdUp()) { Chris@81: std::cerr << "WARNING: TempDirectory::cleanup: " Chris@81: << "Failed to cd to parent directory of " Chris@81: << tmpdir.toStdString() << std::endl; Chris@81: return; Chris@81: } Chris@81: if (!dir.rmdir(dirname)) { Chris@81: std::cerr << "WARNING: TempDirectory::cleanup: " Chris@81: << "Failed to remove directory " Chris@81: << dirname.toStdString() << std::endl; Chris@81: } Chris@81: } Chris@81: Chris@81: if (isRoot) { Chris@81: m_tmpdir = ""; Chris@81: m_mutex.unlock(); Chris@81: } Chris@81: }