|
|
@ -59,6 +59,7 @@ |
|
|
|
#include "base/profile.h" |
|
|
|
#include "base/profile.h" |
|
|
|
#include "base/tristatebool.h" |
|
|
|
#include "base/tristatebool.h" |
|
|
|
#include "base/utils/fs.h" |
|
|
|
#include "base/utils/fs.h" |
|
|
|
|
|
|
|
#include "base/utils/string.h" |
|
|
|
#include "downloadpriority.h" |
|
|
|
#include "downloadpriority.h" |
|
|
|
#include "peerinfo.h" |
|
|
|
#include "peerinfo.h" |
|
|
|
#include "session.h" |
|
|
|
#include "session.h" |
|
|
@ -1481,6 +1482,7 @@ void TorrentHandle::moveStorage(const QString &newPath, bool overwrite) |
|
|
|
|
|
|
|
|
|
|
|
void TorrentHandle::renameFile(const int index, const QString &name) |
|
|
|
void TorrentHandle::renameFile(const int index, const QString &name) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
m_oldPath[LTFileIndex {index}].push_back(filePath(index)); |
|
|
|
++m_renameCount; |
|
|
|
++m_renameCount; |
|
|
|
m_nativeHandle.rename_file(index, Utils::Fs::toNativePath(name).toStdString()); |
|
|
|
m_nativeHandle.rename_file(index, Utils::Fs::toNativePath(name).toStdString()); |
|
|
|
} |
|
|
|
} |
|
|
@ -1723,10 +1725,14 @@ void TorrentHandle::handleSaveResumeDataFailedAlert(const lt::save_resume_data_f |
|
|
|
{ |
|
|
|
{ |
|
|
|
// if torrent has no metadata we should save dummy fastresume data
|
|
|
|
// if torrent has no metadata we should save dummy fastresume data
|
|
|
|
// containing Magnet URI and qBittorrent own resume data only
|
|
|
|
// containing Magnet URI and qBittorrent own resume data only
|
|
|
|
if (p->error.value() == lt::errors::no_metadata) |
|
|
|
if (p->error.value() == lt::errors::no_metadata) { |
|
|
|
handleSaveResumeDataAlert(nullptr); |
|
|
|
handleSaveResumeDataAlert(nullptr); |
|
|
|
else |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
LogMsg(tr("Save resume data failed. Torrent: \"%1\", error: \"%2\"") |
|
|
|
|
|
|
|
.arg(name(), QString::fromStdString(p->error.message())), Log::CRITICAL); |
|
|
|
m_session->handleTorrentResumeDataFailed(this); |
|
|
|
m_session->handleTorrentResumeDataFailed(this); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void TorrentHandle::handleFastResumeRejectedAlert(const lt::fastresume_rejected_alert *p) |
|
|
|
void TorrentHandle::handleFastResumeRejectedAlert(const lt::fastresume_rejected_alert *p) |
|
|
@ -1744,45 +1750,66 @@ void TorrentHandle::handleFastResumeRejectedAlert(const lt::fastresume_rejected_ |
|
|
|
|
|
|
|
|
|
|
|
void TorrentHandle::handleFileRenamedAlert(const lt::file_renamed_alert *p) |
|
|
|
void TorrentHandle::handleFileRenamedAlert(const lt::file_renamed_alert *p) |
|
|
|
{ |
|
|
|
{ |
|
|
|
const QString newName = Utils::Fs::fromNativePath(p->new_name()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: Check this!
|
|
|
|
|
|
|
|
if (filesCount() > 1) { |
|
|
|
|
|
|
|
// Check if folders were renamed
|
|
|
|
|
|
|
|
QStringList oldPathParts = m_torrentInfo.origFilePath(p->index).split('/'); |
|
|
|
|
|
|
|
oldPathParts.removeLast(); |
|
|
|
|
|
|
|
QString oldPath = oldPathParts.join('/'); |
|
|
|
|
|
|
|
QStringList newPathParts = newName.split('/'); |
|
|
|
|
|
|
|
newPathParts.removeLast(); |
|
|
|
|
|
|
|
const QString newPath = newPathParts.join('/'); |
|
|
|
|
|
|
|
if (!newPathParts.isEmpty() && (oldPath != newPath)) { |
|
|
|
|
|
|
|
qDebug("oldPath(%s) != newPath(%s)", qUtf8Printable(oldPath), qUtf8Printable(newPath)); |
|
|
|
|
|
|
|
oldPath = QString("%1/%2").arg(savePath(true), oldPath); |
|
|
|
|
|
|
|
qDebug("Detected folder renaming, attempt to delete old folder: %s", qUtf8Printable(oldPath)); |
|
|
|
|
|
|
|
QDir().rmpath(oldPath); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We don't really need to call updateStatus() in this place.
|
|
|
|
// We don't really need to call updateStatus() in this place.
|
|
|
|
// All we need to do is make sure we have a valid instance of the TorrentInfo object.
|
|
|
|
// All we need to do is make sure we have a valid instance of the TorrentInfo object.
|
|
|
|
m_torrentInfo = TorrentInfo {m_nativeHandle.torrent_file()}; |
|
|
|
m_torrentInfo = TorrentInfo {m_nativeHandle.torrent_file()}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// remove empty leftover folders
|
|
|
|
|
|
|
|
// for example renaming "a/b/c" to "d/b/c", then folders "a/b" and "a" will
|
|
|
|
|
|
|
|
// be removed if they are empty
|
|
|
|
|
|
|
|
const QString oldFilePath = m_oldPath[LTFileIndex {p->index}].takeFirst(); |
|
|
|
|
|
|
|
const QString newFilePath = Utils::Fs::fromNativePath(p->new_name()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (m_oldPath[LTFileIndex {p->index}].isEmpty()) |
|
|
|
|
|
|
|
m_oldPath.remove(LTFileIndex {p->index}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QVector<QStringRef> oldPathParts = oldFilePath.splitRef('/', QString::SkipEmptyParts); |
|
|
|
|
|
|
|
oldPathParts.removeLast(); // drop file name part
|
|
|
|
|
|
|
|
QVector<QStringRef> newPathParts = newFilePath.splitRef('/', QString::SkipEmptyParts); |
|
|
|
|
|
|
|
newPathParts.removeLast(); // drop file name part
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(Q_OS_WIN) |
|
|
|
|
|
|
|
const Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive; |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
const Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive; |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int pathIdx = 0; |
|
|
|
|
|
|
|
while ((pathIdx < oldPathParts.size()) && (pathIdx < newPathParts.size())) { |
|
|
|
|
|
|
|
if (oldPathParts[pathIdx].compare(newPathParts[pathIdx], caseSensitivity) != 0) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
++pathIdx; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = (oldPathParts.size() - 1); i >= pathIdx; --i) { |
|
|
|
|
|
|
|
QDir().rmdir(savePath() + Utils::String::join(oldPathParts, QLatin1String("/"))); |
|
|
|
|
|
|
|
oldPathParts.removeLast(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
--m_renameCount; |
|
|
|
--m_renameCount; |
|
|
|
while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty()) |
|
|
|
while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty()) |
|
|
|
m_moveFinishedTriggers.takeFirst()(); |
|
|
|
m_moveFinishedTriggers.takeFirst()(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (isPaused() && (m_renameCount == 0)) |
|
|
|
|
|
|
|
saveResumeData(); // otherwise the new path will not be saved
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void TorrentHandle::handleFileRenameFailedAlert(const lt::file_rename_failed_alert *p) |
|
|
|
void TorrentHandle::handleFileRenameFailedAlert(const lt::file_rename_failed_alert *p) |
|
|
|
{ |
|
|
|
{ |
|
|
|
Q_UNUSED(p); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LogMsg(tr("File rename failed. Torrent: \"%1\", file: \"%2\", reason: \"%3\"") |
|
|
|
LogMsg(tr("File rename failed. Torrent: \"%1\", file: \"%2\", reason: \"%3\"") |
|
|
|
.arg(name(), filePath(p->index) |
|
|
|
.arg(name(), filePath(p->index) |
|
|
|
, QString::fromStdString(p->error.message())), Log::WARNING); |
|
|
|
, QString::fromStdString(p->error.message())), Log::WARNING); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m_oldPath[LTFileIndex {p->index}].removeFirst(); |
|
|
|
|
|
|
|
if (m_oldPath[LTFileIndex {p->index}].isEmpty()) |
|
|
|
|
|
|
|
m_oldPath.remove(LTFileIndex {p->index}); |
|
|
|
|
|
|
|
|
|
|
|
--m_renameCount; |
|
|
|
--m_renameCount; |
|
|
|
while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty()) |
|
|
|
while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty()) |
|
|
|
m_moveFinishedTriggers.takeFirst()(); |
|
|
|
m_moveFinishedTriggers.takeFirst()(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (isPaused() && (m_renameCount == 0)) |
|
|
|
|
|
|
|
saveResumeData(); // otherwise the new path will not be saved
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void TorrentHandle::handleFileCompletedAlert(const lt::file_completed_alert *p) |
|
|
|
void TorrentHandle::handleFileCompletedAlert(const lt::file_completed_alert *p) |
|
|
|