fix corruption: torrentVerify on completion (#4178)

* torrentVerify on completion

* Make torrent verify on completion configurable via settings

* code review: replacing tr_verify_complete_mode with bool

* code review: sorting torrent_complete_verify_enabled with bool

* Update Application.cc

* code review: avoiding `session->onTorrentCompletenessChanged` before verification completion
This commit is contained in:
Cœur
2025-11-10 21:16:15 +01:00
committed by GitHub
parent d0e6b5519d
commit 78238ec3de
10 changed files with 60 additions and 5 deletions

View File

@@ -386,6 +386,7 @@ auto constexpr MyStatic = std::array<std::string_view, TR_N_KEYS>{
"torrent-complete-notification-enabled"sv,
"torrent-complete-sound-command"sv,
"torrent-complete-sound-enabled"sv,
"torrent-complete-verify-enabled"sv,
"torrent-duplicate"sv,
"torrent-get"sv,
"torrent-set"sv,

View File

@@ -388,6 +388,7 @@ enum // NOLINT(performance-enum-size)
TR_KEY_torrent_complete_notification_enabled,
TR_KEY_torrent_complete_sound_command,
TR_KEY_torrent_complete_sound_enabled,
TR_KEY_torrent_complete_verify_enabled,
TR_KEY_torrent_duplicate,
TR_KEY_torrent_get,
TR_KEY_torrent_set,

View File

@@ -1659,6 +1659,15 @@ size_t tr_sessionGetCacheLimit_MB(tr_session const* session)
// ---
void tr_sessionSetCompleteVerifyEnabled(tr_session* session, bool enabled)
{
TR_ASSERT(session != nullptr);
session->settings_.torrent_complete_verify_enabled = enabled;
}
// ---
void tr_session::setDefaultTrackers(std::string_view trackers)
{
auto const oldval = default_trackers_;

View File

@@ -416,6 +416,7 @@ public:
bool speed_limit_down_enabled = false;
bool speed_limit_up_enabled = false;
bool tcp_enabled = true;
bool torrent_complete_verify_enabled = false;
bool utp_enabled = true;
double ratio_limit = 2.0;
size_t cache_size_mbytes = 4U;
@@ -513,6 +514,7 @@ public:
{ TR_KEY_start_added_torrents, &should_start_added_torrents },
{ TR_KEY_tcp_enabled, &tcp_enabled },
{ TR_KEY_torrent_added_verify_mode, &torrent_added_verify_mode },
{ TR_KEY_torrent_complete_verify_enabled, &torrent_complete_verify_enabled },
{ TR_KEY_trash_original_torrent_files, &should_delete_source_torrents },
{ TR_KEY_umask, &umask },
{ TR_KEY_upload_slots_per_torrent, &upload_slots_per_torrent },
@@ -963,6 +965,11 @@ public:
return settings().torrent_added_verify_mode == TR_VERIFY_ADDED_FULL;
}
[[nodiscard]] constexpr auto shouldFullyVerifyCompleteTorrents() const noexcept
{
return settings().torrent_complete_verify_enabled;
}
[[nodiscard]] constexpr auto shouldDeleteSource() const noexcept
{
return settings().should_delete_source_torrents;
@@ -1207,6 +1214,7 @@ private:
friend void tr_sessionSetAntiBruteForceEnabled(tr_session* session, bool is_enabled);
friend void tr_sessionSetAntiBruteForceThreshold(tr_session* session, int max_bad_requests);
friend void tr_sessionSetCacheLimit_MB(tr_session* session, size_t mbytes);
friend void tr_sessionSetCompleteVerifyEnabled(tr_session* session, bool enabled);
friend void tr_sessionSetDHTEnabled(tr_session* session, bool enabled);
friend void tr_sessionSetDeleteSource(tr_session* session, bool delete_source);
friend void tr_sessionSetEncryption(tr_session* session, tr_encryption_mode mode);

View File

@@ -1786,6 +1786,12 @@ void tr_torrent::recheck_completeness()
bool const recent_change = bytes_downloaded_.during_this_session() != 0U;
bool const was_running = is_running();
if (new_completeness != TR_LEECH && was_running && session->shouldFullyVerifyCompleteTorrents())
{
tr_torrentVerify(this);
return;
}
tr_logAddTraceTor(
this,
fmt::format(
@@ -1794,10 +1800,11 @@ void tr_torrent::recheck_completeness()
get_completion_string(new_completeness)));
completeness_ = new_completeness;
session->close_torrent_files(id());
if (is_done())
{
session->close_torrent_files(id());
if (recent_change)
{
// https://www.bittorrent.org/beps/bep_0003.html

View File

@@ -635,7 +635,7 @@ size_t tr_sessionGetQueueStalledMinutes(tr_session const* session);
Stalled torrents are left running but are not counted by `tr_sessionGetQueueSize()`. */
void tr_sessionSetQueueStalledMinutes(tr_session* session, int minutes);
/** @return true if we're torrents idle for over N minutes will be flagged as 'stalled' */
/** @return true if torrents idle for over N minutes will be flagged as 'stalled' */
bool tr_sessionGetQueueStalledEnabled(tr_session const* session);
/** @brief Set whether or not to count torrents idle for over N minutes as 'stalled' */
@@ -646,10 +646,14 @@ void tr_sessionSetQueueStartCallback(tr_session* session, void (*callback)(tr_se
// ---
/** @brief Set whether or not to verify data when torrent download is complete */
void tr_sessionSetCompleteVerifyEnabled(tr_session* session, bool enabled);
// ---
/**
* Load all the torrents in the session's torrent folder.
* This can be used at startup to kickstart all the torrents
* from the previous session.
* This can be used at startup to kickstart all the torrents from the previous session.
*
* @return the number of torrents in the session
*/