lbajardsilogic@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: Sonic Visualiser lbajardsilogic@0: An audio file viewer and annotation editor. lbajardsilogic@0: Centre for Digital Music, Queen Mary, University of London. lbajardsilogic@0: This file copyright 2006 Chris Cannam. lbajardsilogic@0: lbajardsilogic@0: This program is free software; you can redistribute it and/or lbajardsilogic@0: modify it under the terms of the GNU General Public License as lbajardsilogic@0: published by the Free Software Foundation; either version 2 of the lbajardsilogic@0: License, or (at your option) any later version. See the file lbajardsilogic@0: COPYING included with this distribution for more information. lbajardsilogic@0: */ lbajardsilogic@0: lbarthelemy@187: lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbarthelemy@187: #include "TempDirectory.h" lbarthelemy@187: #include "system/System.h" lbarthelemy@187: #include "Exceptions.h" lbarthelemy@187: lbajardsilogic@0: TempDirectory * lbajardsilogic@0: TempDirectory::m_instance = new TempDirectory; lbajardsilogic@0: lbajardsilogic@0: TempDirectory * lbajardsilogic@0: TempDirectory::getInstance() lbajardsilogic@0: { lbajardsilogic@0: return m_instance; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: TempDirectory::TempDirectory() : lbajardsilogic@0: m_tmpdir("") lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: TempDirectory::~TempDirectory() lbajardsilogic@0: { lbajardsilogic@0: std::cerr << "TempDirectory::~TempDirectory" << std::endl; lbajardsilogic@0: lbajardsilogic@0: cleanup(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: TempDirectory::cleanup() lbajardsilogic@0: { lbajardsilogic@0: cleanupDirectory(""); lbajardsilogic@0: } lbajardsilogic@0: lbarthelemy@187: QString lbarthelemy@187: TempDirectory::getDir() lbarthelemy@187: { lbarthelemy@187: QMutexLocker locker(&m_mutex); lbarthelemy@187: lbarthelemy@187: QString svDirBase = ".easaier"; lbarthelemy@187: QString svDir = QDir::home().filePath(svDirBase); lbarthelemy@187: if (!QFileInfo(svDir).exists()) { lbarthelemy@187: if (!QDir::home().mkdir(svDirBase)) { lbarthelemy@187: throw DirectoryCreationFailed(QString("%1 directory in $HOME") lbarthelemy@187: .arg(svDirBase)); lbarthelemy@187: } lbarthelemy@187: } else if (!QFileInfo(svDir).isDir()) { lbarthelemy@187: throw DirectoryCreationFailed(QString("$HOME/%1 is not a directory") lbarthelemy@187: .arg(svDirBase)); lbarthelemy@187: } lbarthelemy@187: lbarthelemy@187: cleanupAbandonedDirectories(svDir); lbarthelemy@187: lbarthelemy@187: return svDir; lbajardsilogic@12: } lbajardsilogic@12: lbajardsilogic@0: QString lbajardsilogic@0: TempDirectory::getPath() lbajardsilogic@0: { lbajardsilogic@0: if (m_tmpdir != "") return m_tmpdir; lbajardsilogic@0: lbajardsilogic@12: QString svDir = getDir(); lbajardsilogic@0: lbajardsilogic@0: return createTempDirectoryIn(svDir); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString lbajardsilogic@12: TempDirectory::getConfigPath() lbajardsilogic@12: { lbajardsilogic@12: QString configPath = getDir(); lbajardsilogic@12: configPath.append("/config.xml"); lbajardsilogic@12: lbajardsilogic@12: return configPath; lbajardsilogic@12: } lbajardsilogic@12: lbajardsilogic@12: QString lbajardsilogic@0: TempDirectory::createTempDirectoryIn(QString dir) lbajardsilogic@0: { lbajardsilogic@0: // Entered with mutex held. lbajardsilogic@0: lbajardsilogic@0: QDir tempDirBase(dir); lbajardsilogic@0: lbajardsilogic@0: // Generate a temporary directory. Qt4.1 doesn't seem to be able lbajardsilogic@0: // to do this for us, and mkdtemp is not standard. This method is lbajardsilogic@0: // based on the way glibc does mkdtemp. lbajardsilogic@0: lbajardsilogic@0: static QString chars = lbajardsilogic@0: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; lbajardsilogic@0: lbajardsilogic@0: QString suffix; lbajardsilogic@0: int padlen = 6, attempts = 100; lbajardsilogic@0: unsigned int r = time(0) ^ getpid(); lbajardsilogic@0: lbajardsilogic@0: for (int i = 0; i < padlen; ++i) { lbajardsilogic@0: suffix += "X"; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: for (int j = 0; j < attempts; ++j) { lbajardsilogic@0: lbajardsilogic@0: unsigned int v = r; lbajardsilogic@0: lbajardsilogic@0: for (int i = 0; i < padlen; ++i) { lbajardsilogic@0: suffix[i] = chars[v % 62]; lbajardsilogic@0: v /= 62; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString candidate = QString("sv_%1").arg(suffix); lbajardsilogic@0: lbajardsilogic@0: if (tempDirBase.mkpath(candidate)) { lbajardsilogic@0: m_tmpdir = tempDirBase.filePath(candidate); lbajardsilogic@0: break; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: r = r + 7777; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_tmpdir == "") { lbajardsilogic@0: throw DirectoryCreationFailed(QString("temporary subdirectory in %1") lbajardsilogic@0: .arg(tempDirBase.canonicalPath())); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString pidpath = QDir(m_tmpdir).filePath(QString("%1.pid").arg(getpid())); lbajardsilogic@0: QFile pidfile(pidpath); lbajardsilogic@0: lbajardsilogic@0: if (!pidfile.open(QIODevice::WriteOnly)) { lbajardsilogic@0: throw DirectoryCreationFailed(QString("pid file creation in %1") lbajardsilogic@0: .arg(m_tmpdir)); lbajardsilogic@0: } else { lbajardsilogic@0: pidfile.close(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return m_tmpdir; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString lbajardsilogic@0: TempDirectory::getSubDirectoryPath(QString subdir) lbajardsilogic@0: { lbajardsilogic@0: QString tmpdirpath = getPath(); lbajardsilogic@0: lbajardsilogic@0: QMutexLocker locker(&m_mutex); lbajardsilogic@0: lbajardsilogic@0: QDir tmpdir(tmpdirpath); lbajardsilogic@0: QFileInfo fi(tmpdir.filePath(subdir)); lbajardsilogic@0: lbajardsilogic@0: if (!fi.exists()) { lbajardsilogic@14: //if (!tmpdir.mkdir(subdir)) { lbajardsilogic@14: if (!tmpdir.mkpath(subdir)) { lbajardsilogic@0: throw DirectoryCreationFailed(fi.filePath()); lbajardsilogic@0: } else { lbajardsilogic@0: return fi.filePath(); lbajardsilogic@0: } lbajardsilogic@0: } else if (fi.isDir()) { lbajardsilogic@0: return fi.filePath(); lbajardsilogic@0: } else { lbajardsilogic@0: throw DirectoryCreationFailed(fi.filePath()); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: TempDirectory::cleanupDirectory(QString tmpdir) lbajardsilogic@0: { lbajardsilogic@0: bool isRoot = false; lbajardsilogic@0: lbajardsilogic@0: if (tmpdir == "") { lbajardsilogic@0: lbajardsilogic@0: m_mutex.lock(); lbajardsilogic@0: lbajardsilogic@0: isRoot = true; lbajardsilogic@0: tmpdir = m_tmpdir; lbajardsilogic@0: lbajardsilogic@0: if (tmpdir == "") { lbajardsilogic@0: m_mutex.unlock(); lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QDir dir(tmpdir); lbajardsilogic@0: dir.setFilter(QDir::Dirs | QDir::Files); lbajardsilogic@0: lbajardsilogic@0: for (unsigned int i = 0; i < dir.count(); ++i) { lbajardsilogic@0: lbajardsilogic@0: if (dir[i] == "." || dir[i] == "..") continue; lbajardsilogic@0: QFileInfo fi(dir.filePath(dir[i])); lbajardsilogic@0: lbajardsilogic@0: if (fi.isDir()) { lbajardsilogic@0: cleanupDirectory(fi.absoluteFilePath()); lbajardsilogic@0: } else { lbajardsilogic@45: QFile tempFile(fi.absoluteFilePath()); lbajardsilogic@45: bool permit = tempFile.setPermissions(QFile::ReadOther | QFile::WriteOther); lbajardsilogic@45: if (!permit) lbajardsilogic@45: { lbajardsilogic@45: std::cerr << "WARNING: TempDirectory::cleanup: " lbajardsilogic@45: << "Permission denied \"" lbajardsilogic@45: << fi.absoluteFilePath().toStdString() << "\"" lbajardsilogic@45: << std::endl; lbajardsilogic@45: } lbajardsilogic@45: //if (!QFile(fi.absoluteFilePath()).remove()) lbajardsilogic@45: if (!tempFile.remove()) lbajardsilogic@45: { lbajardsilogic@45: std::cerr << "WARNING: TempDirectory::cleanup: " lbajardsilogic@0: << "Failed to unlink file \"" lbajardsilogic@0: << fi.absoluteFilePath().toStdString() << "\"" lbajardsilogic@0: << std::endl; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString dirname = dir.dirName(); lbajardsilogic@0: if (dirname != "") { lbajardsilogic@0: if (!dir.cdUp()) { lbajardsilogic@0: std::cerr << "WARNING: TempDirectory::cleanup: " lbajardsilogic@0: << "Failed to cd to parent directory of " lbajardsilogic@0: << tmpdir.toStdString() << std::endl; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: if (!dir.rmdir(dirname)) { lbajardsilogic@0: std::cerr << "WARNING: TempDirectory::cleanup: " lbajardsilogic@0: << "Failed to remove directory " lbajardsilogic@0: << dirname.toStdString() << std::endl; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (isRoot) { lbajardsilogic@0: m_tmpdir = ""; lbajardsilogic@0: m_mutex.unlock(); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: TempDirectory::cleanupAbandonedDirectories(QString svDir) lbajardsilogic@0: { lbajardsilogic@0: QDir dir(svDir, "sv_*", QDir::Name, QDir::Dirs); lbajardsilogic@0: lbajardsilogic@0: for (unsigned int i = 0; i < dir.count(); ++i) { lbajardsilogic@0: lbajardsilogic@0: QDir subdir(dir.filePath(dir[i]), "*.pid", QDir::Name, QDir::Files); lbajardsilogic@0: lbajardsilogic@0: for (unsigned int j = 0; j < subdir.count(); ++j) { lbajardsilogic@0: lbajardsilogic@0: bool ok = false; lbajardsilogic@0: int pid = QFileInfo(subdir[j]).baseName().toInt(&ok); lbajardsilogic@0: if (!ok) continue; lbajardsilogic@0: lbajardsilogic@0: if (GetProcessStatus(pid) == ProcessNotRunning) { lbajardsilogic@0: std::cerr << "INFO: Found abandoned temporary directory from " lbajardsilogic@41: << "an old Sound Access process\n(pid=" << pid lbajardsilogic@0: << ", directory=\"" lbajardsilogic@0: << dir.filePath(dir[i]).toStdString() lbajardsilogic@0: << "\"). Removing it..." << std::endl; lbajardsilogic@0: cleanupDirectory(dir.filePath(dir[i])); lbajardsilogic@0: std::cerr << "...done." << std::endl; lbajardsilogic@0: break; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: