diff --git a/include/libtorrent/resolve_links.hpp b/include/libtorrent/resolve_links.hpp index cec4c67a8..df3649432 100644 --- a/include/libtorrent/resolve_links.hpp +++ b/include/libtorrent/resolve_links.hpp @@ -33,12 +33,11 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_RESOLVE_LINKS_HPP #define TORRENT_RESOLVE_LINKS_HPP -#include "libtorrent/aux_/disable_warnings_push.hpp" -#include -#include "libtorrent/aux_/disable_warnings_pop.hpp" - #include #include +#include +#include +#include #include "libtorrent/export.hpp" @@ -77,7 +76,7 @@ namespace libtorrent std::vector m_links; // maps file size to file index, in m_torrent_file - boost::unordered_multimap m_file_sizes; + std::unordered_multimap m_file_sizes; }; #endif // TORRENT_DISABLE_MUTABLE_TORRENTS diff --git a/src/resolve_links.cpp b/src/resolve_links.cpp index 63f2a50c4..afdeddb50 100644 --- a/src/resolve_links.cpp +++ b/src/resolve_links.cpp @@ -84,48 +84,48 @@ void resolve_links::match(std::shared_ptr const& ti std::int64_t file_size = fs.file_size(i); - auto iter = m_file_sizes.find(file_size); - - // we don't have a file whose size matches, look at the next one - if (iter == m_file_sizes.end()) continue; - - TORRENT_ASSERT(iter->second < m_torrent_file->files().num_files()); - TORRENT_ASSERT(iter->second >= 0); - - // if we already have found a duplicate for this file, no need - // to keep looking - if (m_links[iter->second].ti) continue; - - // files are aligned and have the same size, now start comparing - // piece hashes, to see if the files are identical - - // the pieces of the incoming file - int their_piece = fs.map_file(i, 0, 0).piece; - // the pieces of "this" file (from m_torrent_file) - int our_piece = m_torrent_file->files().map_file( - iter->second, 0, 0).piece; - - int num_pieces = (file_size + piece_size - 1) / piece_size; - - bool match = true; - for (int p = 0; p < num_pieces; ++p, ++their_piece, ++our_piece) + auto range = m_file_sizes.equal_range(file_size); + for (auto iter = range.first; iter != range.second; ++iter) { - if (m_torrent_file->hash_for_piece(our_piece) - != ti->hash_for_piece(their_piece)) + TORRENT_ASSERT(iter->second < m_torrent_file->files().num_files()); + TORRENT_ASSERT(iter->second >= 0); + + // if we already have found a duplicate for this file, no need + // to keep looking + if (m_links[iter->second].ti) continue; + + // files are aligned and have the same size, now start comparing + // piece hashes, to see if the files are identical + + // the pieces of the incoming file + int their_piece = fs.map_file(i, 0, 0).piece; + // the pieces of "this" file (from m_torrent_file) + int our_piece = m_torrent_file->files().map_file( + iter->second, 0, 0).piece; + + int num_pieces = (file_size + piece_size - 1) / piece_size; + + bool match = true; + for (int p = 0; p < num_pieces; ++p, ++their_piece, ++our_piece) { - match = false; - break; + if (m_torrent_file->hash_for_piece(our_piece) + != ti->hash_for_piece(their_piece)) + { + match = false; + break; + } } + if (!match) continue; + + m_links[iter->second].ti = ti; + m_links[iter->second].save_path = save_path; + m_links[iter->second].file_idx = i; + + // since we have a duplicate for this file, we may as well remove + // it from the file-size map, so we won't find it again. + m_file_sizes.erase(iter); + break; } - if (!match) continue; - - m_links[iter->second].ti = ti; - m_links[iter->second].save_path = save_path; - m_links[iter->second].file_idx = i; - - // since we have a duplicate for this file, we may as well remove - // it from the file-size map, so we won't find it again. - m_file_sizes.erase(iter); } } diff --git a/test/test_resolve_links.cpp b/test/test_resolve_links.cpp index 64ab7ba46..d3fc7338e 100644 --- a/test/test_resolve_links.cpp +++ b/test/test_resolve_links.cpp @@ -31,10 +31,14 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "test.hpp" + +#ifndef TORRENT_DISABLE_MUTABLE_TORRENTS + #include "libtorrent/torrent_info.hpp" #include "libtorrent/resolve_links.hpp" #include "libtorrent/file.hpp" // for combine_path #include "libtorrent/hex.hpp" // to_hex +#include "libtorrent/create_torrent.hpp" #include @@ -87,8 +91,6 @@ static test_torrent_t test_torrents[] = { TORRENT_TEST(resolve_links) { - -#ifndef TORRENT_DISABLE_MUTABLE_TORRENTS std::string path = combine_path(parent_path(current_working_directory()) , "mutable_test_torrents"); @@ -131,6 +133,48 @@ TORRENT_TEST(resolve_links) TEST_EQUAL(num_matches, e.expected_matches); } -#endif // TORRENT_DISABLE_MUTABLE_TORRENTS } +// this ensure that internally the is a range lookup +// since the zero-hash piece is in the second place +TORRENT_TEST(range_lookup_duplicated_files) +{ + file_storage fs1; + file_storage fs2; + + fs1.add_file("test_resolve_links_dir/tmp1", 1024); + fs1.add_file("test_resolve_links_dir/tmp2", 1024); + fs2.add_file("test_resolve_links_dir/tmp1", 1024); + fs2.add_file("test_resolve_links_dir/tmp2", 1024); + + libtorrent::create_torrent t1(fs1, 1024); + libtorrent::create_torrent t2(fs2, 1024); + + t1.set_hash(0, sha1_hash::max()); + + std::vector tmp1; + std::vector tmp2; + bencode(std::back_inserter(tmp1), t1.generate()); + bencode(std::back_inserter(tmp2), t2.generate()); + error_code ec; + auto ti1 = std::make_shared(&tmp1[0], int(tmp1.size()), ec); + auto ti2 = std::make_shared(&tmp2[0], int(tmp2.size()), ec); + + std::fprintf(stderr, "resolving\n"); + resolve_links l(ti1); + l.match(ti2, "."); + + std::vector const& links = l.get_links(); + + std::string::size_type num_matches = std::count_if(links.begin(), links.end() + , std::bind(&resolve_links::link_t::ti, _1)); + + TEST_EQUAL(num_matches, 1); +} + +#else +TORRENT_TEST(empty) +{ + TEST_CHECK(true); +} +#endif // TORRENT_DISABLE_MUTABLE_TORRENTS