From 14625a565deea677a7e452141193f68d2ab71265 Mon Sep 17 00:00:00 2001 From: Christophe Dumez Date: Sat, 17 Mar 2012 15:41:32 +0200 Subject: [PATCH] Make sure OS-created files do not prevent "empty" folder removal Mac OS X creates .DS_Store files and Windows creates .Thumbs.db files which can prevent otherwise empty folders removal. (cherry picked from commit 41b57a0878f1ea14695114416387630d084baada) --- src/qtlibtorrent/qbtsession.cpp | 67 ++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/src/qtlibtorrent/qbtsession.cpp b/src/qtlibtorrent/qbtsession.cpp index 41c92abe4..c962fa81b 100644 --- a/src/qtlibtorrent/qbtsession.cpp +++ b/src/qtlibtorrent/qbtsession.cpp @@ -90,6 +90,67 @@ const qreal QBtSession::MAX_RATIO = 9999.; const int MAX_TRACKER_ERRORS = 2; +/* Converts a QString hash into a libtorrent sha1_hash */ +static libtorrent::sha1_hash QStringToSha1(const QString& s) { + QByteArray raw = s.toAscii(); + Q_ASSERT(raw.size() == 40); + libtorrent::sha1_hash ret; + from_hex(raw.constData(), 40, (char*)&ret[0]); + return ret; +} + +/** + * Remove an empty folder tree. + * + * This function will also remove .DS_Store files on Mac OS and + * Thumbs.db on Windows. + */ +static bool smartRemoveEmptyFolderTree(const QString& dir_path) +{ + qDebug() << Q_FUNC_INFO << dir_path; + if (dir_path.isEmpty()) + return false; + + QDir dir(dir_path); + if (!dir.exists()) + return true; + + // Remove Files created by the OS +#if defined Q_WS_MAC + QFile::remove(dir_path + QLatin1String("/.DS_Store")); +#elif defined Q_WS_WIN + QFile::remove(dir_path + QLatin1String("/Thumbs.db")); +#endif + + QFileInfoList sub_files = dir.entryInfoList(); + foreach (const QFileInfo& info, sub_files) { + QString sub_name = info.fileName(); + if (sub_name == "." || sub_name == "..") + continue; + + QString sub_path = info.absoluteFilePath(); + qDebug() << Q_FUNC_INFO << "sub file: " << sub_path; + if (info.isDir()) { + if (!smartRemoveEmptyFolderTree(sub_path)) { + qWarning() << Q_FUNC_INFO << "Failed to remove folder: " << sub_path; + return false; + } + } else { + if (info.isHidden()) { + qDebug() << Q_FUNC_INFO << "Removing hidden file: " << sub_path; + if (!QFile::remove(sub_path)) { + qWarning() << Q_FUNC_INFO << "Failed to remove " << sub_path; + return false; + } + } else { + qWarning() << Q_FUNC_INFO << "Folder is not empty, aborting. Found: " << sub_path; + } + } + } + qDebug() << Q_FUNC_INFO << "Calling rmdir on " << dir_path; + return QDir().rmdir(dir_path); +} + // Main constructor QBtSession::QBtSession() : m_scanFolders(ScanFoldersModel::instance(this)), @@ -772,8 +833,10 @@ void QBtSession::deleteTorrent(const QString &hash, bool delete_local_files) { if(delete_local_files) { if(h.has_metadata()) { QDir save_dir(h.save_path()); - if(save_dir != QDir(defaultSavePath) && (defaultTempPath.isEmpty() || save_dir != QDir(defaultTempPath))) + if (save_dir != QDir(defaultSavePath) && (defaultTempPath.isEmpty() || save_dir != QDir(defaultTempPath))) { savePathsToRemove[hash] = save_dir.absolutePath(); + qDebug() << "Save path to remove (async): " << save_dir.absolutePath(); + } } s->remove_torrent(h, session::delete_files); } else { @@ -2345,7 +2408,7 @@ void QBtSession::readAlerts() { if(savePathsToRemove.contains(hash)) { const QString dirpath = savePathsToRemove.take(hash); qDebug() << "Removing save path: " << dirpath << "..."; - bool ok = misc::removeEmptyFolder(dirpath); + bool ok = smartRemoveEmptyFolderTree(dirpath); Q_UNUSED(ok); qDebug() << "Folder was removed: " << ok; }