From fd2294bdc8759b753ad4eff7d233a4b0e2b0ab63 Mon Sep 17 00:00:00 2001 From: Gwyn Ciesla Date: Feb 23 2023 16:19:31 +0000 Subject: 4.0.1 --- diff --git a/.gitignore b/.gitignore index 75a6f39..0327bd0 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ transmission-2.04.tar.xz /transmission-2.94.tar.xz /transmission-3.00.tar.xz /transmission-4.0.0.tar.xz +/transmission-4.0.1.tar.xz diff --git a/4890.patch b/4890.patch deleted file mode 100644 index 2941f42..0000000 --- a/4890.patch +++ /dev/null @@ -1,363 +0,0 @@ -From ba97fb792c248320edd6353593feaff91b1155ef Mon Sep 17 00:00:00 2001 -From: Charles Kerr -Date: Tue, 14 Feb 2023 10:30:54 -0600 -Subject: [PATCH 1/3] fix: processing of block fragments that arrive - out-of-order from request - -Fixes 4.0.0 regression on torrents whose pieces did not align on block boundaries. ---- - libtransmission/cache.cc | 2 +- - libtransmission/cache.h | 2 +- - libtransmission/peer-msgs.cc | 96 ++++++++++++++++++------------------ - libtransmission/torrent.cc | 11 ++++- - libtransmission/webseed.cc | 2 +- - 5 files changed, 60 insertions(+), 53 deletions(-) - -diff --git a/libtransmission/cache.cc b/libtransmission/cache.cc -index ef446b244c..f7ae03dcc1 100644 ---- a/libtransmission/cache.cc -+++ b/libtransmission/cache.cc -@@ -140,7 +140,7 @@ Cache::Cache(tr_torrents& torrents, int64_t max_bytes) - - // --- - --int Cache::writeBlock(tr_torrent_id_t tor_id, tr_block_index_t block, std::unique_ptr>& writeme) -+int Cache::writeBlock(tr_torrent_id_t tor_id, tr_block_index_t block, std::unique_ptr> writeme) - { - auto const key = Key{ tor_id, block }; - auto iter = std::lower_bound(std::begin(blocks_), std::end(blocks_), key, CompareCacheBlockByKey{}); -diff --git a/libtransmission/cache.h b/libtransmission/cache.h -index e25deb2328..9d6455610b 100644 ---- a/libtransmission/cache.h -+++ b/libtransmission/cache.h -@@ -36,7 +36,7 @@ class Cache - } - - // @return any error code from cacheTrim() -- int writeBlock(tr_torrent_id_t tor, tr_block_index_t block, std::unique_ptr>& writeme); -+ int writeBlock(tr_torrent_id_t tor, tr_block_index_t block, std::unique_ptr> writeme); - - int readBlock(tr_torrent* torrent, tr_block_info::Location loc, uint32_t len, uint8_t* setme); - int prefetchBlock(tr_torrent* torrent, tr_block_info::Location loc, uint32_t len); -diff --git a/libtransmission/peer-msgs.cc b/libtransmission/peer-msgs.cc -index 837dbb4b76..05864fea20 100644 ---- a/libtransmission/peer-msgs.cc -+++ b/libtransmission/peer-msgs.cc -@@ -188,7 +188,20 @@ struct tr_incoming - uint8_t id = 0; // the protocol message, e.g. BtPeerMsgs::Piece - uint32_t length = 0; // the full message payload length. Includes the +1 for id length - std::optional block_req; // metadata for incoming blocks -- std::map>> block_buf; // piece data for incoming blocks -+ -+ struct incoming_piece_data -+ { -+ explicit incoming_piece_data(uint32_t block_size) -+ : buf{ std::make_unique>(block_size) } -+ { -+ } -+ -+ uint32_t n_bytes_received = 0; -+ -+ std::unique_ptr> buf; -+ }; -+ -+ std::map blocks; - }; - - class tr_peerMsgsImpl; -@@ -1397,7 +1410,7 @@ bool messageLengthIsCorrect(tr_peerMsgsImpl const* msg, uint8_t id, uint32_t len - } - } - --int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr>& block_data, tr_block_index_t block); -+int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr> block_data, tr_block_index_t block); - - ReadState readBtPiece(tr_peerMsgsImpl* msgs, size_t inlen, size_t* setme_piece_bytes_read) - { -@@ -1406,7 +1419,8 @@ ReadState readBtPiece(tr_peerMsgsImpl* msgs, size_t inlen, size_t* setme_piece_b - logtrace(msgs, "In readBtPiece"); - - // If this is the first we've seen of the piece data, parse out the header -- if (!msgs->incoming.block_req) -+ auto& incoming = msgs->incoming; -+ if (!incoming.block_req) - { - if (inlen < 8) - { -@@ -1416,67 +1430,55 @@ ReadState readBtPiece(tr_peerMsgsImpl* msgs, size_t inlen, size_t* setme_piece_b - auto req = peer_request{}; - msgs->io->read_uint32(&req.index); - msgs->io->read_uint32(&req.offset); -- req.length = msgs->incoming.length - 9; -+ req.length = incoming.length - 9; - logtrace(msgs, fmt::format(FMT_STRING("got incoming block header {:d}:{:d}->{:d}"), req.index, req.offset, req.length)); -- msgs->incoming.block_req = req; -+ incoming.block_req = req; - return READ_NOW; - } - -- auto& req = msgs->incoming.block_req; -+ auto& req = incoming.block_req; - auto const loc = msgs->torrent->pieceLoc(req->index, req->offset); - auto const block = loc.block; - auto const block_size = msgs->torrent->blockSize(block); -- auto& block_buf = msgs->incoming.block_buf[block]; -- if (!block_buf) -- { -- block_buf = std::make_unique>(); -- block_buf->reserve(block_size); -- } - -- // read in another chunk of data -- auto const n_left_in_block = block_size - std::size(*block_buf); -- auto const n_left_in_req = size_t{ req->length }; -- auto const n_to_read = std::min({ n_left_in_block, n_left_in_req, inlen }); -- auto const old_length = std::size(*block_buf); -- block_buf->resize(old_length + n_to_read); -- msgs->io->read_bytes(&((*block_buf)[old_length]), n_to_read); -+ auto const n_this_pass = std::min(size_t{ req->length }, inlen); -+ TR_ASSERT(loc.block_offset + n_this_pass <= block_size); - -- msgs->publish(tr_peer_event::GotPieceData(n_to_read)); -- *setme_piece_bytes_read += n_to_read; -- logtrace( -- msgs, -- fmt::format( -- FMT_STRING("got {:d} bytes for block {:d}:{:d}->{:d} ... {:d} remain in req, {:d} remain in block"), -- n_to_read, -- req->index, -- req->offset, -- req->length, -- req->length, -- block_size - std::size(*block_buf))); -- -- // if we didn't read enough to finish off the request, -- // update the table and wait for more -- if (n_to_read < n_left_in_req) -- { -- auto new_loc = msgs->torrent->byteLoc(loc.byte + n_to_read); -+ auto& incoming_block = incoming.blocks.try_emplace(block, block_size).first->second; -+ msgs->io->read_bytes(std::data(*incoming_block.buf) + loc.block_offset, n_this_pass); -+ -+ msgs->publish(tr_peer_event::GotPieceData(n_this_pass)); -+ *setme_piece_bytes_read += n_this_pass; -+ incoming_block.n_bytes_received += n_this_pass; -+ TR_ASSERT(incoming_block.n_bytes_received <= block_size); -+ logtrace(msgs, fmt::format("got {:d} bytes for req {:d}:{:d}->{:d}", n_this_pass, req->index, req->offset, req->length)); -+ -+ // if we haven't gotten the full response yet, -+ // update what part of `req` is unfulfilled and wait for more -+ if (n_this_pass < req->length) -+ { -+ req->length -= n_this_pass; -+ auto const new_loc = msgs->torrent->byteLoc(loc.byte + n_this_pass); - req->index = new_loc.piece; - req->offset = new_loc.piece_offset; -- req->length -= n_to_read; - return READ_LATER; - } - -- // we've fully read this message -+ // we've got the entire response message - req.reset(); - msgs->state = AwaitingBt::Length; - -- // if we didn't read enough to finish off the block, -- // update the table and wait for more -- if (std::size(*block_buf) < block_size) -+ // if we haven't gotten the entire block yet, wait for more -+ if (incoming_block.n_bytes_received < block_size) - { - return READ_LATER; - } - -- return clientGotBlock(msgs, block_buf, block) != 0 ? READ_ERR : READ_NOW; -+ // we've got the entire block, so send it along. -+ auto block_buf = std::move(incoming_block.buf); -+ incoming.blocks.erase(block); // note: invalidates `incoming_block` local -+ auto const ok = clientGotBlock(msgs, std::move(block_buf), block) == 0; -+ return ok ? READ_NOW : READ_ERR; - } - - ReadState readBtMessage(tr_peerMsgsImpl* msgs, size_t inlen) -@@ -1744,7 +1746,7 @@ ReadState readBtMessage(tr_peerMsgsImpl* msgs, size_t inlen) - } - - /* returns 0 on success, or an errno on failure */ --int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr>& block_data, tr_block_index_t const block) -+int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr> block_data, tr_block_index_t const block) - { - TR_ASSERT(msgs != nullptr); - -@@ -1760,7 +1762,6 @@ int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr>& - if (std::size(*block_data) != msgs->torrent->blockSize(block)) - { - logdbg(msgs, fmt::format("wrong block size: expected {:d}, got {:d}", n_expected, std::size(*block_data))); -- block_data->clear(); - return EMSGSIZE; - } - -@@ -1769,7 +1770,6 @@ int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr>& - if (!tr_peerMgrDidPeerRequest(msgs->torrent, msgs, block)) - { - logdbg(msgs, "we didn't ask for this message..."); -- block_data->clear(); - return 0; - } - -@@ -1777,19 +1777,17 @@ int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr>& - if (msgs->torrent->hasPiece(loc.piece)) - { - logtrace(msgs, "we did ask for this message, but the piece is already complete..."); -- block_data->clear(); - return 0; - } - - // NB: if writeBlock() fails the torrent may be paused. - // If this happens, `msgs` will be a dangling pointer and must no longer be used. -- if (auto const err = msgs->session->cache->writeBlock(tor->id(), block, block_data); err != 0) -+ if (auto const err = msgs->session->cache->writeBlock(tor->id(), block, std::move(block_data)); err != 0) - { - return err; - } - - msgs->blame.set(loc.piece); -- msgs->incoming.block_buf.erase(block); - msgs->publish(tr_peer_event::GotBlock(tor->blockInfo(), block)); - - return 0; -diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc -index 4b5a0b1dea..cd96bac2c3 100644 ---- a/libtransmission/torrent.cc -+++ b/libtransmission/torrent.cc -@@ -2400,8 +2400,17 @@ void tr_torrentGotBlock(tr_torrent* tor, tr_block_index_t block) - tor->setDirty(); - - tor->completion.addBlock(block); -- if (auto const piece = tor->blockLoc(block).piece; tor->hasPiece(piece)) -+ -+ auto const block_loc = tor->blockLoc(block); -+ auto const first_piece = block_loc.piece; -+ auto const last_piece = tor->byteLoc(block_loc.byte + tor->blockSize(block) - 1).piece; -+ for (auto piece = first_piece; piece <= last_piece; ++piece) - { -+ if (!tor->hasPiece(piece)) -+ { -+ continue; -+ } -+ - if (tor->checkPiece(piece)) - { - onPieceCompleted(tor, piece); -diff --git a/libtransmission/webseed.cc b/libtransmission/webseed.cc -index 7f07dd149e..8136139d87 100644 ---- a/libtransmission/webseed.cc -+++ b/libtransmission/webseed.cc -@@ -352,7 +352,7 @@ struct write_block_data - { - if (auto const* const tor = tr_torrentFindFromId(session_, tor_id_); tor != nullptr) - { -- session_->cache->writeBlock(tor_id_, block_, data_); -+ session_->cache->writeBlock(tor_id_, block_, std::move(data_)); - webseed_->publish(tr_peer_event::GotBlock(tor->blockInfo(), block_)); - } - - -From 8a3418aae23e37d446a86b11a34679db0bfa99f7 Mon Sep 17 00:00:00 2001 -From: Charles Kerr -Date: Tue, 14 Feb 2023 10:59:16 -0600 -Subject: [PATCH 2/3] fixup! fix: processing of block fragments that arrive - out-of-order from request - -refactor: be more paranoid about duplicate requests at endgame. ---- - libtransmission/peer-msgs.cc | 16 ++++++++++------ - 1 file changed, 10 insertions(+), 6 deletions(-) - -diff --git a/libtransmission/peer-msgs.cc b/libtransmission/peer-msgs.cc -index 05864fea20..24e3359d65 100644 ---- a/libtransmission/peer-msgs.cc -+++ b/libtransmission/peer-msgs.cc -@@ -22,6 +22,7 @@ - - #include "transmission.h" - -+#include "bitfield.h" - #include "cache.h" - #include "completion.h" - #include "crypto-utils.h" -@@ -193,12 +194,12 @@ struct tr_incoming - { - explicit incoming_piece_data(uint32_t block_size) - : buf{ std::make_unique>(block_size) } -+ , have{ block_size } - { - } - -- uint32_t n_bytes_received = 0; -- - std::unique_ptr> buf; -+ tr_bitfield have; - }; - - std::map blocks; -@@ -1443,19 +1444,22 @@ ReadState readBtPiece(tr_peerMsgsImpl* msgs, size_t inlen, size_t* setme_piece_b - - auto const n_this_pass = std::min(size_t{ req->length }, inlen); - TR_ASSERT(loc.block_offset + n_this_pass <= block_size); -+ if (n_this_pass == 0) -+ { -+ return READ_LATER; -+ } - - auto& incoming_block = incoming.blocks.try_emplace(block, block_size).first->second; - msgs->io->read_bytes(std::data(*incoming_block.buf) + loc.block_offset, n_this_pass); - - msgs->publish(tr_peer_event::GotPieceData(n_this_pass)); - *setme_piece_bytes_read += n_this_pass; -- incoming_block.n_bytes_received += n_this_pass; -- TR_ASSERT(incoming_block.n_bytes_received <= block_size); -+ incoming_block.have.setSpan(loc.block_offset, loc.block_offset + n_this_pass); - logtrace(msgs, fmt::format("got {:d} bytes for req {:d}:{:d}->{:d}", n_this_pass, req->index, req->offset, req->length)); - - // if we haven't gotten the full response yet, - // update what part of `req` is unfulfilled and wait for more -- if (n_this_pass < req->length) -+ if (req->length > n_this_pass) - { - req->length -= n_this_pass; - auto const new_loc = msgs->torrent->byteLoc(loc.byte + n_this_pass); -@@ -1469,7 +1473,7 @@ ReadState readBtPiece(tr_peerMsgsImpl* msgs, size_t inlen, size_t* setme_piece_b - msgs->state = AwaitingBt::Length; - - // if we haven't gotten the entire block yet, wait for more -- if (incoming_block.n_bytes_received < block_size) -+ if (!incoming_block.have.hasAll()) - { - return READ_LATER; - } - -From d75445758c3e7dc666aba781111275d62acbf3b8 Mon Sep 17 00:00:00 2001 -From: Charles Kerr -Date: Tue, 14 Feb 2023 11:57:35 -0600 -Subject: [PATCH 3/3] fixup! fix: processing of block fragments that arrive - out-of-order from request - -chore: sync tests ---- - tests/libtransmission/move-test.cc | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tests/libtransmission/move-test.cc b/tests/libtransmission/move-test.cc -index cc5dc05ce6..e06d1daefd 100644 ---- a/tests/libtransmission/move-test.cc -+++ b/tests/libtransmission/move-test.cc -@@ -84,7 +84,7 @@ TEST_P(IncompleteDirTest, incompleteDir) - - auto const test_incomplete_dir_threadfunc = [](TestIncompleteDirData* data) noexcept - { -- data->session->cache->writeBlock(data->tor->id(), data->block, data->buf); -+ data->session->cache->writeBlock(data->tor->id(), data->block, std::move(data->buf)); - tr_torrentGotBlock(data->tor, data->block); - data->done = true; - }; diff --git a/f551b4adbff0d59557d61867d0b6518c50f5a73f.patch b/f551b4adbff0d59557d61867d0b6518c50f5a73f.patch deleted file mode 100644 index fcc68e2..0000000 --- a/f551b4adbff0d59557d61867d0b6518c50f5a73f.patch +++ /dev/null @@ -1,500 +0,0 @@ -From f551b4adbff0d59557d61867d0b6518c50f5a73f Mon Sep 17 00:00:00 2001 -From: Charles Kerr -Date: Mon, 13 Feb 2023 12:33:33 -0600 -Subject: [PATCH] fix: magnet links are always paused when added (#4856) - ---- - libtransmission/peer-mgr.cc | 8 +- - libtransmission/resume.cc | 6 +- - libtransmission/torrent-magnet.cc | 34 +++---- - libtransmission/torrent-magnet.h | 2 + - libtransmission/torrent.cc | 148 ++++++++++++++---------------- - libtransmission/torrent.h | 9 +- - libtransmission/transmission.h | 2 +- - macosx/Torrent.mm | 2 +- - 8 files changed, 101 insertions(+), 110 deletions(-) - -diff --git a/libtransmission/peer-mgr.cc b/libtransmission/peer-mgr.cc -index 4cf1d332c8..8e826dc3fa 100644 ---- a/libtransmission/peer-mgr.cc -+++ b/libtransmission/peer-mgr.cc -@@ -43,6 +43,7 @@ - #include "session.h" - #include "timer.h" - #include "torrent.h" -+#include "torrent-magnet.h" - #include "tr-assert.h" - #include "tr-utp.h" - #include "utils.h" -@@ -2391,8 +2392,11 @@ void tr_peerMgr::bandwidthPulse() - session->top_bandwidth_.allocate(Msec); - - // torrent upkeep -- auto& torrents = session->torrents(); -- std::for_each(std::begin(torrents), std::end(torrents), [](auto* tor) { tor->do_idle_work(); }); -+ for (auto* const tor : session->torrents()) -+ { -+ tor->do_idle_work(); -+ tr_torrentMagnetDoIdleWork(tor); -+ } - - /* pump the queues */ - queuePulse(session, TR_UP); -diff --git a/libtransmission/resume.cc b/libtransmission/resume.cc -index 80c00dbd28..9716ae876c 100644 ---- a/libtransmission/resume.cc -+++ b/libtransmission/resume.cc -@@ -712,7 +712,7 @@ auto loadFromFile(tr_torrent* tor, tr_resume::fields_t fields_to_load, bool* did - - if (auto val = bool{}; (fields_to_load & tr_resume::Run) != 0 && tr_variantDictFindBool(&top, TR_KEY_paused, &val)) - { -- tor->isRunning = !val; -+ tor->start_when_stable = !val; - fields_loaded |= tr_resume::Run; - } - -@@ -831,7 +831,7 @@ auto setFromCtor(tr_torrent* tor, tr_resume::fields_t fields, tr_ctor const* cto - { - if (auto is_paused = bool{}; tr_ctorGetPaused(ctor, mode, &is_paused)) - { -- tor->isRunning = !is_paused; -+ tor->start_when_stable = !is_paused; - ret |= tr_resume::Run; - } - } -@@ -907,7 +907,7 @@ void save(tr_torrent* tor) - tr_variantDictAddInt(&top, TR_KEY_uploaded, tor->uploadedPrev + tor->uploadedCur); - tr_variantDictAddInt(&top, TR_KEY_max_peers, tor->peerLimit()); - tr_variantDictAddInt(&top, TR_KEY_bandwidth_priority, tor->getPriority()); -- tr_variantDictAddBool(&top, TR_KEY_paused, !tor->isRunning && !tor->isQueued()); -+ tr_variantDictAddBool(&top, TR_KEY_paused, !tor->start_when_stable); - savePeers(&top, tor); - - if (tor->hasMetainfo()) -diff --git a/libtransmission/torrent-magnet.cc b/libtransmission/torrent-magnet.cc -index 1d91cbfef1..c32defb433 100644 ---- a/libtransmission/torrent-magnet.cc -+++ b/libtransmission/torrent-magnet.cc -@@ -176,13 +176,6 @@ bool tr_torrentUseMetainfoFromFile( - delete tor->incompleteMetadata; - tor->incompleteMetadata = nullptr; - } -- tor->isStopping = true; -- tor->magnetVerify = true; -- if (tor->session->shouldPauseAddedTorrents()) -- { -- tor->startAfterVerify = false; -- } -- tor->markEdited(); - - return true; - } -@@ -310,13 +303,6 @@ void on_have_all_metainfo(tr_torrent* tor, tr_incomplete_metadata* m) - { - delete tor->incompleteMetadata; - tor->incompleteMetadata = nullptr; -- tor->isStopping = true; -- tor->magnetVerify = true; -- if (tor->session->shouldPauseAddedTorrents() && !tor->magnetStartAfterVerify) -- { -- tor->startAfterVerify = false; -- } -- tor->markEdited(); - } - else /* drat. */ - { -@@ -340,6 +326,19 @@ void on_have_all_metainfo(tr_torrent* tor, tr_incomplete_metadata* m) - } // namespace set_metadata_piece_helpers - } // namespace - -+void tr_torrentMagnetDoIdleWork(tr_torrent* const tor) -+{ -+ using namespace set_metadata_piece_helpers; -+ -+ TR_ASSERT(tr_isTorrent(tor)); -+ -+ if (auto* const m = tor->incompleteMetadata; m != nullptr && std::empty(m->pieces_needed)) -+ { -+ tr_logAddDebugTor(tor, fmt::format("we now have all the metainfo!")); -+ on_have_all_metainfo(tor, m); -+ } -+} -+ - void tr_torrentSetMetadataPiece(tr_torrent* tor, int piece, void const* data, size_t len) - { - using namespace set_metadata_piece_helpers; -@@ -384,13 +383,6 @@ void tr_torrentSetMetadataPiece(tr_torrent* tor, int piece, void const* data, si - - needed.erase(iter); - tr_logAddDebugTor(tor, fmt::format("saving metainfo piece {}... {} remain", piece, std::size(needed))); -- -- // are we done? -- if (std::empty(needed)) -- { -- tr_logAddDebugTor(tor, fmt::format("metainfo piece {} was the last one", piece)); -- on_have_all_metainfo(tor, m); -- } - } - - // --- -diff --git a/libtransmission/torrent-magnet.h b/libtransmission/torrent-magnet.h -index 8af953bec9..cb5d7e1fcb 100644 ---- a/libtransmission/torrent-magnet.h -+++ b/libtransmission/torrent-magnet.h -@@ -33,6 +33,8 @@ bool tr_torrentSetMetadataSizeHint(tr_torrent* tor, int64_t metadata_size); - - double tr_torrentGetMetadataPercent(tr_torrent const* tor); - -+void tr_torrentMagnetDoIdleWork(tr_torrent* tor); -+ - bool tr_torrentUseMetainfoFromFile( - tr_torrent* tor, - tr_torrent_metainfo const* metainfo, -diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc -index 1e74f8152b..4b5a0b1dea 100644 ---- a/libtransmission/torrent.cc -+++ b/libtransmission/torrent.cc -@@ -830,6 +830,8 @@ void torrentStart(tr_torrent* tor, torrent_start_opts opts) - { - using namespace start_stop_helpers; - -+ auto const lock = tor->unique_lock(); -+ - switch (tor->activity()) - { - case TR_STATUS_SEED: -@@ -849,7 +851,6 @@ void torrentStart(tr_torrent* tor, torrent_start_opts opts) - case TR_STATUS_CHECK_WAIT: - /* verifying right now... wait until that's done so - * we'll know what completeness to use/announce */ -- tor->startAfterVerify = true; - return; - - case TR_STATUS_STOPPED: -@@ -868,9 +869,6 @@ void torrentStart(tr_torrent* tor, torrent_start_opts opts) - return; - } - -- /* otherwise, start it now... */ -- auto const lock = tor->unique_lock(); -- - /* allow finished torrents to be resumed */ - if (tr_torrentIsSeedRatioDone(tor)) - { -@@ -895,6 +893,9 @@ void torrentStop(tr_torrent* const tor) - TR_ASSERT(tor->session->amInSessionThread()); - auto const lock = tor->unique_lock(); - -+ tor->isRunning = false; -+ tor->isStopping = false; -+ - if (!tor->session->isClosing()) - { - tr_logAddInfoTor(tor, _("Pausing torrent")); -@@ -913,16 +914,6 @@ void torrentStop(tr_torrent* const tor) - } - - torrentSetQueued(tor, false); -- -- if (tor->magnetVerify) -- { -- tor->magnetVerify = false; -- tr_logAddTraceTor(tor, "Magnet Verify"); -- tor->refreshCurrentDir(); -- tr_torrentVerify(tor); -- -- callScriptIfEnabled(tor, TR_SCRIPT_ON_TORRENT_ADDED); -- } - } - } // namespace - -@@ -935,8 +926,7 @@ void tr_torrentStop(tr_torrent* tor) - - auto const lock = tor->unique_lock(); - -- tor->isRunning = false; -- tor->isStopping = false; -+ tor->start_when_stable = false; - tor->setDirty(); - tor->session->runInSessionThread(torrentStop, tor); - } -@@ -965,7 +955,6 @@ void tr_torrentFreeInSessionThread(tr_torrent* tor) - tr_logAddInfoTor(tor, _("Removing torrent")); - } - -- tor->magnetVerify = false; - torrentStop(tor); - - if (tor->isDeleting) -@@ -975,7 +964,6 @@ void tr_torrentFreeInSessionThread(tr_torrent* tor) - tr_torrent_metainfo::removeFile(tor->session->resumeDir(), tor->name(), tor->infoHashString(), ".resume"sv); - } - -- tor->isRunning = false; - freeTorrent(tor); - } - -@@ -1036,6 +1024,34 @@ void torrentInitFromInfoDict(tr_torrent* tor) - tor->checked_pieces_ = tr_bitfield{ size_t(tor->pieceCount()) }; - } - -+void on_metainfo_completed(tr_torrent* tor) -+{ -+ // we can look for files now that we know what files are in the torrent -+ tor->refreshCurrentDir(); -+ -+ callScriptIfEnabled(tor, TR_SCRIPT_ON_TORRENT_ADDED); -+ -+ if (tor->session->shouldFullyVerifyAddedTorrents() || !isNewTorrentASeed(tor)) -+ { -+ tr_torrentVerify(tor); -+ } -+ else -+ { -+ tor->completion.setHasAll(); -+ tor->doneDate = tor->addedDate; -+ tor->recheckCompleteness(); -+ -+ if (tor->start_when_stable) -+ { -+ torrentStart(tor, {}); -+ } -+ else if (tor->isRunning) -+ { -+ tr_torrentStop(tor); -+ } -+ } -+} -+ - void torrentInit(tr_torrent* tor, tr_ctor const* ctor) - { - tr_session* session = tr_ctorGetSession(ctor); -@@ -1081,7 +1097,7 @@ void torrentInit(tr_torrent* tor, tr_ctor const* ctor) - tor->anyDate = now; - - tr_resume::fields_t loaded = {}; -- if (tor->hasMetainfo()) -+ - { - // tr_resume::load() calls a lot of tr_torrentSetFoo() methods - // that set things as dirty, but... these settings being loaded are -@@ -1106,9 +1122,6 @@ void torrentInit(tr_torrent* tor, tr_ctor const* ctor) - - tor->refreshCurrentDir(); - -- bool const do_start = tor->isRunning; -- tor->isRunning = false; -- - if ((loaded & tr_resume::Speedlimit) == 0) - { - tor->useSpeedLimit(TR_UP, false); -@@ -1174,37 +1187,14 @@ void torrentInit(tr_torrent* tor, tr_ctor const* ctor) - - tor->torrent_announcer = session->announcer_->addTorrent(tor, &tr_torrent::onTrackerResponse); - -- if (is_new_torrent) -+ if (auto const has_metainfo = tor->hasMetainfo(); is_new_torrent && has_metainfo) - { -- if (tor->hasMetainfo()) -- { -- callScriptIfEnabled(tor, TR_SCRIPT_ON_TORRENT_ADDED); -- } -- -- if (!tor->hasMetainfo() && !do_start) -- { -- auto opts = torrent_start_opts{}; -- opts.bypass_queue = true; -- opts.has_local_data = has_local_data; -- torrentStart(tor, opts); -- } -- else if (!session->shouldFullyVerifyAddedTorrents() && isNewTorrentASeed(tor)) -- { -- tor->completion.setHasAll(); -- tor->doneDate = tor->addedDate; -- tor->recheckCompleteness(); -- } -- else -- { -- tor->startAfterVerify = do_start; -- tr_torrentVerify(tor); -- } -+ on_metainfo_completed(tor); - } -- else if (do_start) -+ else if (tor->start_when_stable || !has_metainfo) - { -- // if checked_pieces_ got populated from the loading the resume -- // file above, then torrentStart doesn't need to check again - auto opts = torrent_start_opts{}; -+ opts.bypass_queue = !has_metainfo; // to fetch metainfo from peers - opts.has_local_data = has_local_data; - torrentStart(tor, opts); - } -@@ -1216,16 +1206,20 @@ void torrentInit(tr_torrent* tor, tr_ctor const* ctor) - } // namespace torrent_init_helpers - } // namespace - --void tr_torrent::setMetainfo(tr_torrent_metainfo const& tm) -+void tr_torrent::setMetainfo(tr_torrent_metainfo tm) - { - using namespace torrent_init_helpers; - -- metainfo_ = tm; -+ TR_ASSERT(!hasMetainfo()); -+ metainfo_ = std::move(tm); - - torrentInitFromInfoDict(this); - tr_peerMgrOnTorrentGotMetainfo(this); - session->onMetadataCompleted(this); - this->setDirty(); -+ this->markEdited(); -+ -+ on_metainfo_completed(this); - } - - tr_torrent* tr_torrentNew(tr_ctor* ctor, tr_torrent** setme_duplicate_of) -@@ -1763,33 +1757,35 @@ void tr_torrentAmountFinished(tr_torrent const* tor, float* tabs, int n_tabs) - - // --- Start/Stop Callback - --void tr_torrentStart(tr_torrent* tor) -+namespace -+{ -+void tr_torrentStartImpl(tr_torrent* tor, bool bypass_queue) - { -- if (tr_isTorrent(tor)) -+ if (!tr_isTorrent(tor)) - { -- tor->startAfterVerify = true; -- torrentStart(tor, {}); -+ return; - } -+ -+ tor->start_when_stable = true; -+ auto opts = torrent_start_opts{}; -+ opts.bypass_queue = bypass_queue; -+ torrentStart(tor, opts); -+} -+} // namespace -+ -+void tr_torrentStart(tr_torrent* tor) -+{ -+ tr_torrentStartImpl(tor, false); - } - - void tr_torrentStartNow(tr_torrent* tor) - { -- if (tr_isTorrent(tor)) -- { -- auto opts = torrent_start_opts{}; -- opts.bypass_queue = true; -- torrentStart(tor, opts); -- } -+ tr_torrentStartImpl(tor, true); - } - - void tr_torrentStartMagnet(tr_torrent* tor) - { -- if (tr_isTorrent(tor)) -- { -- tor->magnetStartAfterVerify = true; -- tor->startAfterVerify = true; -- torrentStart(tor, {}); -- } -+ tr_torrentStart(tor); - } - - // --- -@@ -1809,10 +1805,8 @@ void onVerifyDoneThreadFunc(tr_torrent* const tor) - - tor->recheckCompleteness(); - -- if (tor->startAfterVerify) -+ if (tor->start_when_stable) - { -- tor->startAfterVerify = false; -- - auto opts = torrent_start_opts{}; - opts.has_local_data = !tor->checked_pieces_.hasNone(); - torrentStart(tor, opts); -@@ -1832,20 +1826,18 @@ void verifyTorrent(tr_torrent* const tor) - /* if the torrent's already being verified, stop it */ - tor->session->verifyRemove(tor); - -- bool const start_after = (tor->isRunning || tor->startAfterVerify) && !tor->isStopping; -- -- if (tor->isRunning) -+ if (!tor->hasMetainfo()) - { -- tr_torrentStop(tor); -+ return; - } - -- if (setLocalErrorIfFilesDisappeared(tor)) -+ if (tor->isRunning) - { -- tor->startAfterVerify = false; -+ torrentStop(tor); - } -- else -+ -+ if (!setLocalErrorIfFilesDisappeared(tor)) - { -- tor->startAfterVerify = start_after; - tor->session->verifyAdd(tor); - } - } -diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h -index deebb77337..a1a3031aa8 100644 ---- a/libtransmission/torrent.h -+++ b/libtransmission/torrent.h -@@ -109,7 +109,8 @@ struct tr_torrent final : public tr_completion::torrent_view - // but more refactoring is needed before that can happen - // because much of tr_torrent's impl is in the non-member C bindings - -- void setMetainfo(tr_torrent_metainfo const& tm); -+ // Used to add metainfo to a magnet torrent. -+ void setMetainfo(tr_torrent_metainfo tm); - - [[nodiscard]] auto unique_lock() const - { -@@ -903,10 +904,10 @@ struct tr_torrent final : public tr_completion::torrent_view - bool is_queued = false; - bool isRunning = false; - bool isStopping = false; -- bool startAfterVerify = false; -- bool magnetStartAfterVerify = false; - -- bool magnetVerify = false; -+ // start the torrent after all the startup scaffolding is done, -+ // e.g. fetching metadata from peers and/or verifying the torrent -+ bool start_when_stable = false; - - private: - [[nodiscard]] constexpr bool isPieceTransferAllowed(tr_direction direction) const noexcept -diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h -index 11bb8743dd..82bf1d5e54 100644 ---- a/libtransmission/transmission.h -+++ b/libtransmission/transmission.h -@@ -601,7 +601,7 @@ void tr_sessionSetAntiBruteForceEnabled(tr_session* session, bool enabled); - /** @brief Like `tr_torrentStart()`, but resumes right away regardless of the queues. */ - void tr_torrentStartNow(tr_torrent* tor); - --/** @brief Like tr_torrentStart(), but sets magnetStartAfterVerify to true. */ -+/** @brief DEPRECATED. Equivalent to tr_torrentStart(). Use that instead. */ - void tr_torrentStartMagnet(tr_torrent*); - - /** @brief Return the queued torrent's position in the queue it's in. [0...n) */ -diff --git a/macosx/Torrent.mm b/macosx/Torrent.mm -index bd5ad7972f..98e69882d3 100644 ---- a/macosx/Torrent.mm -+++ b/macosx/Torrent.mm -@@ -280,7 +280,7 @@ - (void)startMagnetTransferAfterMetaDownload - { - if ([self alertForRemainingDiskSpace]) - { -- tr_torrentStartMagnet(self.fHandle); -+ tr_torrentStart(self.fHandle); - [self update]; - - //capture, specifically, stop-seeding settings changing to unlimited diff --git a/sources b/sources index 83b59f4..8053cb5 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (transmission-4.0.0.tar.xz) = 79945af73fe7226dddadba7cc039516f2f878e05a9cf6c6d799b636b8298e2b2fa25c4426789bd41ef4d2b00d75a3c1c115c1676b4d2a9f09a1526456dceb3f8 +SHA512 (transmission-4.0.1.tar.xz) = a0226c96b08fd7be7cb9763132e36e59a4f84d67277c345860ac5a2e685ec0d5f2e8b3fe1e2d090e1180499518084de99387b822bb6dbdc1b7cb076d9a99ce05 diff --git a/transmission.spec b/transmission.spec index 4f3e0f4..4238fff 100644 --- a/transmission.spec +++ b/transmission.spec @@ -1,8 +1,8 @@ %global _hardened_build 1 Name: transmission -Version: 4.0.0 -Release: 3%{?dist} +Version: 4.0.1 +Release: 1%{?dist} Summary: A lightweight GTK+ BitTorrent client # See COPYING. This licensing situation is... special. License: MIT and GPLv2 @@ -11,11 +11,9 @@ URL: http://www.transmissionbt.com Source0: https://github.com/transmission/transmission/releases/download/%{version}/transmission-%{version}.tar.xz # https://bugzilla.redhat.com/show_bug.cgi?id=1221292 Source1: https://raw.githubusercontent.com/gnome-design-team/gnome-icons/master/apps-symbolic/Adwaita/scalable/apps/transmission-symbolic.svg -Patch0: f551b4adbff0d59557d61867d0b6518c50f5a73f.patch -Patch1: 4890.patch # Fix the DBus name to match the app name for flatpak builds # https://github.com/transmission/transmission/pull/847 -Patch2: 0001-gtk-use-com.transmissionbt.Transmission.-D-Bus-names.patch +Patch0: 0001-gtk-use-com.transmissionbt.Transmission.-D-Bus-names.patch BuildRequires: make @@ -182,6 +180,9 @@ desktop-file-install \ %doc %{_mandir}/man1/transmission-qt.* %changelog +* Thu Feb 23 2023 Gwyn Ciesla - 4.0.1-1 +- 4.0.1 + * Wed Feb 15 2023 Kalev Lember - 4.0.0-3 - Avoid hardcoding /usr prefix - Restore flatpak DBus name patch