allow padfiles of equal size to share the same filename

This commit is contained in:
Arvid Norberg 2019-02-28 18:18:50 +01:00 committed by Arvid Norberg
parent ed867e0062
commit e106602f49
2 changed files with 62 additions and 20 deletions

View File

@ -59,6 +59,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/lazy_entry.hpp" #include "libtorrent/lazy_entry.hpp"
#endif #endif
#include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <cstdint> #include <cstdint>
#include <iterator> #include <iterator>
@ -637,9 +638,8 @@ namespace {
void torrent_info::resolve_duplicate_filenames_slow() void torrent_info::resolve_duplicate_filenames_slow()
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
int cnt = 0;
std::unordered_set<std::string, string_hash_no_case, string_eq_no_case> files; std::unordered_map<std::string, file_index_t, string_hash_no_case, string_eq_no_case> files;
std::vector<std::string> const& paths = m_files.paths(); std::vector<std::string> const& paths = m_files.paths();
files.reserve(paths.size() + aux::numeric_cast<std::size_t>(m_files.num_files())); files.reserve(paths.size() + aux::numeric_cast<std::size_t>(m_files.num_files()));
@ -649,14 +649,14 @@ namespace {
for (auto const& i : paths) for (auto const& i : paths)
{ {
std::string p = combine_path(m_files.name(), i); std::string p = combine_path(m_files.name(), i);
files.insert(p); files.insert({p, file_index_t{-1}});
while (has_parent_path(p)) while (has_parent_path(p))
{ {
p = parent_path(p); p = parent_path(std::move(p));
// we don't want trailing slashes here // we don't want trailing slashes here
TORRENT_ASSERT(p[p.size() - 1] == TORRENT_SEPARATOR); TORRENT_ASSERT(p[p.size() - 1] == TORRENT_SEPARATOR);
p.resize(p.size() - 1); p.resize(p.size() - 1);
files.insert(p); files.insert({p, file_index_t{-1}});
} }
} }
@ -665,23 +665,31 @@ namespace {
// as long as this file already exists // as long as this file already exists
// increase the counter // increase the counter
std::string filename = m_files.file_path(i); std::string filename = m_files.file_path(i);
if (!files.insert(filename).second) auto const ret = files.insert({filename, i});
{ if (ret.second) continue;
std::string base = remove_extension(filename); // pad files are allowed to collide with each-other, as long as they have
std::string ext = extension(filename); // the same size.
do file_index_t const other_idx = ret.first->second;
{ if (other_idx != file_index_t{-1}
++cnt; && (m_files.file_flags(i) & file_storage::flag_pad_file)
char new_ext[50]; && (m_files.file_flags(other_idx) & file_storage::flag_pad_file)
std::snprintf(new_ext, sizeof(new_ext), ".%d%s", cnt, ext.c_str()); && m_files.file_size(i) == m_files.file_size(other_idx))
filename = base + new_ext; continue;
}
while (!files.insert(filename).second);
copy_on_write(); std::string base = remove_extension(filename);
m_files.rename_file(i, filename); std::string ext = extension(filename);
int cnt = 0;
do
{
++cnt;
char new_ext[50];
std::snprintf(new_ext, sizeof(new_ext), ".%d%s", cnt, ext.c_str());
filename = base + new_ext;
} }
cnt = 0; while (!files.insert({filename, i}).second);
copy_on_write();
m_files.rename_file(i, filename);
} }
} }

View File

@ -913,6 +913,40 @@ std::vector<lt::aux::vector<file_t, lt::file_index_t>> const test_cases
{"test/filler-1", 0x4000, {}, "test/filler-1"}, {"test/filler-1", 0x4000, {}, "test/filler-1"},
{"test/filler-2", 0x4000, {}, "test/filler-2"}, {"test/filler-2", 0x4000, {}, "test/filler-2"},
}, },
{
// pad files are allowed to collide, as long as they have the same size
{"test/.pad/1234", 0x4000, file_storage::flag_pad_file, "test/.pad/1234"},
{"test/filler-1", 0x4000, {}, "test/filler-1"},
{"test/.pad/1234", 0x4000, file_storage::flag_pad_file, "test/.pad/1234"},
{"test/filler-2", 0x4000, {}, "test/filler-2"},
},
{
// pad files of different sizes are NOT allowed to collide
{"test/.pad/1234", 0x8000, file_storage::flag_pad_file, "test/.pad/1234"},
{"test/filler-1", 0x4000, {}, "test/filler-1"},
{"test/.pad/1234", 0x4000, file_storage::flag_pad_file, "test/.pad/1234.1"},
{"test/filler-2", 0x4000, {}, "test/filler-2"},
},
{
// pad files are NOT allowed to collide with normal files
{"test/.pad/1234", 0x4000, {}, "test/.pad/1234"},
{"test/filler-1", 0x4000, {}, "test/filler-1"},
{"test/.pad/1234", 0x4000, file_storage::flag_pad_file, "test/.pad/1234.1"},
{"test/filler-2", 0x4000, {}, "test/filler-2"},
},
{
// normal files are NOT allowed to collide with pad files
{"test/.pad/1234", 0x4000, file_storage::flag_pad_file, "test/.pad/1234"},
{"test/filler-1", 0x4000, {}, "test/filler-1"},
{"test/.pad/1234", 0x4000, {}, "test/.pad/1234.1"},
{"test/filler-2", 0x4000, {}, "test/filler-2"},
},
{
// pad files are NOT allowed to collide with directories
{"test/.pad/1234", 0x4000, file_storage::flag_pad_file, "test/.pad/1234.1"},
{"test/filler-1", 0x4000, {}, "test/filler-1"},
{"test/.pad/1234/filler-2", 0x4000, {}, "test/.pad/1234/filler-2"},
},
}; };
void test_resolve_duplicates(aux::vector<file_t, file_index_t> const& test) void test_resolve_duplicates(aux::vector<file_t, file_index_t> const& test)