From bcb703b9a30d537f55c43e74ef64393dcd2e30e2 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 18 Nov 2013 06:59:47 +0000 Subject: [PATCH] improve duplicate file detection in torrent files --- include/libtorrent/file.hpp | 1 + src/file.cpp | 12 ++++++++++++ src/torrent_info.cpp | 15 ++++++++++----- test/test_file.cpp | 5 +++++ test/test_torrent_info.cpp | 10 +++++++--- 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/include/libtorrent/file.hpp b/include/libtorrent/file.hpp index 75993d934..91086ebdc 100644 --- a/include/libtorrent/file.hpp +++ b/include/libtorrent/file.hpp @@ -133,6 +133,7 @@ namespace libtorrent TORRENT_EXTRA_EXPORT std::string split_path(std::string const& f); TORRENT_EXTRA_EXPORT char const* next_path_element(char const* p); TORRENT_EXTRA_EXPORT std::string extension(std::string const& f); + TORRENT_EXTRA_EXPORT std::string remove_extension(std::string const& f); TORRENT_EXTRA_EXPORT void replace_extension(std::string& f, std::string const& ext); TORRENT_EXTRA_EXPORT bool is_root_path(std::string const& f); diff --git a/src/file.cpp b/src/file.cpp index de7f81f3f..60955b18a 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -423,6 +423,18 @@ namespace libtorrent return ""; } + std::string remove_extension(std::string const& f) + { + char const* slash = strrchr(f.c_str(), '/'); +#ifdef TORRENT_WINDOWS + slash = (std::max)((char const*)strrchr(f.c_str(), '\\'), slash); +#endif + char const* ext = strrchr(f.c_str(), '.'); + // if we don't have an extension, just return f + if (ext == 0 || ext == &f[0] || (slash != NULL && ext < slash)) return f; + return f.substr(0, ext - &f[0]); + } + void replace_extension(std::string& f, std::string const& ext) { for (int i = f.size() - 1; i >= 0; --i) diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 299c267d2..a4bfd510d 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -402,12 +402,17 @@ namespace libtorrent // as long as this file already exists // increase the counter int cnt = 0; - while (!files.insert(e.path).second) + if (!files.insert(e.path).second) { - ++cnt; - char suffix[50]; - snprintf(suffix, sizeof(suffix), "%d%s", cnt, extension(e.path).c_str()); - replace_extension(e.path, suffix); + std::string base = remove_extension(e.path); + std::string ext = extension(e.path); + do + { + ++cnt; + char new_ext[50]; + snprintf(new_ext, sizeof(new_ext), ".%d%s", cnt, ext.c_str()); + e.path = base + new_ext; + } while (!files.insert(e.path).second); } target.add_file(e, file_hash ? file_hash->string_ptr() + info_ptr_diff : 0); diff --git a/test/test_file.cpp b/test/test_file.cpp index 8b620a471..f04b0d286 100644 --- a/test/test_file.cpp +++ b/test/test_file.cpp @@ -127,6 +127,11 @@ int test_main() TEST_EQUAL(extension("blah.foo."), "."); TEST_EQUAL(extension("blah.foo/bar"), ""); + TEST_EQUAL(remove_extension("blah"), "blah"); + TEST_EQUAL(remove_extension("blah.exe"), "blah"); + TEST_EQUAL(remove_extension("blah.foo.bar"), "blah.foo"); + TEST_EQUAL(remove_extension("blah.foo."), "blah.foo"); + TEST_EQUAL(filename("blah"), "blah"); TEST_EQUAL(filename("/blah/foo/bar"), "bar"); TEST_EQUAL(filename("/blah/foo/bar/"), "bar"); diff --git a/test/test_torrent_info.cpp b/test/test_torrent_info.cpp index 2c819572a..178743da9 100644 --- a/test/test_torrent_info.cpp +++ b/test/test_torrent_info.cpp @@ -41,7 +41,6 @@ int test_main() { file_storage fs; - int total_size = 100 * 0x4000; fs.add_file("test/temporary.txt", 0x4000); fs.add_file("test/A/tmp", 0x4000); @@ -76,12 +75,17 @@ int test_main() "test/A/tmp", "test/Temporary.1.txt", // duplicate of temporary.txt "test/TeMPorArY.2.txT", // duplicate of temporary.txt - "test/a.1", // a file may not have the same name as a directory + + // a file may not have the same name as a directory + // however, detecting this is not supported currently. + // it is in the next major release + "test/a", + "test/b.exe", "test/B.1.ExE", // duplicate of b.exe "test/B.2.exe", // duplicate of b.exe "test/test/TEMPORARY.TXT", // a file with the same name in a seprate directory is fine - "test/A.2", // duplicate of directory a + "test/A.1", // duplicate of directory a }; for (int i = 0; i < ti.num_files(); ++i)