mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-03-10 20:31:47 +00:00
Handle exception when torrent file cannot be exported
Both `lt::create_torrent` constructor and `lt::create_torrent::generate()` can throw an exception so we need to handle it to prevent the app from crashing.
This commit is contained in:
parent
6070b41c9b
commit
3faa7226e7
@ -338,18 +338,24 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
|
|||||||
if (torrentInfo)
|
if (torrentInfo)
|
||||||
{
|
{
|
||||||
const QString torrentFilepath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.torrent").arg(id.toString()));
|
const QString torrentFilepath = m_resumeDataDir.absoluteFilePath(QString::fromLatin1("%1.torrent").arg(id.toString()));
|
||||||
const lt::create_torrent torrentCreator = lt::create_torrent(*torrentInfo);
|
|
||||||
const lt::entry metadata = torrentCreator.generate();
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
const auto torrentCreator = lt::create_torrent(*torrentInfo);
|
||||||
|
const lt::entry metadata = torrentCreator.generate();
|
||||||
writeEntryToFile(torrentFilepath, metadata);
|
writeEntryToFile(torrentFilepath, metadata);
|
||||||
}
|
}
|
||||||
catch (const RuntimeError &err)
|
catch (const RuntimeError &err)
|
||||||
{
|
{
|
||||||
LogMsg(tr("Couldn't save torrent metadata to '%1'. Error: %2")
|
LogMsg(tr("Couldn't save torrent metadata to '%1'. Error: %2.")
|
||||||
.arg(torrentFilepath, err.message()), Log::CRITICAL);
|
.arg(torrentFilepath, err.message()), Log::CRITICAL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
catch (const std::exception &err)
|
||||||
|
{
|
||||||
|
LogMsg(tr("Couldn't save torrent metadata to '%1'. Error: %2.")
|
||||||
|
.arg(torrentFilepath, QString::fromLocal8Bit(err.what())), Log::CRITICAL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lt::entry data = lt::write_resume_data(p);
|
lt::entry data = lt::write_resume_data(p);
|
||||||
@ -371,7 +377,7 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
|
|||||||
}
|
}
|
||||||
catch (const RuntimeError &err)
|
catch (const RuntimeError &err)
|
||||||
{
|
{
|
||||||
LogMsg(tr("Couldn't save torrent resume data to '%1'. Error: %2")
|
LogMsg(tr("Couldn't save torrent resume data to '%1'. Error: %2.")
|
||||||
.arg(resumeFilepath, err.message()), Log::CRITICAL);
|
.arg(resumeFilepath, err.message()), Log::CRITICAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -459,9 +459,18 @@ void BitTorrent::DBResumeDataStorage::Worker::store(const TorrentID &id, const L
|
|||||||
const std::shared_ptr<lt::torrent_info> torrentInfo = std::move(p.ti);
|
const std::shared_ptr<lt::torrent_info> torrentInfo = std::move(p.ti);
|
||||||
if (torrentInfo)
|
if (torrentInfo)
|
||||||
{
|
{
|
||||||
const lt::create_torrent torrentCreator = lt::create_torrent(*torrentInfo);
|
try
|
||||||
const lt::entry metadata = torrentCreator.generate();
|
{
|
||||||
lt::bencode(std::back_inserter(bencodedMetadata), metadata);
|
const auto torrentCreator = lt::create_torrent(*torrentInfo);
|
||||||
|
const lt::entry metadata = torrentCreator.generate();
|
||||||
|
lt::bencode(std::back_inserter(bencodedMetadata), metadata);
|
||||||
|
}
|
||||||
|
catch (const std::exception &err)
|
||||||
|
{
|
||||||
|
LogMsg(tr("Couldn't save torrent metadata. Error: %1.")
|
||||||
|
.arg(QString::fromLocal8Bit(err.what())), Log::CRITICAL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
columns.append(DB_COLUMN_METADATA);
|
columns.append(DB_COLUMN_METADATA);
|
||||||
}
|
}
|
||||||
|
@ -2321,7 +2321,7 @@ void Session::exportTorrentFile(const Torrent *torrent, TorrentExportFolder fold
|
|||||||
}
|
}
|
||||||
catch (const RuntimeError &err)
|
catch (const RuntimeError &err)
|
||||||
{
|
{
|
||||||
LogMsg(tr("Couldn't export torrent metadata file '%1'. Reason: %2")
|
LogMsg(tr("Couldn't export torrent metadata file '%1'. Reason: %2.")
|
||||||
.arg(newTorrentPath, err.message()), Log::WARNING);
|
.arg(newTorrentPath, err.message()), Log::WARNING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,12 @@ void TorrentCreatorThread::sendProgressSignal(int currentPieceIdx, int totalPiec
|
|||||||
emit updateProgress(static_cast<int>((currentPieceIdx * 100.) / totalPieces));
|
emit updateProgress(static_cast<int>((currentPieceIdx * 100.) / totalPieces));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TorrentCreatorThread::checkInterruptionRequested() const
|
||||||
|
{
|
||||||
|
if (isInterruptionRequested())
|
||||||
|
throw RuntimeError(tr("Operation aborted"));
|
||||||
|
}
|
||||||
|
|
||||||
void TorrentCreatorThread::run()
|
void TorrentCreatorThread::run()
|
||||||
{
|
{
|
||||||
emit updateProgress(0);
|
emit updateProgress(0);
|
||||||
@ -118,7 +124,7 @@ void TorrentCreatorThread::run()
|
|||||||
// need to sort the file names by natural sort order
|
// need to sort the file names by natural sort order
|
||||||
QStringList dirs = {m_params.inputPath};
|
QStringList dirs = {m_params.inputPath};
|
||||||
|
|
||||||
QDirIterator dirIter(m_params.inputPath, (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories);
|
QDirIterator dirIter {m_params.inputPath, (QDir::AllDirs | QDir::NoDotAndDotDot), QDirIterator::Subdirectories};
|
||||||
while (dirIter.hasNext())
|
while (dirIter.hasNext())
|
||||||
{
|
{
|
||||||
dirIter.next();
|
dirIter.next();
|
||||||
@ -151,7 +157,7 @@ void TorrentCreatorThread::run()
|
|||||||
fs.add_file(fileName.toStdString(), fileSizeMap[fileName]);
|
fs.add_file(fileName.toStdString(), fileSizeMap[fileName]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInterruptionRequested()) return;
|
checkInterruptionRequested();
|
||||||
|
|
||||||
#if (LIBTORRENT_VERSION_NUM >= 20000)
|
#if (LIBTORRENT_VERSION_NUM >= 20000)
|
||||||
lt::create_torrent newTorrent {fs, m_params.pieceSize, toNativeTorrentFormatFlag(m_params.torrentFormat)};
|
lt::create_torrent newTorrent {fs, m_params.pieceSize, toNativeTorrentFormatFlag(m_params.torrentFormat)};
|
||||||
@ -181,9 +187,7 @@ void TorrentCreatorThread::run()
|
|||||||
lt::set_piece_hashes(newTorrent, Utils::Fs::toNativePath(parentPath).toStdString()
|
lt::set_piece_hashes(newTorrent, Utils::Fs::toNativePath(parentPath).toStdString()
|
||||||
, [this, &newTorrent](const lt::piece_index_t n)
|
, [this, &newTorrent](const lt::piece_index_t n)
|
||||||
{
|
{
|
||||||
if (isInterruptionRequested())
|
checkInterruptionRequested();
|
||||||
throw RuntimeError {tr("Create new torrent aborted.")};
|
|
||||||
|
|
||||||
sendProgressSignal(static_cast<LTUnderlyingType<lt::piece_index_t>>(n), newTorrent.num_pieces());
|
sendProgressSignal(static_cast<LTUnderlyingType<lt::piece_index_t>>(n), newTorrent.num_pieces());
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -194,7 +198,7 @@ void TorrentCreatorThread::run()
|
|||||||
// Is private ?
|
// Is private ?
|
||||||
newTorrent.set_priv(m_params.isPrivate);
|
newTorrent.set_priv(m_params.isPrivate);
|
||||||
|
|
||||||
if (isInterruptionRequested()) return;
|
checkInterruptionRequested();
|
||||||
|
|
||||||
lt::entry entry = newTorrent.generate();
|
lt::entry entry = newTorrent.generate();
|
||||||
|
|
||||||
@ -202,32 +206,30 @@ void TorrentCreatorThread::run()
|
|||||||
if (!m_params.source.isEmpty())
|
if (!m_params.source.isEmpty())
|
||||||
entry["info"]["source"] = m_params.source.toStdString();
|
entry["info"]["source"] = m_params.source.toStdString();
|
||||||
|
|
||||||
if (isInterruptionRequested()) return;
|
checkInterruptionRequested();
|
||||||
|
|
||||||
// create the torrent
|
// create the torrent
|
||||||
QFile outfile {m_params.savePath};
|
QFile outfile {m_params.savePath};
|
||||||
if (!outfile.open(QIODevice::WriteOnly))
|
if (!outfile.open(QIODevice::WriteOnly))
|
||||||
{
|
throw RuntimeError(outfile.errorString());
|
||||||
throw RuntimeError {tr("Create new torrent file failed. Reason: %1")
|
|
||||||
.arg(outfile.errorString())};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isInterruptionRequested()) return;
|
checkInterruptionRequested();
|
||||||
|
|
||||||
lt::bencode(Utils::IO::FileDeviceOutputIterator {outfile}, entry);
|
lt::bencode(Utils::IO::FileDeviceOutputIterator {outfile}, entry);
|
||||||
if (outfile.error() != QFileDevice::NoError)
|
if (outfile.error() != QFileDevice::NoError)
|
||||||
{
|
throw RuntimeError(outfile.errorString());
|
||||||
throw RuntimeError {tr("Create new torrent file failed. Reason: %1")
|
|
||||||
.arg(outfile.errorString())};
|
|
||||||
}
|
|
||||||
outfile.close();
|
outfile.close();
|
||||||
|
|
||||||
emit updateProgress(100);
|
emit updateProgress(100);
|
||||||
emit creationSuccess(m_params.savePath, parentPath);
|
emit creationSuccess(m_params.savePath, parentPath);
|
||||||
}
|
}
|
||||||
catch (const std::exception &e)
|
catch (const RuntimeError &err)
|
||||||
{
|
{
|
||||||
emit creationFailure(e.what());
|
emit creationFailure(tr("Create new torrent file failed. Reason: %1.").arg(err.message()));
|
||||||
|
}
|
||||||
|
catch (const std::exception &err)
|
||||||
|
{
|
||||||
|
emit creationFailure(tr("Create new torrent file failed. Reason: %1.").arg(QString::fromLocal8Bit(err.what())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,10 +65,11 @@ namespace BitTorrent
|
|||||||
class TorrentCreatorThread final : public QThread
|
class TorrentCreatorThread final : public QThread
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Q_DISABLE_COPY_MOVE(TorrentCreatorThread)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TorrentCreatorThread(QObject *parent = nullptr);
|
explicit TorrentCreatorThread(QObject *parent = nullptr);
|
||||||
~TorrentCreatorThread();
|
~TorrentCreatorThread() override;
|
||||||
|
|
||||||
void create(const TorrentCreatorParams ¶ms);
|
void create(const TorrentCreatorParams ¶ms);
|
||||||
|
|
||||||
@ -79,16 +80,15 @@ namespace BitTorrent
|
|||||||
, const int pieceSize, const bool isAlignmentOptimized, int paddedFileSizeLimit);
|
, const int pieceSize, const bool isAlignmentOptimized, int paddedFileSizeLimit);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
|
||||||
void run() override;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void creationFailure(const QString &msg);
|
void creationFailure(const QString &msg);
|
||||||
void creationSuccess(const QString &path, const QString &branchPath);
|
void creationSuccess(const QString &path, const QString &branchPath);
|
||||||
void updateProgress(int progress);
|
void updateProgress(int progress);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void run() override;
|
||||||
void sendProgressSignal(int currentPieceIdx, int totalPieces);
|
void sendProgressSignal(int currentPieceIdx, int totalPieces);
|
||||||
|
void checkInterruptionRequested() const;
|
||||||
|
|
||||||
TorrentCreatorParams m_params;
|
TorrentCreatorParams m_params;
|
||||||
};
|
};
|
||||||
|
@ -167,18 +167,25 @@ TorrentInfo TorrentInfo::loadFromFile(const QString &path, QString *error) noexc
|
|||||||
void TorrentInfo::saveToFile(const QString &path) const
|
void TorrentInfo::saveToFile(const QString &path) const
|
||||||
{
|
{
|
||||||
if (!isValid())
|
if (!isValid())
|
||||||
throw RuntimeError {tr("Invalid metadata.")};
|
throw RuntimeError {tr("Invalid metadata")};
|
||||||
|
|
||||||
const lt::create_torrent torrentCreator = lt::create_torrent(*(nativeInfo()));
|
try
|
||||||
const lt::entry torrentEntry = torrentCreator.generate();
|
{
|
||||||
|
const auto torrentCreator = lt::create_torrent(*nativeInfo());
|
||||||
|
const lt::entry torrentEntry = torrentCreator.generate();
|
||||||
|
|
||||||
QFile torrentFile {path};
|
QFile torrentFile {path};
|
||||||
if (!torrentFile.open(QIODevice::WriteOnly))
|
if (!torrentFile.open(QIODevice::WriteOnly))
|
||||||
throw RuntimeError {torrentFile.errorString()};
|
throw RuntimeError(torrentFile.errorString());
|
||||||
|
|
||||||
lt::bencode(Utils::IO::FileDeviceOutputIterator {torrentFile}, torrentEntry);
|
lt::bencode(Utils::IO::FileDeviceOutputIterator {torrentFile}, torrentEntry);
|
||||||
if (torrentFile.error() != QFileDevice::NoError)
|
if (torrentFile.error() != QFileDevice::NoError)
|
||||||
throw RuntimeError {torrentFile.errorString()};
|
throw RuntimeError(torrentFile.errorString());
|
||||||
|
}
|
||||||
|
catch (const lt::system_error &err)
|
||||||
|
{
|
||||||
|
throw RuntimeError(QString::fromLocal8Bit(err.what()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TorrentInfo::isValid() const
|
bool TorrentInfo::isValid() const
|
||||||
|
@ -475,7 +475,8 @@ void AddNewTorrentDialog::saveTorrentFile()
|
|||||||
}
|
}
|
||||||
catch (const RuntimeError &err)
|
catch (const RuntimeError &err)
|
||||||
{
|
{
|
||||||
QMessageBox::critical(this, tr("I/O Error"), err.message());
|
QMessageBox::critical(this, tr("I/O Error")
|
||||||
|
, tr("Couldn't export torrent metadata file '%1'. Reason: %2.").arg(path, err.message()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user