From b6bf09fc0f948bcf458c8f27930caa2861b6c748 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Mon, 4 May 2020 11:11:24 +0300 Subject: [PATCH 1/4] Fix calculation of torrent current state Some actions can be performed despite of other states (e.g. "Errored" torrent can check its files currently) so the states that relate to such actions should override other (so-called "static") states. --- src/base/bittorrent/torrenthandleimpl.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/base/bittorrent/torrenthandleimpl.cpp b/src/base/bittorrent/torrenthandleimpl.cpp index 2508e9a9f..a6ba38cf4 100644 --- a/src/base/bittorrent/torrenthandleimpl.cpp +++ b/src/base/bittorrent/torrenthandleimpl.cpp @@ -851,15 +851,21 @@ TorrentState TorrentHandleImpl::state() const void TorrentHandleImpl::updateState() { - if (hasError()) { - m_state = TorrentState::Error; - } - else if (m_nativeStatus.state == lt::torrent_status::checking_resume_data) { + if (m_nativeStatus.state == lt::torrent_status::checking_resume_data) { m_state = TorrentState::CheckingResumeData; } + else if (m_nativeStatus.state == lt::torrent_status::checking_files) { + m_state = m_hasSeedStatus ? TorrentState::CheckingUploading : TorrentState::CheckingDownloading; + } + else if (m_nativeStatus.state == lt::torrent_status::allocating) { + m_state = TorrentState::Allocating; + } else if (isMoveInProgress()) { m_state = TorrentState::Moving; } + else if (hasError()) { + m_state = TorrentState::Error; + } else if (hasMissingFiles()) { m_state = TorrentState::MissingFiles; } @@ -878,12 +884,6 @@ void TorrentHandleImpl::updateState() else m_state = m_nativeStatus.upload_payload_rate > 0 ? TorrentState::Uploading : TorrentState::StalledUploading; break; - case lt::torrent_status::allocating: - m_state = TorrentState::Allocating; - break; - case lt::torrent_status::checking_files: - m_state = m_hasSeedStatus ? TorrentState::CheckingUploading : TorrentState::CheckingDownloading; - break; case lt::torrent_status::downloading_metadata: m_state = TorrentState::DownloadingMetadata; break; From e49c55404417e44d27f20688019527489c1f8689 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Fri, 8 May 2020 14:42:02 +0300 Subject: [PATCH 2/4] Improve "move torrent storage" queue --- src/base/bittorrent/session.cpp | 46 +++++++++++-------------- src/base/bittorrent/session.h | 3 +- src/base/bittorrent/torrenthandleimpl.h | 3 +- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index 7fffb8a28..4a9a473e2 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -1889,7 +1889,7 @@ bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOptio const auto iter = std::find_if(m_moveStorageQueue.begin() + 1, m_moveStorageQueue.end() , [torrent](const MoveStorageJob &job) { - return job.torrent == torrent; + return job.torrentHandle == torrent->nativeHandle(); }); if (iter != m_moveStorageQueue.end()) m_moveStorageQueue.erase(iter); @@ -4034,11 +4034,13 @@ bool Session::addMoveTorrentStorageJob(TorrentHandleImpl *torrent, const QString { Q_ASSERT(torrent); + const lt::torrent_handle torrentHandle = torrent->nativeHandle(); + if (m_moveStorageQueue.size() > 1) { const auto iter = std::find_if(m_moveStorageQueue.begin() + 1, m_moveStorageQueue.end() - , [torrent](const MoveStorageJob &job) + , [&torrentHandle](const MoveStorageJob &job) { - return job.torrent == torrent; + return job.torrentHandle == torrentHandle; }); if (iter != m_moveStorageQueue.end()) { @@ -4047,9 +4049,8 @@ bool Session::addMoveTorrentStorageJob(TorrentHandleImpl *torrent, const QString } } - QString currentLocation = QString::fromStdString( - torrent->nativeHandle().status(lt::torrent_handle::query_save_path).save_path); - if (!m_moveStorageQueue.isEmpty() && (m_moveStorageQueue.first().torrent == torrent)) { + QString currentLocation = torrent->actualStorageLocation(); + if (!m_moveStorageQueue.isEmpty() && (m_moveStorageQueue.first().torrentHandle == torrentHandle)) { // if there is active job for this torrent consider its target path as current location // of this torrent to prevent creating meaningless job that will do nothing currentLocation = m_moveStorageQueue.first().path; @@ -4058,7 +4059,7 @@ bool Session::addMoveTorrentStorageJob(TorrentHandleImpl *torrent, const QString if (QDir {currentLocation} == QDir {newPath}) return false; - const MoveStorageJob moveStorageJob {torrent, newPath, mode}; + const MoveStorageJob moveStorageJob {torrentHandle, newPath, mode}; m_moveStorageQueue << moveStorageJob; qDebug("Move storage from \"%s\" to \"%s\" is enqueued.", qUtf8Printable(currentLocation), qUtf8Printable(newPath)); @@ -4070,24 +4071,19 @@ bool Session::addMoveTorrentStorageJob(TorrentHandleImpl *torrent, const QString void Session::moveTorrentStorage(const MoveStorageJob &job) const { - lt::torrent_handle handle = job.torrent->nativeHandle(); - qDebug("Moving torrent storage to \"%s\"...", qUtf8Printable(job.path)); -#if (LIBTORRENT_VERSION_NUM < 10200) - handle.move_storage(job.path.toUtf8().constData() + + job.torrentHandle.move_storage(job.path.toUtf8().constData() , ((job.mode == MoveStorageMode::Overwrite) +#if (LIBTORRENT_VERSION_NUM < 10200) ? lt::always_replace_files : lt::dont_replace)); #else - handle.move_storage(job.path.toUtf8().constData() - , ((job.mode == MoveStorageMode::Overwrite) ? lt::move_flags_t::always_replace_files : lt::move_flags_t::dont_replace)); #endif } void Session::handleMoveTorrentStorageJobFinished(const QString &errorMessage) { - Q_ASSERT(!m_moveStorageQueue.isEmpty()); - const MoveStorageJob finishedJob = m_moveStorageQueue.takeFirst(); if (!m_moveStorageQueue.isEmpty()) moveTorrentStorage(m_moveStorageQueue.first()); @@ -4095,11 +4091,14 @@ void Session::handleMoveTorrentStorageJobFinished(const QString &errorMessage) const auto iter = std::find_if(m_moveStorageQueue.cbegin(), m_moveStorageQueue.cend() , [&finishedJob](const MoveStorageJob &job) { - return job.torrent == finishedJob.torrent; + return job.torrentHandle == finishedJob.torrentHandle; }); if (iter == m_moveStorageQueue.cend()) { // There is no more job for this torrent - finishedJob.torrent->handleStorageMoved(finishedJob.path, errorMessage); + TorrentHandleImpl *torrent = m_torrents.value(finishedJob.torrentHandle.info_hash()); + if (torrent) { + torrent->handleStorageMoved(finishedJob.path, errorMessage); + } } } @@ -4989,23 +4988,18 @@ void Session::handleAlertsDroppedAlert(const lt::alerts_dropped_alert *p) const void Session::handleStorageMovedAlert(const lt::storage_moved_alert *p) { - if (m_moveStorageQueue.isEmpty()) return; + Q_ASSERT(!m_moveStorageQueue.isEmpty()); + Q_ASSERT(m_moveStorageQueue.first().torrentHandle == p->handle); - const TorrentHandleImpl *torrent = m_torrents.value(p->handle.info_hash()); const MoveStorageJob ¤tJob = m_moveStorageQueue.first(); - if (currentJob.torrent != torrent) return; - const QString newPath {p->storage_path()}; handleMoveTorrentStorageJobFinished(newPath != currentJob.path ? tr("New path doesn't match a target path.") : QString {}); } void Session::handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p) { - if (m_moveStorageQueue.isEmpty()) return; - - const TorrentHandleImpl *torrent = m_torrents.value(p->handle.info_hash()); - const MoveStorageJob ¤tJob = m_moveStorageQueue.first(); - if (currentJob.torrent != torrent) return; + Q_ASSERT(!m_moveStorageQueue.isEmpty()); + Q_ASSERT(m_moveStorageQueue.first().torrentHandle == p->handle); handleMoveTorrentStorageJobFinished(QString::fromStdString(p->message())); } diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index bd87f2fd1..233aaf0be 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -528,7 +529,7 @@ namespace BitTorrent private: struct MoveStorageJob { - TorrentHandleImpl *torrent; + lt::torrent_handle torrentHandle; QString path; MoveStorageMode mode; }; diff --git a/src/base/bittorrent/torrenthandleimpl.h b/src/base/bittorrent/torrenthandleimpl.h index fa879e281..78566771c 100644 --- a/src/base/bittorrent/torrenthandleimpl.h +++ b/src/base/bittorrent/torrenthandleimpl.h @@ -254,6 +254,8 @@ namespace BitTorrent void saveResumeData(); void handleStorageMoved(const QString &newPath, const QString &errorMessage); + QString actualStorageLocation() const; + private: typedef std::function EventTrigger; @@ -286,7 +288,6 @@ namespace BitTorrent void resume_impl(bool forced); bool isMoveInProgress() const; - QString actualStorageLocation() const; bool isAutoManaged() const; void setAutoManaged(bool enable); From 378a8636118f466681db0d0e056b856d0443f197 Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Sat, 9 May 2020 09:23:24 +0300 Subject: [PATCH 3/4] Remove unwanted files after torrent removed --- src/base/bittorrent/session.cpp | 64 +++++++++++++++++------ src/base/bittorrent/session.h | 2 +- src/base/bittorrent/torrenthandle.h | 1 - src/base/bittorrent/torrenthandleimpl.cpp | 23 -------- src/base/bittorrent/torrenthandleimpl.h | 1 - 5 files changed, 48 insertions(+), 43 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index 4a9a473e2..d3455baef 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -115,6 +115,7 @@ namespace { #if (LIBTORRENT_VERSION_NUM < 10200) using LTAlertCategory = int; + using LTDownloadPriority = int; using LTPeerClass = int; using LTQueuePosition = int; using LTSessionFlags = int; @@ -122,6 +123,7 @@ namespace using LTString = std::string; #else using LTAlertCategory = lt::alert_category_t; + using LTDownloadPriority = lt::download_priority_t; using LTPeerClass = lt::peer_class_t; using LTQueuePosition = lt::queue_position_t; using LTSessionFlags = lt::session_flags_t; @@ -416,6 +418,34 @@ namespace return {}; } #endif + + QStringList getUnwantedFilePaths(const lt::torrent_handle &torrentHandle) + { + const TorrentInfo torrentInfo {torrentHandle.torrent_file()}; + if (!torrentInfo.isValid()) + return {}; + + const QString savePath = QString::fromStdString( + torrentHandle.status(lt::torrent_handle::query_save_path).save_path); + const QDir saveDir {savePath}; + #if (LIBTORRENT_VERSION_NUM < 10200) + const std::vector fp = torrentHandle.file_priorities(); + #else + const std::vector fp = torrentHandle.get_file_priorities(); + #endif + + QStringList res; + for (int i = 0; i < static_cast(fp.size()); ++i) { + if (fp[i] == LTDownloadPriority {0}) { + const QString path = Utils::Fs::expandPathAbs( + saveDir.absoluteFilePath(torrentInfo.filePath(i))); + if (path.contains(".unwanted")) + res << path; + } + } + + return res; + } } // Session @@ -1845,32 +1875,21 @@ bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOptio // Remove it from session if (deleteOption == Torrent) { - m_removingTorrents[torrent->hash()] = {torrent->name(), "", deleteOption}; - QStringList unwantedFiles; - if (torrent->hasMetadata()) - unwantedFiles = torrent->absoluteFilePathsUnwanted(); + m_removingTorrents[torrent->hash()] = {torrent->name(), getUnwantedFilePaths(torrent->nativeHandle()), deleteOption}; m_nativeSession->remove_torrent(torrent->nativeHandle(), lt::session::delete_partfile); - // Remove unwanted and incomplete files - for (const QString &unwantedFile : asConst(unwantedFiles)) { - qDebug("Removing unwanted file: %s", qUtf8Printable(unwantedFile)); - Utils::Fs::forceRemove(unwantedFile); - const QString parentFolder = Utils::Fs::branchPath(unwantedFile); - qDebug("Attempt to remove parent folder (if empty): %s", qUtf8Printable(parentFolder)); - QDir().rmdir(parentFolder); - } } else { const QString rootPath = torrent->rootPath(true); if (!rootPath.isEmpty()) { // torrent with root folder - m_removingTorrents[torrent->hash()] = {torrent->name(), rootPath, deleteOption}; + m_removingTorrents[torrent->hash()] = {torrent->name(), {rootPath}, deleteOption}; } else if (torrent->useTempPath()) { // torrent without root folder still has it in its temporary save path - m_removingTorrents[torrent->hash()] = {torrent->name(), torrent->savePath(true), deleteOption}; + m_removingTorrents[torrent->hash()] = {torrent->name(), {torrent->actualStorageLocation()}, deleteOption}; } else { - m_removingTorrents[torrent->hash()] = {torrent->name(), "", deleteOption}; + m_removingTorrents[torrent->hash()] = {torrent->name(), {}, deleteOption}; } m_nativeSession->remove_torrent(torrent->nativeHandle(), lt::session::delete_files); } @@ -4608,6 +4627,15 @@ void Session::handleTorrentRemovedAlert(const lt::torrent_removed_alert *p) const auto removingTorrentDataIter = m_removingTorrents.find(infoHash); if (removingTorrentDataIter != m_removingTorrents.end()) { if (removingTorrentDataIter->deleteOption == Torrent) { + // Remove unwanted and incomplete files + for (const QString &unwantedFile : asConst(removingTorrentDataIter->pathsToRemove)) { + qDebug("Removing unwanted file: %s", qUtf8Printable(unwantedFile)); + Utils::Fs::forceRemove(unwantedFile); + const QString parentFolder = Utils::Fs::branchPath(unwantedFile); + qDebug("Attempt to remove parent folder (if empty): %s", qUtf8Printable(parentFolder)); + QDir().rmdir(parentFolder); + } + LogMsg(tr("'%1' was removed from the transfer list.", "'xxx.avi' was removed...").arg(removingTorrentDataIter->name)); m_removingTorrents.erase(removingTorrentDataIter); } @@ -4622,7 +4650,8 @@ void Session::handleTorrentDeletedAlert(const lt::torrent_deleted_alert *p) if (removingTorrentDataIter == m_removingTorrents.end()) return; - Utils::Fs::smartRemoveEmptyFolderTree(removingTorrentDataIter->savePathToRemove); + Q_ASSERT(removingTorrentDataIter->pathsToRemove.count() == 1); + Utils::Fs::smartRemoveEmptyFolderTree(removingTorrentDataIter->pathsToRemove.first()); LogMsg(tr("'%1' was removed from the transfer list and hard disk.", "'xxx.avi' was removed...").arg(removingTorrentDataIter->name)); m_removingTorrents.erase(removingTorrentDataIter); } @@ -4637,7 +4666,8 @@ void Session::handleTorrentDeleteFailedAlert(const lt::torrent_delete_failed_ale // libtorrent won't delete the directory if it contains files not listed in the torrent, // so we remove the directory ourselves - Utils::Fs::smartRemoveEmptyFolderTree(removingTorrentDataIter->savePathToRemove); + Q_ASSERT(removingTorrentDataIter->pathsToRemove.count() == 1); + Utils::Fs::smartRemoveEmptyFolderTree(removingTorrentDataIter->pathsToRemove.first()); if (p->error) { LogMsg(tr("'%1' was removed from the transfer list but the files couldn't be deleted. Error: %2", "'xxx.avi' was removed...") diff --git a/src/base/bittorrent/session.h b/src/base/bittorrent/session.h index 233aaf0be..bea23f3f8 100644 --- a/src/base/bittorrent/session.h +++ b/src/base/bittorrent/session.h @@ -537,7 +537,7 @@ namespace BitTorrent struct RemovingTorrentData { QString name; - QString savePathToRemove; + QStringList pathsToRemove; DeleteOption deleteOption; }; diff --git a/src/base/bittorrent/torrenthandle.h b/src/base/bittorrent/torrenthandle.h index 811e527b9..1960a8b3d 100644 --- a/src/base/bittorrent/torrenthandle.h +++ b/src/base/bittorrent/torrenthandle.h @@ -192,7 +192,6 @@ namespace BitTorrent virtual QString fileName(int index) const = 0; virtual qlonglong fileSize(int index) const = 0; virtual QStringList absoluteFilePaths() const = 0; - virtual QStringList absoluteFilePathsUnwanted() const = 0; virtual QVector filePriorities() const = 0; virtual TorrentInfo info() const = 0; diff --git a/src/base/bittorrent/torrenthandleimpl.cpp b/src/base/bittorrent/torrenthandleimpl.cpp index a6ba38cf4..d2d20c65e 100644 --- a/src/base/bittorrent/torrenthandleimpl.cpp +++ b/src/base/bittorrent/torrenthandleimpl.cpp @@ -660,29 +660,6 @@ QStringList TorrentHandleImpl::absoluteFilePaths() const return res; } -QStringList TorrentHandleImpl::absoluteFilePathsUnwanted() const -{ - if (!hasMetadata()) return {}; - - const QDir saveDir(savePath(true)); -#if (LIBTORRENT_VERSION_NUM < 10200) - const std::vector fp = m_nativeHandle.file_priorities(); -#else - const std::vector fp = m_nativeHandle.get_file_priorities(); -#endif - - QStringList res; - for (int i = 0; i < static_cast(fp.size()); ++i) { - if (fp[i] == LTDownloadPriority {0}) { - const QString path = Utils::Fs::expandPathAbs(saveDir.absoluteFilePath(filePath(i))); - if (path.contains(".unwanted")) - res << path; - } - } - - return res; -} - QVector TorrentHandleImpl::filePriorities() const { #if (LIBTORRENT_VERSION_NUM < 10200) diff --git a/src/base/bittorrent/torrenthandleimpl.h b/src/base/bittorrent/torrenthandleimpl.h index 78566771c..7cefaea80 100644 --- a/src/base/bittorrent/torrenthandleimpl.h +++ b/src/base/bittorrent/torrenthandleimpl.h @@ -148,7 +148,6 @@ namespace BitTorrent QString fileName(int index) const override; qlonglong fileSize(int index) const override; QStringList absoluteFilePaths() const override; - QStringList absoluteFilePathsUnwanted() const override; QVector filePriorities() const override; TorrentInfo info() const override; From 53fd0e1607452d8d90028fccbe5c0a4e67dfea7c Mon Sep 17 00:00:00 2001 From: "Vladimir Golovnev (Glassez)" Date: Sat, 9 May 2020 10:33:05 +0300 Subject: [PATCH 4/4] Wait for storage to be moved when removing torrent --- src/base/bittorrent/session.cpp | 66 ++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp index d3455baef..d18bf7c51 100644 --- a/src/base/bittorrent/session.cpp +++ b/src/base/bittorrent/session.cpp @@ -1875,8 +1875,27 @@ bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOptio // Remove it from session if (deleteOption == Torrent) { - m_removingTorrents[torrent->hash()] = {torrent->name(), getUnwantedFilePaths(torrent->nativeHandle()), deleteOption}; - m_nativeSession->remove_torrent(torrent->nativeHandle(), lt::session::delete_partfile); + const lt::torrent_handle nativeHandle {torrent->nativeHandle()}; + const auto iter = std::find_if(m_moveStorageQueue.begin(), m_moveStorageQueue.end() + , [&nativeHandle](const MoveStorageJob &job) + { + return job.torrentHandle == nativeHandle; + }); + if (iter != m_moveStorageQueue.end()) { + // We shouldn't actually remove torrent until existing "move storage jobs" are done + torrentQueuePositionBottom(nativeHandle); +#if (LIBTORRENT_VERSION_NUM < 10200) + nativeHandle.auto_managed(false); +#else + nativeHandle.unset_flags(lt::torrent_flags::auto_managed); +#endif + nativeHandle.pause(); + m_removingTorrents[torrent->hash()] = {torrent->name(), {}, deleteOption}; + } + else { + m_removingTorrents[torrent->hash()] = {torrent->name(), getUnwantedFilePaths(nativeHandle), deleteOption}; + m_nativeSession->remove_torrent(nativeHandle, lt::session::delete_partfile); + } } else { const QString rootPath = torrent->rootPath(true); @@ -1891,6 +1910,19 @@ bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOptio else { m_removingTorrents[torrent->hash()] = {torrent->name(), {}, deleteOption}; } + + if (m_moveStorageQueue.size() > 1) { + // Delete "move storage job" for the deleted torrent + // (note: we shouldn't delete active job) + const auto iter = std::find_if(m_moveStorageQueue.begin() + 1, m_moveStorageQueue.end() + , [torrent](const MoveStorageJob &job) + { + return job.torrentHandle == torrent->nativeHandle(); + }); + if (iter != m_moveStorageQueue.end()) + m_moveStorageQueue.erase(iter); + } + m_nativeSession->remove_torrent(torrent->nativeHandle(), lt::session::delete_files); } @@ -1902,18 +1934,6 @@ bool Session::deleteTorrent(const InfoHash &hash, const DeleteOption deleteOptio for (const QString &file : files) Utils::Fs::forceRemove(resumeDataDir.absoluteFilePath(file)); - if (m_moveStorageQueue.size() > 1) { - // Delete "move storage job" for the deleted torrent - // (note: we shouldn't delete active job) - const auto iter = std::find_if(m_moveStorageQueue.begin() + 1, m_moveStorageQueue.end() - , [torrent](const MoveStorageJob &job) - { - return job.torrentHandle == torrent->nativeHandle(); - }); - if (iter != m_moveStorageQueue.end()) - m_moveStorageQueue.erase(iter); - } - delete torrent; return true; } @@ -4113,11 +4133,20 @@ void Session::handleMoveTorrentStorageJobFinished(const QString &errorMessage) return job.torrentHandle == finishedJob.torrentHandle; }); if (iter == m_moveStorageQueue.cend()) { - // There is no more job for this torrent TorrentHandleImpl *torrent = m_torrents.value(finishedJob.torrentHandle.info_hash()); if (torrent) { + // There is no more job for this torrent torrent->handleStorageMoved(finishedJob.path, errorMessage); } + else { + // Last job is completed for torrent that being removing, so actually remove it + const lt::torrent_handle nativeHandle {finishedJob.torrentHandle}; + RemovingTorrentData &removingTorrentData = m_removingTorrents[nativeHandle.info_hash()]; + if (removingTorrentData.deleteOption == Torrent) { + removingTorrentData.pathsToRemove = getUnwantedFilePaths(nativeHandle); + m_nativeSession->remove_torrent(nativeHandle, lt::session::delete_partfile); + } + } } } @@ -5019,11 +5048,14 @@ void Session::handleAlertsDroppedAlert(const lt::alerts_dropped_alert *p) const void Session::handleStorageMovedAlert(const lt::storage_moved_alert *p) { Q_ASSERT(!m_moveStorageQueue.isEmpty()); - Q_ASSERT(m_moveStorageQueue.first().torrentHandle == p->handle); const MoveStorageJob ¤tJob = m_moveStorageQueue.first(); + Q_ASSERT(currentJob.torrentHandle == p->handle); + const QString newPath {p->storage_path()}; - handleMoveTorrentStorageJobFinished(newPath != currentJob.path ? tr("New path doesn't match a target path.") : QString {}); + Q_ASSERT(newPath == currentJob.path); + + handleMoveTorrentStorageJobFinished(); } void Session::handleStorageMovedFailedAlert(const lt::storage_moved_failed_alert *p)