Browse Source

Don't remove torrent contents parent folder, even it is empty. Closes #2244.

adaptive-webui-19844
Chocobo1 10 years ago
parent
commit
4fcd107ff3
  1. 29
      src/core/bittorrent/session.cpp
  2. 2
      src/core/bittorrent/session.h
  3. 79
      src/core/utils/fs.cpp
  4. 3
      src/core/utils/fs.h

29
src/core/bittorrent/session.cpp

@ -813,11 +813,11 @@ bool Session::deleteTorrent(const QString &hash, bool deleteLocalFiles)
// Remove it from session // Remove it from session
if (deleteLocalFiles) { if (deleteLocalFiles) {
QDir saveDir(torrent->actualSavePath()); QString tmp = torrent->filePath(0);
if ((saveDir != QDir(m_defaultSavePath)) && (saveDir != QDir(m_tempPath))) { tmp.truncate(tmp.indexOf("/")); // get the torrent root directory name
m_savePathsToRemove[torrent->hash()] = saveDir.absolutePath(); if (!tmp.isEmpty())
qDebug() << "Save path to remove (async): " << saveDir.absolutePath(); m_savePathsToRemove[torrent->hash()] = torrent->actualSavePath() + tmp;
}
m_nativeSession->remove_torrent(torrent->nativeHandle(), libt::session::delete_files); m_nativeSession->remove_torrent(torrent->nativeHandle(), libt::session::delete_files);
} }
else { else {
@ -2049,7 +2049,6 @@ void Session::handleAlert(libt::alert *a)
handleMetadataReceivedAlert(static_cast<libt::metadata_received_alert*>(a)); handleMetadataReceivedAlert(static_cast<libt::metadata_received_alert*>(a));
dispatchTorrentAlert(a); dispatchTorrentAlert(a);
break; break;
case libt::state_update_alert::alert_type: case libt::state_update_alert::alert_type:
handleStateUpdateAlert(static_cast<libt::state_update_alert*>(a)); handleStateUpdateAlert(static_cast<libt::state_update_alert*>(a));
break; break;
@ -2065,6 +2064,9 @@ void Session::handleAlert(libt::alert *a)
case libt::torrent_deleted_alert::alert_type: case libt::torrent_deleted_alert::alert_type:
handleTorrentDeletedAlert(static_cast<libt::torrent_deleted_alert*>(a)); handleTorrentDeletedAlert(static_cast<libt::torrent_deleted_alert*>(a));
break; break;
case libt::torrent_delete_failed_alert::alert_type:
handleTorrentDeleteFailedAlert(static_cast<libt::torrent_delete_failed_alert*>(a));
break;
case libt::portmap_error_alert::alert_type: case libt::portmap_error_alert::alert_type:
handlePortmapWarningAlert(static_cast<libt::portmap_error_alert*>(a)); handlePortmapWarningAlert(static_cast<libt::portmap_error_alert*>(a));
break; break;
@ -2178,13 +2180,16 @@ void Session::handleTorrentRemovedAlert(libtorrent::torrent_removed_alert *p)
void Session::handleTorrentDeletedAlert(libt::torrent_deleted_alert *p) void Session::handleTorrentDeletedAlert(libt::torrent_deleted_alert *p)
{ {
m_savePathsToRemove.remove(p->info_hash);
}
void Session::handleTorrentDeleteFailedAlert(libt::torrent_delete_failed_alert *p)
{
// libtorrent won't delete the directory if it contains files not listed in the torrent,
// so we remove the directory ourselves
if (m_savePathsToRemove.contains(p->info_hash)) { if (m_savePathsToRemove.contains(p->info_hash)) {
qDebug("A torrent was deleted from the hard disk, attempting to remove the root folder too..."); QString path = m_savePathsToRemove.take(p->info_hash);
const QString dirpath = m_savePathsToRemove.take(p->info_hash); Utils::Fs::smartRemoveEmptyFolderTree(path);
qDebug() << "Removing save path: " << dirpath << "...";
bool ok = Utils::Fs::smartRemoveEmptyFolderTree(dirpath);
Q_UNUSED(ok);
qDebug() << "Folder was removed: " << ok;
} }
} }

2
src/core/bittorrent/session.h

@ -61,6 +61,7 @@ namespace libtorrent
struct torrent_finished_alert; struct torrent_finished_alert;
struct torrent_removed_alert; struct torrent_removed_alert;
struct torrent_deleted_alert; struct torrent_deleted_alert;
struct torrent_delete_failed_alert;
struct torrent_paused_alert; struct torrent_paused_alert;
struct torrent_resumed_alert; struct torrent_resumed_alert;
struct save_resume_data_alert; struct save_resume_data_alert;
@ -305,6 +306,7 @@ namespace BitTorrent
void handleFileErrorAlert(libtorrent::file_error_alert *p); void handleFileErrorAlert(libtorrent::file_error_alert *p);
void handleTorrentRemovedAlert(libtorrent::torrent_removed_alert *p); void handleTorrentRemovedAlert(libtorrent::torrent_removed_alert *p);
void handleTorrentDeletedAlert(libtorrent::torrent_deleted_alert *p); void handleTorrentDeletedAlert(libtorrent::torrent_deleted_alert *p);
void handleTorrentDeleteFailedAlert(libtorrent::torrent_delete_failed_alert *p);
void handlePortmapWarningAlert(libtorrent::portmap_error_alert *p); void handlePortmapWarningAlert(libtorrent::portmap_error_alert *p);
void handlePortmapAlert(libtorrent::portmap_alert *p); void handlePortmapAlert(libtorrent::portmap_alert *p);
void handlePeerBlockedAlert(libtorrent::peer_blocked_alert *p); void handlePeerBlockedAlert(libtorrent::peer_blocked_alert *p);

79
src/core/utils/fs.cpp

@ -33,6 +33,7 @@
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QSettings> #include <QSettings>
#include <QDirIterator>
#include <QCoreApplication> #include <QCoreApplication>
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
@ -112,57 +113,51 @@ QString Utils::Fs::folderName(const QString& file_path)
} }
/** /**
* Remove an empty folder tree. * This function will first remove system cache files, e.g. `Thumbs.db`,
* * `.DS_Store`. Then will try to remove the whole tree if the tree consist
* This function will also remove .DS_Store files on Mac OS and * only of folders
* Thumbs.db on Windows.
*/ */
bool Utils::Fs::smartRemoveEmptyFolderTree(const QString& dir_path) bool Utils::Fs::smartRemoveEmptyFolderTree(const QString& path)
{ {
qDebug() << Q_FUNC_INFO << dir_path; if (!QDir(path).exists())
if (dir_path.isEmpty())
return false; return false;
QDir dir(dir_path); static const QStringList deleteFilesList = {
if (!dir.exists()) // Windows
return true; "Thumbs.db",
"desktop.ini",
// Linux
".directory",
// Mac OS
".DS_Store"
};
// Remove Files created by the OS // travel from the deepest folder and remove anything unwanted on the way out.
#if defined Q_OS_MAC QStringList dirList(path + "/"); // get all sub directories paths
forceRemove(dir_path + QLatin1String("/.DS_Store")); QDirIterator iter(path, (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories);
#elif defined Q_OS_WIN while (iter.hasNext())
forceRemove(dir_path + QLatin1String("/Thumbs.db")); dirList << iter.next() + "/";
#endif std::sort(dirList.begin(), dirList.end(), [](const QString &l, const QString &r) { return l.count("/") > r.count("/"); }); // sort descending by directory depth
QFileInfoList sub_files = dir.entryInfoList(); for (const QString &p : dirList) {
foreach (const QFileInfo& info, sub_files) { // remove unwanted files
QString sub_name = info.fileName(); for (const QString &f : deleteFilesList) {
if (sub_name == "." || sub_name == "..") forceRemove(p + f);
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 (!forceRemove(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;
} }
// remove temp files on linux (file ends with '~'), e.g. `filename~`
QDir dir(p);
QStringList tmpFileList = dir.entryList(QDir::Files);
for (const QString &f : tmpFileList) {
if (f.endsWith("~"))
forceRemove(p + f);
} }
// remove directory if empty
dir.rmdir(p);
} }
qDebug() << Q_FUNC_INFO << "Calling rmdir on " << dir_path;
return QDir().rmdir(dir_path); return QDir(path).exists();
} }
/** /**

3
src/core/utils/fs.h

@ -55,7 +55,8 @@ namespace Utils
bool sameFileNames(const QString& first, const QString& second); bool sameFileNames(const QString& first, const QString& second);
QString expandPath(const QString& path); QString expandPath(const QString& path);
QString expandPathAbs(const QString& path); QString expandPathAbs(const QString& path);
bool smartRemoveEmptyFolderTree(const QString& dir_path);
bool smartRemoveEmptyFolderTree(const QString& path);
bool forceRemove(const QString& file_path); bool forceRemove(const QString& file_path);
void removeDirRecursive(const QString& dirName); void removeDirRecursive(const QString& dirName);

Loading…
Cancel
Save