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)
|
||||
{
|
||||
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
|
||||
{
|
||||
const auto torrentCreator = lt::create_torrent(*torrentInfo);
|
||||
const lt::entry metadata = torrentCreator.generate();
|
||||
writeEntryToFile(torrentFilepath, metadata);
|
||||
}
|
||||
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);
|
||||
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);
|
||||
@ -371,7 +377,7 @@ void BitTorrent::BencodeResumeDataStorage::Worker::store(const TorrentID &id, co
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
if (torrentInfo)
|
||||
{
|
||||
const lt::create_torrent torrentCreator = lt::create_torrent(*torrentInfo);
|
||||
const lt::entry metadata = torrentCreator.generate();
|
||||
lt::bencode(std::back_inserter(bencodedMetadata), metadata);
|
||||
try
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
@ -2321,7 +2321,7 @@ void Session::exportTorrentFile(const Torrent *torrent, TorrentExportFolder fold
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +98,12 @@ void TorrentCreatorThread::sendProgressSignal(int currentPieceIdx, int totalPiec
|
||||
emit updateProgress(static_cast<int>((currentPieceIdx * 100.) / totalPieces));
|
||||
}
|
||||
|
||||
void TorrentCreatorThread::checkInterruptionRequested() const
|
||||
{
|
||||
if (isInterruptionRequested())
|
||||
throw RuntimeError(tr("Operation aborted"));
|
||||
}
|
||||
|
||||
void TorrentCreatorThread::run()
|
||||
{
|
||||
emit updateProgress(0);
|
||||
@ -118,7 +124,7 @@ void TorrentCreatorThread::run()
|
||||
// need to sort the file names by natural sort order
|
||||
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())
|
||||
{
|
||||
dirIter.next();
|
||||
@ -151,7 +157,7 @@ void TorrentCreatorThread::run()
|
||||
fs.add_file(fileName.toStdString(), fileSizeMap[fileName]);
|
||||
}
|
||||
|
||||
if (isInterruptionRequested()) return;
|
||||
checkInterruptionRequested();
|
||||
|
||||
#if (LIBTORRENT_VERSION_NUM >= 20000)
|
||||
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()
|
||||
, [this, &newTorrent](const lt::piece_index_t n)
|
||||
{
|
||||
if (isInterruptionRequested())
|
||||
throw RuntimeError {tr("Create new torrent aborted.")};
|
||||
|
||||
checkInterruptionRequested();
|
||||
sendProgressSignal(static_cast<LTUnderlyingType<lt::piece_index_t>>(n), newTorrent.num_pieces());
|
||||
});
|
||||
|
||||
@ -194,7 +198,7 @@ void TorrentCreatorThread::run()
|
||||
// Is private ?
|
||||
newTorrent.set_priv(m_params.isPrivate);
|
||||
|
||||
if (isInterruptionRequested()) return;
|
||||
checkInterruptionRequested();
|
||||
|
||||
lt::entry entry = newTorrent.generate();
|
||||
|
||||
@ -202,32 +206,30 @@ void TorrentCreatorThread::run()
|
||||
if (!m_params.source.isEmpty())
|
||||
entry["info"]["source"] = m_params.source.toStdString();
|
||||
|
||||
if (isInterruptionRequested()) return;
|
||||
checkInterruptionRequested();
|
||||
|
||||
// create the torrent
|
||||
QFile outfile {m_params.savePath};
|
||||
if (!outfile.open(QIODevice::WriteOnly))
|
||||
{
|
||||
throw RuntimeError {tr("Create new torrent file failed. Reason: %1")
|
||||
.arg(outfile.errorString())};
|
||||
}
|
||||
throw RuntimeError(outfile.errorString());
|
||||
|
||||
if (isInterruptionRequested()) return;
|
||||
checkInterruptionRequested();
|
||||
|
||||
lt::bencode(Utils::IO::FileDeviceOutputIterator {outfile}, entry);
|
||||
if (outfile.error() != QFileDevice::NoError)
|
||||
{
|
||||
throw RuntimeError {tr("Create new torrent file failed. Reason: %1")
|
||||
.arg(outfile.errorString())};
|
||||
}
|
||||
throw RuntimeError(outfile.errorString());
|
||||
outfile.close();
|
||||
|
||||
emit updateProgress(100);
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(TorrentCreatorThread)
|
||||
|
||||
public:
|
||||
TorrentCreatorThread(QObject *parent = nullptr);
|
||||
~TorrentCreatorThread();
|
||||
explicit TorrentCreatorThread(QObject *parent = nullptr);
|
||||
~TorrentCreatorThread() override;
|
||||
|
||||
void create(const TorrentCreatorParams ¶ms);
|
||||
|
||||
@ -79,16 +80,15 @@ namespace BitTorrent
|
||||
, const int pieceSize, const bool isAlignmentOptimized, int paddedFileSizeLimit);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void run() override;
|
||||
|
||||
signals:
|
||||
void creationFailure(const QString &msg);
|
||||
void creationSuccess(const QString &path, const QString &branchPath);
|
||||
void updateProgress(int progress);
|
||||
|
||||
private:
|
||||
void run() override;
|
||||
void sendProgressSignal(int currentPieceIdx, int totalPieces);
|
||||
void checkInterruptionRequested() const;
|
||||
|
||||
TorrentCreatorParams m_params;
|
||||
};
|
||||
|
@ -167,18 +167,25 @@ TorrentInfo TorrentInfo::loadFromFile(const QString &path, QString *error) noexc
|
||||
void TorrentInfo::saveToFile(const QString &path) const
|
||||
{
|
||||
if (!isValid())
|
||||
throw RuntimeError {tr("Invalid metadata.")};
|
||||
throw RuntimeError {tr("Invalid metadata")};
|
||||
|
||||
const lt::create_torrent torrentCreator = lt::create_torrent(*(nativeInfo()));
|
||||
const lt::entry torrentEntry = torrentCreator.generate();
|
||||
try
|
||||
{
|
||||
const auto torrentCreator = lt::create_torrent(*nativeInfo());
|
||||
const lt::entry torrentEntry = torrentCreator.generate();
|
||||
|
||||
QFile torrentFile {path};
|
||||
if (!torrentFile.open(QIODevice::WriteOnly))
|
||||
throw RuntimeError {torrentFile.errorString()};
|
||||
QFile torrentFile {path};
|
||||
if (!torrentFile.open(QIODevice::WriteOnly))
|
||||
throw RuntimeError(torrentFile.errorString());
|
||||
|
||||
lt::bencode(Utils::IO::FileDeviceOutputIterator {torrentFile}, torrentEntry);
|
||||
if (torrentFile.error() != QFileDevice::NoError)
|
||||
throw RuntimeError {torrentFile.errorString()};
|
||||
lt::bencode(Utils::IO::FileDeviceOutputIterator {torrentFile}, torrentEntry);
|
||||
if (torrentFile.error() != QFileDevice::NoError)
|
||||
throw RuntimeError(torrentFile.errorString());
|
||||
}
|
||||
catch (const lt::system_error &err)
|
||||
{
|
||||
throw RuntimeError(QString::fromLocal8Bit(err.what()));
|
||||
}
|
||||
}
|
||||
|
||||
bool TorrentInfo::isValid() const
|
||||
|
@ -475,7 +475,8 @@ void AddNewTorrentDialog::saveTorrentFile()
|
||||
}
|
||||
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