From 378a0e974b6035755f355ff261bc1a0b10630c82 Mon Sep 17 00:00:00 2001 From: arvidn Date: Tue, 8 Aug 2017 14:25:21 +0200 Subject: [PATCH] fix issue of force-recheck or seeding from read-only media, torrents with empty files in them. Previously libtorrent would create empty files up-front unconditionally, now they won't be created if they already exist --- ChangeLog | 1 + src/storage.cpp | 14 ++++++++++---- test/setup_transfer.cpp | 4 +++- test/setup_transfer.hpp | 4 +++- test/test_checking.cpp | 13 +++++++++---- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 91ff40e03..0196ea502 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * don't attempt to create empty files on startup, if they already exist * fix force-recheck issue (new files would not be picked up) * fix inconsistency in file_priorities and override_resume_data behavior diff --git a/src/storage.cpp b/src/storage.cpp index 5cf13b620..75b04c779 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -543,7 +543,8 @@ namespace libtorrent // ignore pad files if (files().pad_file_at(file_index)) continue; - if (m_stat_cache.get_filesize(file_index) == stat_cache::not_in_cache) + boost::int64_t cached_size = m_stat_cache.get_filesize(file_index); + if (cached_size == stat_cache::not_in_cache) { file_status s; std::string file_path = files().file_path(file_index, m_save_path); @@ -551,6 +552,7 @@ namespace libtorrent if (!ec) { m_stat_cache.set_cache(file_index, s.file_size, s.mtime); + cached_size = s.file_size; } else if (ec.ec != boost::system::errc::no_such_file_or_directory) { @@ -559,13 +561,17 @@ namespace libtorrent ec.operation = storage_error::stat; break; } + else + { + cached_size = stat_cache::no_exist; + } } // if the file already exists, but is larger than what // it's supposed to be, truncate it - // if the file is empty, just create it either way. - if ((!ec && m_stat_cache.get_filesize(file_index) > files().file_size(file_index)) - || files().file_size(file_index) == 0) + // if the file is empty and doesn't already exist, create it + if ((!ec && cached_size > files().file_size(file_index)) + || (files().file_size(file_index) == 0 && cached_size == stat_cache::no_exist)) { std::string file_path = files().file_path(file_index, m_save_path); std::string dir = parent_path(file_path); diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index 4615b5dc3..394570a41 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -595,7 +595,8 @@ boost::shared_ptr clone_ptr(boost::shared_ptr const& ptr) unsigned char random_byte() { return std::rand() & 0xff; } -void create_random_files(std::string const& path, const int file_sizes[], int num_files) +void create_random_files(std::string const& path, const int file_sizes[], int num_files + , file_storage* fs) { error_code ec; char* random_data = (char*)malloc(300000); @@ -613,6 +614,7 @@ void create_random_files(std::string const& path, const int file_sizes[], int nu full_path = combine_path(full_path, filename); int to_write = file_sizes[i]; + if (fs) fs->add_file(full_path, to_write); file f(full_path, file::write_only, ec); if (ec) fprintf(stderr, "failed to create file \"%s\": (%d) %s\n" , full_path.c_str(), ec.value(), ec.message().c_str()); diff --git a/test/setup_transfer.hpp b/test/setup_transfer.hpp index bbb5e3fb6..f8bc8fd86 100644 --- a/test/setup_transfer.hpp +++ b/test/setup_transfer.hpp @@ -41,6 +41,7 @@ namespace libtorrent { class alert; struct add_torrent_params; + class file_storage; } EXPORT int print_failures(); @@ -83,7 +84,8 @@ EXPORT void wait_for_listen(libtorrent::session& ses, char const* name); EXPORT void wait_for_downloading(libtorrent::session& ses, char const* name); EXPORT void test_sleep(int millisec); -EXPORT void create_random_files(std::string const& path, const int file_sizes[], int num_files); +EXPORT void create_random_files(std::string const& path, const int file_sizes[] + , int num_files, libtorrent::file_storage* fs = NULL); EXPORT boost::shared_ptr create_torrent(std::ostream* file = 0 , char const* name = "temporary", int piece_size = 16 * 1024, int num_pieces = 13 diff --git a/test/test_checking.cpp b/test/test_checking.cpp index 1b367a061..df4dfe1fe 100644 --- a/test/test_checking.cpp +++ b/test/test_checking.cpp @@ -41,7 +41,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/torrent_status.hpp" static const int file_sizes[] = -{ 5, 16 - 5, 16000, 17, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1 +{ 0, 5, 16 - 5, 16000, 17, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1 ,1,1,1,1,1,1,13,65000,34,75,2,30,400,500,23000,900,43000,400,4300,6, 4}; const int num_files = sizeof(file_sizes)/sizeof(file_sizes[0]); @@ -83,9 +83,8 @@ void test_checking(int flags = read_only_files) std::srand(10); int piece_size = 0x4000; - create_random_files("test_torrent_dir", file_sizes, num_files); + create_random_files("test_torrent_dir", file_sizes, num_files, &fs); - add_files(fs, "test_torrent_dir"); lt::create_torrent t(fs, piece_size, 0x4000 , lt::create_torrent::optimize_alignment); @@ -130,7 +129,7 @@ void test_checking(int flags = read_only_files) // increase the size of some files. When they're read only that forces // the checker to open them in write-mode to truncate them static const int file_sizes2[] = - { 5, 16 - 5, 16001, 30, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1 + { 0, 5, 16 - 5, 16001, 30, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1 ,1,1,1,1,1,1,13,65000,34,75,2,30,400,500,23000,900,43000,400,4300,6, 4}; create_random_files("test_torrent_dir", file_sizes2, num_files); } @@ -160,6 +159,9 @@ void test_checking(int flags = read_only_files) if (flags & force_recheck) { + remove_all("test_torrent_dir_tmp", ec); + if (ec) fprintf(stdout, "ERROR: removing \"test_torrent_dir_tmp\": (%d) %s\n" + , ec.value(), ec.message().c_str()); rename("test_torrent_dir", "test_torrent_dir_tmp", ec); if (ec) fprintf(stdout, "ERROR: renaming dir \"test_torrent_dir\": (%d) %s\n" , ec.value(), ec.message().c_str()); @@ -196,6 +198,9 @@ void test_checking(int flags = read_only_files) // now, move back the files and force-recheck. make sure we pick up the // files this time + remove_all("test_torrent_dir", ec); + if (ec) fprintf(stdout, "ERROR: removing \"test_torrent_dir\": (%d) %s\n" + , ec.value(), ec.message().c_str()); rename("test_torrent_dir_tmp", "test_torrent_dir", ec); if (ec) fprintf(stdout, "ERROR: renaming dir \"test_torrent_dir_tmp\": (%d) %s\n" , ec.value(), ec.message().c_str());