diff --git a/ChangeLog b/ChangeLog index c372b760f..14195a7c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * fixed restoring of trackers, comment, creation date and created-by in resume data * fix handling of torrents with too large pieces * fixed division by zero in anti-leech choker * fixed bug in torrent_info::swap diff --git a/include/libtorrent/torrent_flags.hpp b/include/libtorrent/torrent_flags.hpp index 6019bec8f..9bfbb77f4 100644 --- a/include/libtorrent/torrent_flags.hpp +++ b/include/libtorrent/torrent_flags.hpp @@ -183,12 +183,22 @@ namespace torrent_flags { // object override any trackers from the torrent file. If the flag is // not set, the trackers from the add_torrent_params object will be // added to the list of trackers used by the torrent. + // This flag is set by read_resume_data() if there are trackers present in + // the resume data file. This effectively makes the trackers saved in the + // resume data take presedence over the original trackers. This includes if + // there's an empty list of trackers, to support the case where they were + // explicitly removed in the previous session. constexpr torrent_flags_t override_trackers = 11_bit; // If this flag is set, the web seeds from the add_torrent_params // object will override any web seeds in the torrent file. If it's not // set, web seeds in the add_torrent_params object will be added to the // list of web seeds used by the torrent. + // This flag is set by read_resume_data() if there are web seeds present in + // the resume data file. This effectively makes the web seeds saved in the + // resume data take presedence over the original ones. This includes if + // there's an empty list of web seeds, to support the case where they were + // explicitly removed in the previous session. constexpr torrent_flags_t override_web_seeds = 12_bit; // if this flag is set (which it is by default) the torrent will be diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index 960929209..ddf03154c 100644 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -566,6 +566,11 @@ namespace libtorrent { , piece_index_t piece); std::map build_merkle_list(piece_index_t piece) const; + // internal + void internal_set_creator(string_view const); + void internal_set_creation_date(std::time_t); + void internal_set_comment(string_view const); + // returns whether or not this is a merkle torrent. // see `BEP 30`__. // diff --git a/src/read_resume_data.cpp b/src/read_resume_data.cpp index 4b6e0d7bd..92855f337 100644 --- a/src/read_resume_data.cpp +++ b/src/read_resume_data.cpp @@ -115,6 +115,12 @@ namespace { { ec = err; } + else + { + ret.ti->internal_set_creation_date(rd.dict_find_int_value("creation date", 0)); + ret.ti->internal_set_creator(rd.dict_find_string_value("created by", "")); + ret.ti->internal_set_comment(rd.dict_find_string_value("comment", "")); + } } } diff --git a/src/torrent.cpp b/src/torrent.cpp index 2045cbdf9..43a44615f 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -6211,16 +6211,13 @@ bool is_downloading_state(int const st) } // save web seeds - if (!m_web_seeds.empty()) + for (auto const& ws : m_web_seeds) { - for (auto const& ws : m_web_seeds) - { - if (ws.removed || ws.ephemeral) continue; - if (ws.type == web_seed_entry::url_seed) - ret.url_seeds.push_back(ws.url); - else if (ws.type == web_seed_entry::http_seed) - ret.http_seeds.push_back(ws.url); - } + if (ws.removed || ws.ephemeral) continue; + if (ws.type == web_seed_entry::url_seed) + ret.url_seeds.push_back(ws.url); + else if (ws.type == web_seed_entry::http_seed) + ret.http_seeds.push_back(ws.url); } // write have bitmask diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 8d9cba88f..8dc1a45fb 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -1347,6 +1347,15 @@ namespace { return true; } + void torrent_info::internal_set_creator(string_view const c) + { m_created_by = std::string(c); } + + void torrent_info::internal_set_creation_date(std::time_t const t) + { m_creation_date = t; } + + void torrent_info::internal_set_comment(string_view const s) + { m_comment = std::string(s); } + // builds a list of nodes that are required to verify // the given piece std::map diff --git a/src/write_resume_data.cpp b/src/write_resume_data.cpp index 92f6b62a4..51515f262 100644 --- a/src/write_resume_data.cpp +++ b/src/write_resume_data.cpp @@ -92,6 +92,12 @@ namespace libtorrent { auto const info = atp.ti->metadata(); int const size = atp.ti->metadata_size(); ret["info"].preformatted().assign(&info[0], &info[0] + size); + if (!atp.ti->comment().empty()) + ret["comment"] = atp.ti->comment(); + if (atp.ti->creation_date() != 0) + ret["creation date"] = atp.ti->creation_date(); + if (!atp.ti->creator().empty()) + ret["created by"] = atp.ti->creator(); } if (!atp.merkle_tree.empty()) @@ -123,9 +129,9 @@ namespace libtorrent { } // save trackers + entry::list_type& tr_list = ret["trackers"].list(); if (!atp.trackers.empty()) { - entry::list_type& tr_list = ret["trackers"].list(); tr_list.emplace_back(entry::list_type()); std::size_t tier = 0; auto tier_it = atp.tracker_tiers.begin(); @@ -142,17 +148,11 @@ namespace libtorrent { } // save web seeds - if (!atp.url_seeds.empty()) - { - entry::list_type& url_list = ret["url-list"].list(); - std::copy(atp.url_seeds.begin(), atp.url_seeds.end(), std::back_inserter(url_list)); - } + entry::list_type& url_list = ret["url-list"].list(); + std::copy(atp.url_seeds.begin(), atp.url_seeds.end(), std::back_inserter(url_list)); - if (!atp.http_seeds.empty()) - { - entry::list_type& url_list = ret["httpseeds"].list(); - std::copy(atp.http_seeds.begin(), atp.http_seeds.end(), std::back_inserter(url_list)); - } + entry::list_type& httpseeds_list = ret["httpseeds"].list(); + std::copy(atp.http_seeds.begin(), atp.http_seeds.end(), std::back_inserter(httpseeds_list)); // write have bitmask entry::string_type& pieces = ret["pieces"].string(); diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index 8f15bdb8a..fd623c7c7 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -84,6 +84,8 @@ std::shared_ptr generate_torrent(bool const with_files) fs.add_file("test_resume/tmp3", 128 * 1024); lt::create_torrent t(fs, 128 * 1024, 6); + t.set_comment("test comment"); + t.set_creator("libtorrent test"); t.add_tracker("http://torrent_file_tracker.com/announce"); t.add_url_seed("http://torrent_file_url_seed.com/"); diff --git a/test/test_read_resume.cpp b/test/test_read_resume.cpp index 082a75ece..420271af2 100644 --- a/test/test_read_resume.cpp +++ b/test/test_read_resume.cpp @@ -287,3 +287,10 @@ TORRENT_TEST(round_trip_unfinished) test_roundtrip(atp); } +TORRENT_TEST(round_trip_trackers) +{ + add_torrent_params atp; + atp.flags |= torrent_flags::override_trackers; + test_roundtrip(atp); +} + diff --git a/test/test_resume.cpp b/test/test_resume.cpp index 8ee4a6265..18d493141 100644 --- a/test/test_resume.cpp +++ b/test/test_resume.cpp @@ -276,6 +276,143 @@ TORRENT_TEST(piece_priorities) test_piece_priorities(); } +TORRENT_TEST(test_non_metadata) +{ + lt::session ses(settings()); + // this test torrent contain a tracker: + // http://torrent_file_tracker.com/announce + + // and a URL seed: + // http://torrent_file_url_seed.com + + std::shared_ptr ti = generate_torrent(); + add_torrent_params p; + p.ti = ti; + p.save_path = "."; + torrent_handle h = ses.add_torrent(p); + + h.replace_trackers(std::vector{announce_entry{"http://torrent_file_tracker2.com/announce"}}); + h.remove_url_seed("http://torrent_file_url_seed.com/"); + h.add_url_seed("http://torrent.com/"); + + TEST_EQUAL(ti->comment(), "test comment"); + TEST_EQUAL(ti->creator(), "libtorrent test"); + auto const creation_date = ti->creation_date(); + + h.save_resume_data(torrent_handle::save_info_dict); + alert const* a = wait_for_alert(ses, save_resume_data_alert::alert_type); + + TEST_CHECK(a); + save_resume_data_alert const* ra = alert_cast(a); + TEST_CHECK(ra); + if (ra) + { + auto const& atp = ra->params; + TEST_CHECK(atp.trackers == std::vector{"http://torrent_file_tracker2.com/announce"}); + TEST_CHECK(atp.url_seeds == std::vector{"http://torrent.com/"}); + TEST_CHECK(atp.ti); + TEST_EQUAL(atp.ti->comment(), "test comment"); + TEST_EQUAL(atp.ti->creator(), "libtorrent test"); + TEST_EQUAL(atp.ti->creation_date(), creation_date); + + std::vector resume_data = write_resume_data_buf(atp); + p = read_resume_data(resume_data); + p.ti = ti; + p.save_path = "."; + } + + ses.remove_torrent(h); + + // now, make sure the fields are restored correctly + h = ses.add_torrent(p); + + TEST_EQUAL(h.trackers().size(), 1); + TEST_CHECK(h.trackers().at(0).url == "http://torrent_file_tracker2.com/announce"); + TEST_CHECK(h.url_seeds() == std::set{"http://torrent.com/"}); + auto t = h.status().torrent_file.lock(); + TEST_EQUAL(ti->comment(), "test comment"); + TEST_EQUAL(ti->creator(), "libtorrent test"); + TEST_EQUAL(ti->creation_date(), creation_date); +} + +TORRENT_TEST(test_remove_trackers) +{ + lt::session ses(settings()); + // this test torrent contain a tracker: + // http://torrent_file_tracker.com/announce + + std::shared_ptr ti = generate_torrent(); + add_torrent_params p; + p.ti = ti; + p.save_path = "."; + torrent_handle h = ses.add_torrent(p); + + h.replace_trackers(std::vector{}); + + h.save_resume_data(torrent_handle::save_info_dict); + alert const* a = wait_for_alert(ses, save_resume_data_alert::alert_type); + + TEST_CHECK(a); + save_resume_data_alert const* ra = alert_cast(a); + TEST_CHECK(ra); + if (ra) + { + auto const& atp = ra->params; + TEST_EQUAL(atp.trackers.size(), 0); + + std::vector resume_data = write_resume_data_buf(atp); + p = read_resume_data(resume_data); + p.ti = ti; + p.save_path = "."; + } + + ses.remove_torrent(h); + + // now, make sure the fields are restored correctly + h = ses.add_torrent(p); + + TEST_EQUAL(h.trackers().size(), 0); +} + +TORRENT_TEST(test_remove_web_seed) +{ + lt::session ses(settings()); + // this test torrent contain a URL seed: + // http://torrent_file_url_seed.com + + std::shared_ptr ti = generate_torrent(); + add_torrent_params p; + p.ti = ti; + p.save_path = "."; + torrent_handle h = ses.add_torrent(p); + + h.remove_url_seed("http://torrent_file_url_seed.com/"); + + h.save_resume_data(torrent_handle::save_info_dict); + alert const* a = wait_for_alert(ses, save_resume_data_alert::alert_type); + + TEST_CHECK(a); + save_resume_data_alert const* ra = alert_cast(a); + TEST_CHECK(ra); + if (ra) + { + auto const& atp = ra->params; + TEST_CHECK(atp.url_seeds.size() == 0); + + std::vector resume_data = write_resume_data_buf(atp); + p = read_resume_data(resume_data); + p.ti = ti; + p.save_path = "."; + } + + ses.remove_torrent(h); + + // now, make sure the fields are restored correctly + h = ses.add_torrent(p); + + TEST_EQUAL(h.url_seeds().size(), 0); +} + TORRENT_TEST(piece_slots) { // make sure the "pieces" field is correctly accepted from resume data