mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-08-19 21:03:30 -07:00
Properly remove empty leftover folders after rename
TorrentInfo::origFilePath will return the very original path from .torrent file, not the most recent file path before the rename operation and thus the code would not be working as we expected.
This commit is contained in:
parent
01e4179555
commit
e329c41ef2
5 changed files with 64 additions and 33 deletions
|
@ -1402,6 +1402,7 @@ void TorrentHandle::setTrackerLogin(const QString &username, const QString &pass
|
|||
|
||||
void TorrentHandle::renameFile(int index, const QString &name)
|
||||
{
|
||||
m_oldPath[LTFileIndex {index}].push_back(filePath(index));
|
||||
++m_renameCount;
|
||||
qDebug() << Q_FUNC_INFO << index << name;
|
||||
m_nativeHandle.rename_file(index, Utils::Fs::toNativePath(name).toStdString());
|
||||
|
@ -1685,33 +1686,42 @@ void TorrentHandle::handleFastResumeRejectedAlert(const libtorrent::fastresume_r
|
|||
|
||||
void TorrentHandle::handleFileRenamedAlert(const libtorrent::file_renamed_alert *p)
|
||||
{
|
||||
#if LIBTORRENT_VERSION_NUM < 10100
|
||||
QString newName = Utils::Fs::fromNativePath(QString::fromStdString(p->name));
|
||||
#else
|
||||
QString newName = Utils::Fs::fromNativePath(p->new_name());
|
||||
#endif
|
||||
|
||||
// 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();
|
||||
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.
|
||||
// All we need to do is make sure we have a valid instance of the TorrentInfo object.
|
||||
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;
|
||||
while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty())
|
||||
m_moveFinishedTriggers.takeFirst()();
|
||||
|
@ -1719,7 +1729,13 @@ void TorrentHandle::handleFileRenamedAlert(const libtorrent::file_renamed_alert
|
|||
|
||||
void TorrentHandle::handleFileRenameFailedAlert(const libtorrent::file_rename_failed_alert *p)
|
||||
{
|
||||
Q_UNUSED(p);
|
||||
LogMsg(tr("File rename failed. Torrent: \"%1\", file: \"%2\", reason: \"%3\"")
|
||||
.arg(name(), filePath(p->index)
|
||||
, 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;
|
||||
while (!isMoveInProgress() && (m_renameCount == 0) && !m_moveFinishedTriggers.isEmpty())
|
||||
|
|
|
@ -385,6 +385,12 @@ namespace BitTorrent
|
|||
private:
|
||||
typedef boost::function<void ()> EventTrigger;
|
||||
|
||||
#if (LIBTORRENT_VERSION_NUM < 10200)
|
||||
using LTFileIndex = int;
|
||||
#else
|
||||
using LTFileIndex = lt::file_index_t;
|
||||
#endif
|
||||
|
||||
void updateStatus();
|
||||
void updateStatus(const libtorrent::torrent_status &nativeStatus);
|
||||
void updateState();
|
||||
|
@ -446,6 +452,10 @@ namespace BitTorrent
|
|||
QQueue<EventTrigger> m_moveFinishedTriggers;
|
||||
int m_renameCount;
|
||||
|
||||
// Until libtorrent provide an "old_name" field in `file_renamed_alert`
|
||||
// we will rely on this workaround to remove empty leftover folders
|
||||
QHash<LTFileIndex, QVector<QString>> m_oldPath;
|
||||
|
||||
bool m_useAutoTMM;
|
||||
|
||||
// Persistent data
|
||||
|
|
|
@ -213,3 +213,14 @@ TriStateBool Utils::String::parseTriStateBool(const QString &string)
|
|||
return TriStateBool::False;
|
||||
return TriStateBool::Undefined;
|
||||
}
|
||||
|
||||
QString Utils::String::join(const QVector<QStringRef> &strings, const QString &separator)
|
||||
{
|
||||
if (strings.empty())
|
||||
return {};
|
||||
|
||||
QString ret = strings[0].toString();
|
||||
for (int i = 1; i < strings.count(); ++i)
|
||||
ret += (separator + strings[i]);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#define UTILS_STRING_H
|
||||
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
class QByteArray;
|
||||
class QLatin1String;
|
||||
|
@ -70,6 +71,8 @@ namespace Utils
|
|||
|
||||
bool parseBool(const QString &string, const bool defaultValue);
|
||||
TriStateBool parseTriStateBool(const QString &string);
|
||||
|
||||
QString join(const QVector<QStringRef> &strings, const QString &separator);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -205,15 +205,6 @@ void TorrentContentTreeView::renameSelectedFile(BitTorrent::TorrentHandle *torre
|
|||
if (needForceRecheck)
|
||||
torrent->forceRecheck();
|
||||
|
||||
// Remove old folder
|
||||
const QString oldFullPath = torrent->savePath(true) + oldPath;
|
||||
int timeout = 10;
|
||||
while (!QDir().rmpath(oldFullPath) && (timeout > 0)) {
|
||||
// FIXME: We should not sleep here (freezes the UI for 1 second)
|
||||
QThread::msleep(100);
|
||||
--timeout;
|
||||
}
|
||||
|
||||
model->setData(modelIndex, newName);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue