diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index 51cca20a5..d3c74803e 100644 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -93,6 +93,7 @@ namespace libtorrent ~torrent_info(); file_storage const& files() const { return m_files; } + file_storage& files() { return m_files; } void add_tracker(std::string const& url, int tier = 0); std::vector const& trackers() const { return m_urls; } diff --git a/src/storage.cpp b/src/storage.cpp index 8466109e3..8596ed703 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -53,6 +53,9 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#if BOOST_VERSION >= 103500 +#include +#endif #ifdef _MSC_VER #pragma warning(pop) @@ -581,7 +584,10 @@ namespace libtorrent try { #endif - rename(old_path, new_path); + // if old path doesn't exist, just rename the file + // in our file_storage, so that when it is created + // it will get the new name + if (exists(old_path)) rename(old_path, new_path); /* error_code ec; rename(old_path, new_path, ec); @@ -596,6 +602,13 @@ namespace libtorrent m_mapped_files->rename_file(index, new_filename); #ifndef BOOST_NO_EXCEPTIONS } +#if BOOST_VERSION >= 103500 + catch (boost::system::system_error& e) + { + set_error(old_name, e.code()); + return true; + } +#endif catch (std::exception& e) { set_error(old_name, error_code(errno, get_posix_category())); @@ -726,15 +739,6 @@ namespace libtorrent m_file_priority[i] = file_priority->list_int_value_at(i, 1); } - lazy_entry const* mapped_files = rd.dict_find_list("mapped_files"); - if (mapped_files && mapped_files->list_size() == m_files.num_files()) - { - if (!m_mapped_files) - { m_mapped_files.reset(new file_storage(m_files)); } - for (int i = 0; i < m_files.num_files(); ++i) - m_mapped_files->rename_file(i, mapped_files->list_string_value_at(i)); - } - std::vector > file_sizes; lazy_entry const* file_sizes_ent = rd.dict_find_list("file sizes"); if (file_sizes_ent == 0) diff --git a/src/torrent.cpp b/src/torrent.cpp index 3c235e965..7a590f994 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -1661,6 +1661,7 @@ namespace libtorrent { if (alerts().should_post()) alerts().post_alert(file_renamed_alert(get_handle(), j.str, j.piece)); + m_torrent_file->files().rename_file(j.piece, j.str); } else { @@ -2551,6 +2552,17 @@ namespace libtorrent < boost::bind(&announce_entry::tier, _2)); } + lazy_entry const* mapped_files = rd.dict_find_list("mapped_files"); + if (mapped_files && mapped_files->list_size() == m_torrent_file->num_files()) + { + for (int i = 0; i < m_torrent_file->num_files(); ++i) + { + std::string new_filename = mapped_files->list_string_value_at(i); + if (new_filename.empty()) continue; + m_torrent_file->files().rename_file(i, new_filename); + } + } + lazy_entry const* url_list = rd.dict_find_list("url-list"); if (url_list) { diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index 50bcc79d7..782236c51 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -50,7 +50,8 @@ using boost::filesystem::remove_all; using boost::filesystem::create_directory; using namespace libtorrent; -void print_alerts(libtorrent::session& ses, char const* name, bool allow_disconnects, bool allow_no_torrents) +void print_alerts(libtorrent::session& ses, char const* name + , bool allow_disconnects, bool allow_no_torrents, bool allow_failed_fastresume) { std::vector handles = ses.get_torrents(); TEST_CHECK(!handles.empty() || allow_no_torrents); @@ -70,6 +71,8 @@ void print_alerts(libtorrent::session& ses, char const* name, bool allow_disconn { std::cerr << name << ": " << a->message() << "\n"; } + TEST_CHECK(dynamic_cast(a.get()) == 0 || allow_failed_fastresume); + TEST_CHECK(dynamic_cast(a.get()) == 0 || (!handles.empty() && h.is_seed()) || a->message() == "connecting to peer" diff --git a/test/setup_transfer.hpp b/test/setup_transfer.hpp index 4585e4c5b..8c9a4a476 100644 --- a/test/setup_transfer.hpp +++ b/test/setup_transfer.hpp @@ -39,7 +39,8 @@ POSSIBILITY OF SUCH DAMAGE. void print_alerts(libtorrent::session& ses, char const* name , bool allow_disconnects = false - , bool allow_no_torrents = false); + , bool allow_no_torrents = false + , bool allow_failed_fastresume = false); void test_sleep(int millisec); boost::intrusive_ptr create_torrent(std::ostream* file = 0, int piece_size = 16 * 1024, int num_pieces = 1024 / 8); diff --git a/test/test_storage.cpp b/test/test_storage.cpp index 7e84feaee..366e1f00e 100644 --- a/test/test_storage.cpp +++ b/test/test_storage.cpp @@ -417,7 +417,8 @@ void run_test(path const& test_path) void test_fastresume() { - std::cout << "=== test fastresume ===" << std::endl; + std::cout << "\n\n=== test fastresume ===" << std::endl; + remove_all("tmp1"); create_directory("tmp1"); std::ofstream file("tmp1/temporary"); boost::intrusive_ptr t = ::create_torrent(&file); @@ -427,15 +428,15 @@ void test_fastresume() entry resume; { session ses; + ses.set_alert_mask(alert::all_categories); torrent_handle h = ses.add_torrent(boost::intrusive_ptr(new torrent_info(*t)) , "tmp1", entry() , storage_mode_compact); - h.rename_file(0, "testing_renamed_files"); - for (int i = 0; i < 10; ++i) { + print_alerts(ses, "ses"); test_sleep(1000); torrent_status s = h.status(); if (s.progress == 1.0f) @@ -448,16 +449,15 @@ void test_fastresume() ses.remove_torrent(h, session::delete_files); } TEST_CHECK(!exists("tmp1/temporary")); - TEST_CHECK(resume.dict().find("mapped_files") != resume.dict().end()); resume.print(std::cout); + // make sure the fast resume check fails! since we removed the file { session ses; ses.set_alert_mask(alert::all_categories); torrent_handle h = ses.add_torrent(t, "tmp1", resume , storage_mode_compact); - std::auto_ptr a = ses.pop_alert(); ptime end = time_now() + seconds(20); while (a.get() == 0 || dynamic_cast(a.get()) == 0) @@ -473,10 +473,71 @@ void test_fastresume() } TEST_CHECK(dynamic_cast(a.get()) != 0); } + remove_all("tmp1"); +} + +void test_rename_file_in_fastresume() +{ + std::cout << "\n\n=== test rename file in fastresume ===" << std::endl; + remove_all("tmp2"); + create_directory("tmp2"); + std::ofstream file("tmp2/temporary"); + boost::intrusive_ptr t = ::create_torrent(&file); + file.close(); + TEST_CHECK(exists("tmp2/temporary")); + + entry resume; + { + session ses; + ses.set_alert_mask(alert::all_categories); + + torrent_handle h = ses.add_torrent(boost::intrusive_ptr(new torrent_info(*t)) + , "tmp2", entry() + , storage_mode_compact); + + h.rename_file(0, "testing_renamed_files"); + for (int i = 0; i < 10; ++i) + { + print_alerts(ses, "ses"); + test_sleep(1000); + torrent_status s = h.status(); + if (s.progress == 1.0f) + { + std::cout << "progress: 1.0f" << std::endl; + break; + } + } + resume = h.write_resume_data(); + ses.remove_torrent(h); + } + TEST_CHECK(!exists("tmp2/temporary")); + TEST_CHECK(exists("tmp2/testing_renamed_files")); + TEST_CHECK(resume.dict().find("mapped_files") != resume.dict().end()); + resume.print(std::cout); + + // make sure the fast resume check succeeds, even though we renamed the file + { + session ses; + ses.set_alert_mask(alert::all_categories); + torrent_handle h = ses.add_torrent(t, "tmp2", resume + , storage_mode_compact); + + for (int i = 0; i < 5; ++i) + { + print_alerts(ses, "ses"); + test_sleep(1000); + } + torrent_status stat = h.status(); + TEST_CHECK(stat.state == torrent_status::seeding); + } + remove_all("tmp2"); } int test_main() { + test_fastresume(); + test_rename_file_in_fastresume(); + std::vector test_paths; char* env = std::getenv("TORRENT_TEST_PATHS"); if (env == 0) @@ -495,8 +556,6 @@ int test_main() std::for_each(test_paths.begin(), test_paths.end(), bind(&run_test, _1)); - test_fastresume(); - return 0; }