diff --git a/src/qtlibtorrent/qbtsession.cpp b/src/qtlibtorrent/qbtsession.cpp index f165cb5dd..e525edea7 100755 --- a/src/qtlibtorrent/qbtsession.cpp +++ b/src/qtlibtorrent/qbtsession.cpp @@ -83,6 +83,7 @@ //initialize static member variables QHash TorrentTempData::data = QHash(); +QHash TorrentTempData::torrentMoveStates = QHash(); QHash HiddenData::data = QHash(); unsigned int HiddenData::metadata_counter = 0; @@ -2415,22 +2416,74 @@ void QBtSession::readAlerts() { } else if (storage_moved_alert* p = dynamic_cast(a.get())) { QTorrentHandle h(p->handle); - if (h.is_valid()) { - // Attempt to remove old folder if empty - const QString old_save_path = TorrentPersistentData::getPreviousPath(h.hash()); - const QString new_save_path = misc::toQStringU(p->path.c_str()); - qDebug("Torrent moved from %s to %s", qPrintable(old_save_path), qPrintable(new_save_path)); - QDir old_save_dir(old_save_path); - if (old_save_dir != QDir(defaultSavePath) && old_save_dir != QDir(defaultTempPath)) { - qDebug("Attempting to remove %s", qPrintable(old_save_path)); - QDir().rmpath(old_save_path); - } - if (defaultTempPath.isEmpty() || !new_save_path.startsWith(defaultTempPath)) { - qDebug("Storage has been moved, updating save path to %s", qPrintable(new_save_path)); - TorrentPersistentData::saveSavePath(h.hash(), new_save_path); - } - emit savePathChanged(h); - //h.force_recheck(); + if (!h.is_valid()) { + qWarning("invalid handle received in storage_moved_alert"); + break; + } + + QString hash = h.hash(); + + if (!TorrentTempData::isMoveInProgress(hash)) { + qWarning("unexpected storage_moved_alert received"); + break; + } + + QString new_save_path = misc::toQStringU(p->path.c_str()); + if (new_save_path != TorrentTempData::getNewPath(hash)) { + qWarning("new path received in handleStorageMovedAlert() doesn't match a path in a queue"); + break; + } + + QString oldPath = TorrentTempData::getOldPath(hash); + + qDebug("Torrent is successfully moved from %s to %s", qPrintable(oldPath), qPrintable(new_save_path)); + + // Attempt to remove old folder if empty + QDir old_save_dir(oldPath); + if (old_save_dir != QDir(defaultSavePath) && old_save_dir != QDir(defaultTempPath)) { + qDebug("Attempting to remove %s", qPrintable(oldPath)); + QDir().rmpath(oldPath); + } + if (defaultTempPath.isEmpty() || !new_save_path.startsWith(defaultTempPath)) { + qDebug("Storage has been moved, updating save path to %s", qPrintable(new_save_path)); + TorrentPersistentData::saveSavePath(h.hash(), new_save_path); + } + emit savePathChanged(h); + //h.force_recheck(); + + QString queued = TorrentTempData::getQueuedPath(hash); + if (!queued.isEmpty()) { + TorrentTempData::finishMove(hash); + h.move_storage(queued); + } + else { + TorrentTempData::finishMove(hash); + } + } + else if (storage_moved_failed_alert* p = dynamic_cast(a.get())) { + QTorrentHandle h(p->handle); + if (!h.is_valid()) { + qWarning("invalid handle received in storage_moved_failed_alert"); + break; + } + + QString hash = h.hash(); + + if (!TorrentTempData::isMoveInProgress(hash)) { + qWarning("unexpected storage_moved_alert received"); + break; + } + + addConsoleMessage(tr("Could not move torrent: '%1'. Reason: %2").arg(h.name()).arg(misc::toQStringU(p->message())), "red"); + + QString queued = TorrentTempData::getQueuedPath(hash); + if (!queued.isEmpty()) { + TorrentTempData::finishMove(hash); + addConsoleMessage(tr("Attempting to move torrent: '%1' to path: '%2'.").arg(h.name()).arg(queued)); + h.move_storage(queued); + } + else { + TorrentTempData::finishMove(hash); } } else if (metadata_received_alert* p = dynamic_cast(a.get())) { @@ -2988,7 +3041,6 @@ void QBtSession::recoverPersistentData(const QString &hash, const std::vector data) { (*data)["qBt-savePath"] = TorrentPersistentData::getSavePath(hash).toUtf8().constData(); (*data)["qBt-ratioLimit"] = QString::number(TorrentPersistentData::getRatioLimit(hash)).toUtf8().constData(); - (*data)["qBt-previousSavePath"] = TorrentPersistentData::getPreviousPath(hash).toUtf8().constData(); (*data)["qBt-seedDate"] = TorrentPersistentData::getSeedDate(hash).toTime_t(); (*data)["qBt-label"] = TorrentPersistentData::getLabel(hash).toUtf8().constData(); (*data)["qBt-queuePosition"] = TorrentPersistentData::getPriority(hash); diff --git a/src/qtlibtorrent/qtorrenthandle.cpp b/src/qtlibtorrent/qtorrenthandle.cpp index 3cde87596..658f62c0f 100644 --- a/src/qtlibtorrent/qtorrenthandle.cpp +++ b/src/qtlibtorrent/qtorrenthandle.cpp @@ -679,15 +679,26 @@ void QTorrentHandle::set_tracker_login(const QString& username, const QString& p } void QTorrentHandle::move_storage(const QString& new_path) const { - if (QDir(save_path()) == QDir(new_path)) - return; + QString hashstr = hash(); - TorrentPersistentData::setPreviousSavePath(hash(), save_path()); - // Create destination directory if necessary - // or move_storage() will fail... - QDir().mkpath(new_path); - // Actually move the storage - torrent_handle::move_storage(new_path.toUtf8().constData()); + if (TorrentTempData::isMoveInProgress(hashstr)) { + qDebug("enqueue move storage to %s", qPrintable(new_path)); + TorrentTempData::enqueueMove(hashstr, new_path); + } + else { + QString old_path = save_path(); + qDebug("move storage: %s to %s", qPrintable(old_path), qPrintable(new_path)); + if (QDir(old_path) == QDir(new_path)) + return; + + TorrentTempData::startMove(hashstr, old_path, new_path); + + // Create destination directory if necessary + // or move_storage() will fail... + QDir().mkpath(new_path); + // Actually move the storage + torrent_handle::move_storage(new_path.toUtf8().constData()); + } } bool QTorrentHandle::save_torrent_file(const QString& path) const { diff --git a/src/torrentpersistentdata.h b/src/torrentpersistentdata.h index 6f560cbe4..88ee87955 100644 --- a/src/torrentpersistentdata.h +++ b/src/torrentpersistentdata.h @@ -100,6 +100,64 @@ public: fp = data.value(hash).files_priority; } + static bool isMoveInProgress(const QString &hash) { + return torrentMoveStates.find(hash) != torrentMoveStates.end(); + } + + static void enqueueMove(const QString &hash, const QString &queuedPath) { + QHash::iterator i = torrentMoveStates.find(hash); + if (i == torrentMoveStates.end()) { + Q_ASSERT(false); + return; + } + i->queuedPath = queuedPath; + } + + static void startMove(const QString &hash, const QString &oldPath, const QString& newPath) { + QHash::iterator i = torrentMoveStates.find(hash); + if (i != torrentMoveStates.end()) { + Q_ASSERT(false); + return; + } + torrentMoveStates.insert(hash, TorrentMoveState(oldPath, newPath)); + } + + static void finishMove(const QString &hash) { + QHash::iterator i = torrentMoveStates.find(hash); + if (i == torrentMoveStates.end()) { + Q_ASSERT(false); + return; + } + torrentMoveStates.erase(i); + } + + static QString getOldPath(const QString &hash) { + QHash::iterator i = torrentMoveStates.find(hash); + if (i == torrentMoveStates.end()) { + Q_ASSERT(false); + return QString(); + } + return i->oldPath; + } + + static QString getNewPath(const QString &hash) { + QHash::iterator i = torrentMoveStates.find(hash); + if (i == torrentMoveStates.end()) { + Q_ASSERT(false); + return QString(); + } + return i->newPath; + } + + static QString getQueuedPath(const QString &hash) { + QHash::iterator i = torrentMoveStates.find(hash); + if (i == torrentMoveStates.end()) { + Q_ASSERT(false); + return QString(); + } + return i->queuedPath; + } + private: struct TorrentData { TorrentData(): sequential(false), seed(false) {} @@ -111,7 +169,21 @@ private: bool seed; }; + struct TorrentMoveState { + TorrentMoveState(QString oldPath, QString newPath) + : oldPath(oldPath) + , newPath(newPath) + {} + + // the moving occurs from oldPath to newPath + // queuedPath is where files should be moved to, when current moving is completed + QString oldPath; + QString newPath; + QString queuedPath; + }; + static QHash data; + static QHash torrentMoveStates; }; class HiddenData { @@ -238,22 +310,6 @@ public: return data.value("has_error", false).toBool(); } - static void setPreviousSavePath(const QString &hash, const QString &previous_path) { - QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); - QHash all_data = settings.value("torrents").toHash(); - QHash data = all_data.value(hash).toHash(); - data["previous_path"] = previous_path; - all_data[hash] = data; - settings.setValue("torrents", all_data); - } - - static QString getPreviousPath(const QString &hash) { - QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); - const QHash all_data = settings.value("torrents").toHash(); - const QHash data = all_data.value(hash).toHash(); - return data.value("previous_path").toString(); - } - static void saveSeedDate(const QTorrentHandle &h) { QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent-resume")); QHash all_data = settings.value("torrents").toHash();