From f35e06540e603bcf4c9dfb1d517e63415443124f Mon Sep 17 00:00:00 2001 From: sledgehammer999 Date: Sun, 16 Nov 2014 21:25:42 +0200 Subject: [PATCH] Load torrents that have big metadata file. Closes #1889. --- src/addnewtorrentdialog.cpp | 15 ++-- src/misc.cpp | 13 ++++ src/misc.h | 3 + src/qtlibtorrent/qbtsession.cpp | 125 ++++++++++++++++++-------------- src/torrentimportdlg.cpp | 37 ++++++---- 5 files changed, 116 insertions(+), 77 deletions(-) diff --git a/src/addnewtorrentdialog.cpp b/src/addnewtorrentdialog.cpp index 1857eea14..bea92a70e 100644 --- a/src/addnewtorrentdialog.cpp +++ b/src/addnewtorrentdialog.cpp @@ -191,11 +191,16 @@ bool AddNewTorrentDialog::loadTorrent(const QString& torrent_path, const QString m_hasMetadata = true; try { - m_torrentInfo = new torrent_info(fsutils::toNativePath(m_filePath).toUtf8().data()); - m_hash = misc::toQString(m_torrentInfo->info_hash()); - } catch(const std::exception& e) { - MessageBoxRaised::critical(0, tr("Invalid torrent"), tr("Failed to load the torrent: %1").arg(misc::toQStringU(e.what()))); - return false; + std::vector buffer; + lazy_entry entry; + libtorrent::error_code ec; + misc::loadBencodedFile(m_filePath, buffer, entry, ec); + m_torrentInfo = new torrent_info(entry); + m_hash = misc::toQString(m_torrentInfo->info_hash()); + } + catch(const std::exception& e) { + MessageBoxRaised::critical(0, tr("Invalid torrent"), tr("Failed to load the torrent: %1").arg(misc::toQStringU(e.what()))); + return false; } // Prevent showing the dialog if download is already present diff --git a/src/misc.cpp b/src/misc.cpp index ff78595c9..1718d9580 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -77,6 +77,7 @@ const int UNLEN = 256; #include #endif #include +#include using namespace libtorrent; @@ -655,6 +656,18 @@ bool misc::slowEquals(const QByteArray &a, const QByteArray &b) return (diff == 0); } +void misc::loadBencodedFile(const QString &filename, std::vector &buffer, libtorrent::lazy_entry &entry, libtorrent::error_code &ec) +{ + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) return; + const qint64 content_size = file.bytesAvailable(); + if (content_size <= 0) return; + buffer.resize(content_size); + file.read(&buffer[0], content_size); + // bdecode + lazy_bdecode(&buffer[0], &buffer[0] + buffer.size(), entry, ec); +} + namespace { // Trick to get a portable sleep() function class SleeperThread : public QThread { diff --git a/src/misc.h b/src/misc.h index 8409e84c9..17fad89e0 100644 --- a/src/misc.h +++ b/src/misc.h @@ -44,6 +44,7 @@ #endif #include +#include namespace libtorrent { #if LIBTORRENT_VERSION_NUM < 10000 @@ -52,6 +53,7 @@ namespace libtorrent { #else class sha1_hash; #endif + struct lazy_entry; } const qlonglong MAX_ETA = 8640000; @@ -109,6 +111,7 @@ namespace misc // Implements constant-time comparison to protect against timing attacks // Taken from https://crackstation.net/hashing-security.htm bool slowEquals(const QByteArray &a, const QByteArray &b); + void loadBencodedFile(const QString &filename, std::vector &buffer, libtorrent::lazy_entry &entry, libtorrent::error_code &ec); void msleep(unsigned long msecs); } diff --git a/src/qtlibtorrent/qbtsession.cpp b/src/qtlibtorrent/qbtsession.cpp index 8572c65b6..3c5101f78 100755 --- a/src/qtlibtorrent/qbtsession.cpp +++ b/src/qtlibtorrent/qbtsession.cpp @@ -1058,7 +1058,11 @@ QTorrentHandle QBtSession::addTorrent(QString path, bool fromScanDir, QString fr try { qDebug() << "Loading torrent at" << path; // Getting torrent file informations - t = new torrent_info(fsutils::toNativePath(path).toUtf8().constData()); + std::vector buffer; + lazy_entry entry; + libtorrent::error_code ec; + misc::loadBencodedFile(path, buffer, entry, ec); + t = new torrent_info(entry); if (!t->is_valid()) throw std::exception(); } catch(std::exception& e) { @@ -1508,17 +1512,10 @@ void QBtSession::loadSessionState() { fsutils::forceRemove(state_path); return; } - QFile state_file(state_path); - if (!state_file.open(QIODevice::ReadOnly)) return; std::vector in; - const qint64 content_size = state_file.bytesAvailable(); - if (content_size <= 0) return; - in.resize(content_size); - state_file.read(&in[0], content_size); - // bdecode lazy_entry e; libtorrent::error_code ec; - lazy_bdecode(&in[0], &in[0] + in.size(), e, ec); + misc::loadBencodedFile(state_path, in, e, ec); if (!ec) s->load_state(e); } @@ -1752,28 +1749,33 @@ bool QBtSession::isFilePreviewPossible(const QString &hash) const { return false; } -void QBtSession::addTorrentsFromScanFolder(QStringList &pathList) { - foreach (const QString &file, pathList) { - qDebug("File %s added", qPrintable(file)); - if (file.endsWith(".magnet")) { - QFile f(file); - if (!f.open(QIODevice::ReadOnly)) { - qDebug("Failed to open magnet file: %s", qPrintable(f.errorString())); - } else { - const QString link = QString::fromLocal8Bit(f.readAll()); - addMagnetUri(link, false, true, file); - f.remove(); - } - continue; - } - try { - torrent_info t(fsutils::toNativePath(file).toUtf8().constData()); - if (t.is_valid()) - addTorrent(file, true); - } catch(std::exception&) { - qDebug("Ignoring incomplete torrent file: %s", qPrintable(file)); +void QBtSession::addTorrentsFromScanFolder(QStringList &pathList) +{ + foreach (const QString &file, pathList) { + qDebug("File %s added", qPrintable(file)); + if (file.endsWith(".magnet")) { + QFile f(file); + if (!f.open(QIODevice::ReadOnly)) { + qDebug("Failed to open magnet file: %s", qPrintable(f.errorString())); + } else { + const QString link = QString::fromLocal8Bit(f.readAll()); + addMagnetUri(link, false, true, file); + f.remove(); + } + continue; + } + try { + std::vector buffer; + lazy_entry entry; + libtorrent::error_code ec; + misc::loadBencodedFile(file, buffer, entry, ec); + torrent_info t(entry); + if (t.is_valid()) + addTorrent(file, true); + } catch(std::exception&) { + qDebug("Ignoring incomplete torrent file: %s", qPrintable(file)); + } } - } } void QBtSession::setDefaultSavePath(const QString &savepath) { @@ -2049,24 +2051,30 @@ void QBtSession::disableIPFilter() { filterPath = ""; } -void QBtSession::recursiveTorrentDownload(const QTorrentHandle &h) { - try { - for (int i=0; i t = new torrent_info(fsutils::toNativePath(torrent_fullpath).toUtf8().constData()); - const QString sub_hash = misc::toQString(t->info_hash()); - // Passing the save path along to the sub torrent file - TorrentTempData::setSavePath(sub_hash, h.save_path()); - addTorrent(torrent_fullpath); - } +void QBtSession::recursiveTorrentDownload(const QTorrentHandle &h) +{ + try { + for (int i=0; i buffer; + lazy_entry entry; + libtorrent::error_code ec; + misc::loadBencodedFile(torrent_fullpath, buffer, entry, ec); + boost::intrusive_ptr t = new torrent_info(entry); + const QString sub_hash = misc::toQString(t->info_hash()); + // Passing the save path along to the sub torrent file + TorrentTempData::setSavePath(sub_hash, h.save_path()); + addTorrent(torrent_fullpath); + } + } + } + catch(std::exception&) { + qDebug("Caught error loading torrent"); } - } catch(std::exception&) { - qDebug("Caught error loading torrent"); - } } void QBtSession::autoRunExternalProgram(const QTorrentHandle &h) { @@ -2218,15 +2226,20 @@ void QBtSession::handleTorrentFinishedAlert(libtorrent::torrent_finished_alert* const QString torrent_fullpath = h.save_path()+"/"+torrent_relpath; qDebug("Full subtorrent path is %s", qPrintable(torrent_fullpath)); try { - boost::intrusive_ptr t = new torrent_info(fsutils::toNativePath(torrent_fullpath).toUtf8().constData()); - if (t->is_valid()) { - qDebug("emitting recursiveTorrentDownloadPossible()"); - emit recursiveTorrentDownloadPossible(h); - break; - } - } catch(std::exception&) { - qDebug("Caught error loading torrent"); - addConsoleMessage(tr("Unable to decode %1 torrent file.").arg(fsutils::toNativePath(torrent_fullpath)), QString::fromUtf8("red")); + std::vector buffer; + lazy_entry entry; + libtorrent::error_code ec; + misc::loadBencodedFile(torrent_fullpath, buffer, entry, ec); + boost::intrusive_ptr t = new torrent_info(entry); + if (t->is_valid()) { + qDebug("emitting recursiveTorrentDownloadPossible()"); + emit recursiveTorrentDownloadPossible(h); + break; + } + } + catch(std::exception&) { + qDebug("Caught error loading torrent"); + addConsoleMessage(tr("Unable to decode %1 torrent file.").arg(fsutils::toNativePath(torrent_fullpath)), QString::fromUtf8("red")); } } } diff --git a/src/torrentimportdlg.cpp b/src/torrentimportdlg.cpp index 38e01f74a..0ada519d1 100644 --- a/src/torrentimportdlg.cpp +++ b/src/torrentimportdlg.cpp @@ -215,22 +215,27 @@ void TorrentImportDlg::importTorrent() void TorrentImportDlg::loadTorrent(const QString &torrent_path) { - // Load the torrent file - try { - t = new torrent_info(fsutils::toNativePath(torrent_path).toUtf8().constData()); - if (!t->is_valid() || t->num_files() == 0) - throw std::exception(); - } catch(std::exception&) { - ui->browseContentBtn->setEnabled(false); - ui->lineTorrent->clear(); - QMessageBox::warning(this, tr("Invalid torrent file"), tr("This is not a valid torrent file.")); - return; - } - // Update display - ui->lineTorrent->setText(fsutils::toNativePath(torrent_path)); - ui->browseContentBtn->setEnabled(true); - // Load the file names - initializeFilesPath(); + // Load the torrent file + try { + std::vector buffer; + lazy_entry entry; + libtorrent::error_code ec; + misc::loadBencodedFile(torrent_path, buffer, entry, ec); + t = new torrent_info(entry); + if (!t->is_valid() || t->num_files() == 0) + throw std::exception(); + } + catch(std::exception&) { + ui->browseContentBtn->setEnabled(false); + ui->lineTorrent->clear(); + QMessageBox::warning(this, tr("Invalid torrent file"), tr("This is not a valid torrent file.")); + return; + } + // Update display + ui->lineTorrent->setText(fsutils::toNativePath(torrent_path)); + ui->browseContentBtn->setEnabled(true); + // Load the file names + initializeFilesPath(); } void TorrentImportDlg::initializeFilesPath()