From 2c2011d40f36e4fbc1ed487b7a5ebd42097bb9a1 Mon Sep 17 00:00:00 2001 From: Yat Ho Date: Sun, 2 Jun 2024 08:44:01 +0800 Subject: [PATCH] fix: update partial file suffix after verifying torrent (#6871) * fix: only update piece completion if different * fix: remove return statement from void function * refactor: add `tr_torrent::has_file()` * fix: update file suffixes after verifying torrent * fix: tests --- libtransmission/torrent.cc | 64 ++++++++++++++++++---------- libtransmission/torrent.h | 9 +++- tests/libtransmission/move-test.cc | 1 + tests/libtransmission/rename-test.cc | 2 + 4 files changed, 52 insertions(+), 24 deletions(-) diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index b2906e795..5b7cb0ff9 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -1608,6 +1608,39 @@ std::optional tr_torrent::VerifyMediator::find_file(tr_file_index_t return {}; } +void tr_torrent::update_file_path(tr_file_index_t file, std::optional has_file) const +{ + auto const found = find_file(file); + if (!found) + { + return; + } + + auto const has = has_file ? *has_file : this->has_file(file); + auto const needs_suffix = session->isIncompleteFileNamingEnabled() && !has; + auto const oldpath = found->filename(); + auto const newpath = needs_suffix ? + tr_pathbuf{ found->base(), '/', file_subpath(file), tr_torrent_files::PartialFileSuffix } : + tr_pathbuf{ found->base(), '/', file_subpath(file) }; + + if (tr_sys_path_is_same(oldpath, newpath)) + { + return; + } + + if (auto error = tr_error{}; !tr_sys_path_rename(oldpath, newpath, &error)) + { + tr_logAddErrorTor( + this, + fmt::format( + _("Couldn't move '{old_path}' to '{path}': {error} ({error_code})"), + fmt::arg("old_path", oldpath), + fmt::arg("path", newpath), + fmt::arg("error", error.message()), + fmt::arg("error_code", error.code()))); + } +} + void tr_torrent::VerifyMediator::on_verify_queued() { tr_logAddTraceTor(tor_, "Queued for verification"); @@ -1625,7 +1658,7 @@ void tr_torrent::VerifyMediator::on_piece_checked(tr_piece_index_t const piece, { auto const had_piece = tor_->has_piece(piece); - if (has_piece || had_piece) + if (has_piece != had_piece) { tor_->set_has_piece(piece, has_piece); tor_->set_dirty(); @@ -1664,6 +1697,11 @@ void tr_torrent::VerifyMediator::on_verify_done(bool const aborted) return; } + for (tr_file_index_t file = 0, n_files = tor->file_count(); file < n_files; ++file) + { + tor->update_file_path(file, {}); + } + tor->recheck_completeness(); if (tor->verify_done_callback_) @@ -2132,27 +2170,7 @@ void tr_torrent::on_file_completed(tr_file_index_t const file) /* if the torrent's current filename isn't the same as the one in the * metadata -- for example, if it had the ".part" suffix appended to * it until now -- then rename it to match the one in the metadata */ - if (auto found = find_file(file); found) - { - if (auto const& file_subpath = this->file_subpath(file); file_subpath != found->subpath()) - { - auto const& oldpath = found->filename(); - auto const newpath = tr_pathbuf{ found->base(), '/', file_subpath }; - auto error = tr_error{}; - - if (!tr_sys_path_rename(oldpath, newpath, &error)) - { - tr_logAddErrorTor( - this, - fmt::format( - _("Couldn't move '{old_path}' to '{path}': {error} ({error_code})"), - fmt::arg("old_path", oldpath), - fmt::arg("path", newpath), - fmt::arg("error", error.message()), - fmt::arg("error_code", error.code()))); - } - } - } + update_file_path(file, true); } void tr_torrent::on_piece_completed(tr_piece_index_t const piece) @@ -2165,7 +2183,7 @@ void tr_torrent::on_piece_completed(tr_piece_index_t const piece) // if this piece completes any file, invoke the fileCompleted func for it for (auto [file, file_end] = fpm_.file_span_for_piece(piece); file < file_end; ++file) { - if (completion_.has_blocks(block_span_for_file(file))) + if (has_file(file)) { on_file_completed(file); } diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index f269e1f6a..280ddcfce 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -325,6 +325,11 @@ struct tr_torrent return completion_.has_none(); } + [[nodiscard]] auto has_file(tr_file_index_t file) const + { + return completion_.has_blocks(block_span_for_file(file)); + } + [[nodiscard]] auto has_piece(tr_piece_index_t piece) const { return completion_.has_piece(piece); @@ -372,7 +377,7 @@ struct tr_torrent void amount_done_bins(float* tab, int n_tabs) const { - return completion_.amount_done(tab, n_tabs); + completion_.amount_done(tab, n_tabs); } /// FILE <-> PIECE @@ -1249,6 +1254,8 @@ private: void do_magnet_idle_work(); [[nodiscard]] bool use_new_metainfo(tr_error* error); + void update_file_path(tr_file_index_t file, std::optional has_file) const; + void set_location_in_session_thread(std::string_view path, bool move_from_old_path, int volatile* setme_state); void rename_path_in_session_thread( diff --git a/tests/libtransmission/move-test.cc b/tests/libtransmission/move-test.cc index 3a34f7eb2..96839d632 100644 --- a/tests/libtransmission/move-test.cc +++ b/tests/libtransmission/move-test.cc @@ -56,6 +56,7 @@ TEST_P(IncompleteDirTest, incompleteDir) // init an incomplete torrent. // the test zero_torrent will be missing its first piece. + tr_sessionSetIncompleteFileNamingEnabled(session_, true); auto* const tor = zeroTorrentInit(ZeroTorrentState::Partial); auto path = tr_pathbuf{}; diff --git a/tests/libtransmission/rename-test.cc b/tests/libtransmission/rename-test.cc index 3d118dee5..7756c4598 100644 --- a/tests/libtransmission/rename-test.cc +++ b/tests/libtransmission/rename-test.cc @@ -449,6 +449,8 @@ TEST_F(RenameTest, partialFile) **** create our test torrent with an incomplete .part file ***/ + tr_sessionSetIncompleteFileNamingEnabled(session_, true); + auto* tor = zeroTorrentInit(ZeroTorrentState::Partial); EXPECT_EQ(TotalSize, tor->total_size()); EXPECT_EQ(PieceSize, tor->piece_size());