diff --git a/docs/manual.rst b/docs/manual.rst index b99a54104..bcd14f357 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -253,7 +253,7 @@ add_torrent() sha1_hash info_hash; char const* name; fs::path save_path; - entry const* resume_data; + std::vector* resume_data; storage_mode_t storage_mode; bool paused; bool auto_managed; @@ -289,7 +289,8 @@ torrent. The optional parameter, ``resume_data`` can be given if up to date fast-resume data is available. The fast-resume data can be acquired from a running torrent by calling -`save_resume_data()`_ on `torrent_handle`_. See `fast resume`_. +`save_resume_data()`_ on `torrent_handle`_. See `fast resume`_. The ``vector`` that is +passed in will be swapped into the running torrent instance with ``std::vector::swap()``. The ``storage_mode`` parameter refers to the layout of the storage for this torrent. There are 3 different modes: @@ -4416,7 +4417,7 @@ this:: virtual size_type read(char* buf, int slot, int offset, int size) = 0; virtual void write(const char* buf, int slot, int offset, int size) = 0; virtual bool move_storage(fs::path save_path) = 0; - virtual bool verify_resume_data(entry& rd, std::string& error) = 0; + virtual bool verify_resume_data(lazy_entry& rd, std::string& error) = 0; virtual void write_resume_data(entry& rd) const = 0; virtual void move_slot(int src_slot, int dst_slot) = 0; virtual void swap_slots(int slot1, int slot2) = 0; diff --git a/examples/client_test.cpp b/examples/client_test.cpp index d7477eeb8..fc78f67f4 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -66,6 +66,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/ip_filter.hpp" #include "libtorrent/magnet_uri.hpp" #include "libtorrent/bitfield.hpp" +#include "libtorrent/file.hpp" using boost::bind; @@ -485,19 +486,17 @@ void add_torrent(libtorrent::session& ses std::cout << t->name() << "\n"; - entry resume_data; - std::stringstream s; - s << t->name() << ".fastresume"; - boost::filesystem::ifstream resume_file(save_path / s.str(), std::ios_base::binary); - resume_file.unsetf(std::ios_base::skipws); - resume_data = bdecode( - std::istream_iterator(resume_file) - , std::istream_iterator()); - add_torrent_params p; + lazy_entry resume_data; + + std::string filename = (save_path / (t->name() + ".fastresume")).string(); + + std::vector buf; + if (load_file(filename.c_str(), buf) == 0) + p.resume_data = &buf; + p.ti = t; p.save_path = save_path; - p.resume_data = &resume_data; p.storage_mode = compact_mode ? storage_mode_compact : storage_mode_sparse; p.paused = true; p.duplicate_is_error = false; diff --git a/include/libtorrent/file.hpp b/include/libtorrent/file.hpp index 8a03c5294..19d69e603 100644 --- a/include/libtorrent/file.hpp +++ b/include/libtorrent/file.hpp @@ -34,7 +34,8 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_FILE_HPP_INCLUDED #include -#include +#include +#include #ifdef _MSC_VER #pragma warning(push, 1) @@ -54,10 +55,7 @@ namespace libtorrent { namespace fs = boost::filesystem; - struct TORRENT_EXPORT file_error: std::runtime_error - { - file_error(std::string const& msg): std::runtime_error(msg) {} - }; + int load_file(fs::path const& filename, std::vector& v); class TORRENT_EXPORT file: public boost::noncopyable { diff --git a/include/libtorrent/lazy_entry.hpp b/include/libtorrent/lazy_entry.hpp index c40d87bcc..ffd4337e4 100644 --- a/include/libtorrent/lazy_entry.hpp +++ b/include/libtorrent/lazy_entry.hpp @@ -170,7 +170,7 @@ namespace libtorrent return m_size; } - // end points one byte passed end + // end points one byte passed last byte void set_end(char const* end) { TORRENT_ASSERT(end > m_begin); diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index 7c8075d4f..d95782d79 100644 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -140,7 +140,7 @@ namespace libtorrent sha1_hash info_hash; char const* name; fs::path save_path; - entry const* resume_data; + std::vector* resume_data; storage_mode_t storage_mode; bool paused; bool auto_managed; diff --git a/include/libtorrent/storage.hpp b/include/libtorrent/storage.hpp index 8a7bb15a8..1733abe8a 100644 --- a/include/libtorrent/storage.hpp +++ b/include/libtorrent/storage.hpp @@ -133,7 +133,7 @@ namespace libtorrent virtual bool move_storage(fs::path save_path) = 0; // verify storage dependent fast resume entries - virtual bool verify_resume_data(entry const& rd, std::string& error) = 0; + virtual bool verify_resume_data(lazy_entry const& rd, std::string& error) = 0; // write storage dependent fast resume entries virtual bool write_resume_data(entry& rd) const = 0; @@ -212,7 +212,7 @@ namespace libtorrent boost::intrusive_ptr info() const { return m_info; } void write_resume_data(entry& rd) const; - void async_check_fastresume(entry const* resume_data + void async_check_fastresume(lazy_entry const* resume_data , boost::function const& handler); void async_check_files(boost::function const& handler); @@ -259,7 +259,7 @@ namespace libtorrent fs::path save_path() const; - bool verify_resume_data(entry const& rd, std::string& error) + bool verify_resume_data(lazy_entry const& rd, std::string& error) { return m_storage->verify_resume_data(rd, error); } bool is_allocating() const @@ -282,7 +282,7 @@ namespace libtorrent // the error message indicates that the fast resume data was rejected // if 'fatal_disk_error' is returned, the error message indicates what // when wrong in the disk access - int check_fastresume(entry const& rd, std::string& error); + int check_fastresume(lazy_entry const& rd, std::string& error); // this function returns true if the checking is complete int check_files(int& current_slot, int& have_piece, std::string& error); diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 971a4f1bc..cf834e833 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -107,7 +107,7 @@ namespace libtorrent , int block_size , storage_constructor_type sc , bool paused - , entry const* resume_data + , std::vector* resume_data , int seq , bool auto_managed); @@ -124,12 +124,14 @@ namespace libtorrent , int block_size , storage_constructor_type sc , bool paused - , entry const* resume_data + , std::vector* resume_data , int seq , bool auto_managed); ~torrent(); + void parse_resume_data(std::vector* resume_data); + // starts the announce timer void start(); @@ -564,7 +566,7 @@ namespace libtorrent torrent_handle get_handle(); void write_resume_data(entry& rd) const; - void read_resume_data(entry const& rd); + void read_resume_data(lazy_entry const& rd); // LOGGING #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING @@ -787,7 +789,9 @@ namespace libtorrent // error message std::string m_error; - entry m_resume_data; + // used if there is any resume data + std::vector m_resume_data; + lazy_entry m_resume_entry; // if the torrent is started without metadata, it may // still be given a name until the metadata is received diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index 2845acee7..adebdcf13 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -1048,7 +1048,7 @@ namespace libtorrent #ifdef TORRENT_DISK_STATS m_log << log_time() << " check fastresume" << std::endl; #endif - entry const* rd = (entry const*)j.buffer; + lazy_entry const* rd = (lazy_entry const*)j.buffer; TORRENT_ASSERT(rd != 0); ret = j.storage->check_fastresume(*rd, j.str); break; diff --git a/src/file.cpp b/src/file.cpp index 46d0e24e3..85d31b8a2 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -70,6 +70,7 @@ BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8); #include "libtorrent/file.hpp" #include #include +#include #ifndef O_BINARY #define O_BINARY 0 @@ -130,9 +131,22 @@ namespace namespace libtorrent { - namespace fs = boost::filesystem; + int load_file(fs::path const& filename, std::vector& v) + { + file f; + if (!f.open(filename, file::in)) return -1; + f.seek(0, file::end); + size_type s = f.tell(); + if (s > 5000000) return -2; + v.resize(s); + f.seek(0); + size_type read = f.read(&v[0], s); + if (read != s) return -3; + return 0; + } + const file::open_mode file::in(mode_in); const file::open_mode file::out(mode_out); @@ -160,7 +174,6 @@ namespace libtorrent bool open(fs::path const& path, int mode) { - TORRENT_ASSERT(path.is_complete()); close(); #if defined(_WIN32) && defined(UNICODE) std::wstring wpath(safe_convert(path.native_file_string())); diff --git a/src/mapped_storage.cpp b/src/mapped_storage.cpp index 97d961ab9..90fadd5b1 100644 --- a/src/mapped_storage.cpp +++ b/src/mapped_storage.cpp @@ -560,34 +560,32 @@ namespace libtorrent return false; } - bool verify_resume_data(entry const& rd, std::string& error) + bool verify_resume_data(lazy_entry const& rd, std::string& error) { - if (rd.type() != entry::dictionary_t) + if (rd.type() != lazy_entry::dict_t) { - error = "invalid fastresume file"; + error = "invalid fastresume file (not a dictionary)"; return true; } std::vector > file_sizes; - entry const* file_sizes_ent = rd.find_key("file sizes"); - if (file_sizes_ent == 0 || file_sizes_ent->type() != entry::list_t) + lazy_entry const* file_sizes_ent = rd.dict_find_list("file sizes"); + if (file_sizes_ent == 0) { error = "missing or invalid 'file sizes' entry in resume data"; return false; } - entry::list_type const& l = file_sizes_ent->list(); - - for (entry::list_type::const_iterator i = l.begin(); - i != l.end(); ++i) + for (int i = 0; i < file_sizes_ent->list_size(); ++i) { - if (i->type() != entry::list_t) break; - entry::list_type const& pair = i->list(); - if (pair.size() != 2 || pair.front().type() != entry::int_t - || pair.back().type() != entry::int_t) - break; + lazy_entry const* e = file_sizes_ent->list_at(i); + if (e->type() != lazy_entry::list_t + || e->list_size() != 2 + || e->list_at(0)->type() != lazy_entry::int_t + || e->list_at(1)->type() != lazy_entry::int_t) + continue; file_sizes.push_back(std::pair( - pair.front().integer(), pair.back().integer())); + e->list_int_value_at(0), std::time_t(e->list_int_value_at(1)))); } if (file_sizes.empty()) @@ -596,24 +594,30 @@ namespace libtorrent return false; } - entry const* slots_ent = rd.find_key("slots"); - if (slots_ent == 0 || slots_ent->type() != entry::list_t) + lazy_entry const* slots = rd.dict_find_list("slots"); + if (slots == 0) { error = "missing or invalid 'slots' entry in resume data"; return false; } - entry::list_type const& slots = slots_ent->list(); - bool seed = int(slots.size()) == files().num_pieces() - && std::find_if(slots.begin(), slots.end() - , boost::bind(std::less() - , boost::bind((size_type const& (entry::*)() const) - &entry::integer, _1), 0)) == slots.end(); + bool seed = false; + + if (int(slots->list_size()) == m_files.num_pieces()) + { + bool seed = true; + for (int i = 0; i < slots->list_size(); ++i) + { + lazy_entry const* e = slots->list_at(i); + if (e->list_int_value_at(i, -1) >= 0) continue; + seed = false; + break; + } + } bool full_allocation_mode = false; - entry const* allocation_mode = rd.find_key("allocation"); - if (allocation_mode && allocation_mode->type() == entry::string_t) - full_allocation_mode = allocation_mode->string() == "full"; + if (rd.dict_find_string_value("allocation") == "full") + full_allocation_mode = true; if (seed) { @@ -640,7 +644,6 @@ namespace libtorrent return false; } } - return true; } return match_filesizes(files(), m_save_path, file_sizes diff --git a/src/session.cpp b/src/session.cpp index b9e5f3c4c..194af5b73 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -257,7 +257,12 @@ namespace libtorrent add_torrent_params p(sc); p.ti = tip; p.save_path = save_path; - p.resume_data = &resume_data; + std::vector buf; + if (resume_data.type() != entry::undefined_t) + { + bencode(std::back_inserter(buf), resume_data); + p.resume_data = &buf; + } p.storage_mode = storage_mode; p.paused = paused; return m_impl->add_torrent(p); @@ -275,7 +280,12 @@ namespace libtorrent add_torrent_params p(sc); p.ti = ti; p.save_path = save_path; - p.resume_data = &resume_data; + std::vector buf; + if (resume_data.type() != entry::undefined_t) + { + bencode(std::back_inserter(buf), resume_data); + p.resume_data = &buf; + } p.storage_mode = storage_mode; p.paused = paused; p.userdata = userdata; diff --git a/src/storage.cpp b/src/storage.cpp index af71fcfaf..d6ecd4e71 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -422,7 +422,7 @@ namespace libtorrent bool move_slot(int src_slot, int dst_slot); bool swap_slots(int slot1, int slot2); bool swap_slots3(int slot1, int slot2, int slot3); - bool verify_resume_data(entry const& rd, std::string& error); + bool verify_resume_data(lazy_entry const& rd, std::string& error); bool write_resume_data(entry& rd) const; sha1_hash hash_for_slot(int slot, partial_hash& ph, int piece_size); @@ -685,34 +685,32 @@ namespace libtorrent return false; } - bool storage::verify_resume_data(entry const& rd, std::string& error) + bool storage::verify_resume_data(lazy_entry const& rd, std::string& error) { - if (rd.type() != entry::dictionary_t) + if (rd.type() != lazy_entry::dict_t) { error = "invalid fastresume file (not a dictionary)"; return true; } std::vector > file_sizes; - entry const* file_sizes_ent = rd.find_key("file sizes"); - if (file_sizes_ent == 0 || file_sizes_ent->type() != entry::list_t) + lazy_entry const* file_sizes_ent = rd.dict_find_list("file sizes"); + if (file_sizes_ent == 0) { error = "missing or invalid 'file sizes' entry in resume data"; return false; } - entry::list_type const& l = file_sizes_ent->list(); - - for (entry::list_type::const_iterator i = l.begin(); - i != l.end(); ++i) + for (int i = 0; i < file_sizes_ent->list_size(); ++i) { - if (i->type() != entry::list_t) break; - entry::list_type const& pair = i->list(); - if (pair.size() != 2 || pair.front().type() != entry::int_t - || pair.back().type() != entry::int_t) - break; + lazy_entry const* e = file_sizes_ent->list_at(i); + if (e->type() != lazy_entry::list_t + || e->list_size() != 2 + || e->list_at(0)->type() != lazy_entry::int_t + || e->list_at(1)->type() != lazy_entry::int_t) + continue; file_sizes.push_back(std::pair( - pair.front().integer(), std::time_t(pair.back().integer()))); + e->list_int_value_at(0), std::time_t(e->list_int_value_at(1)))); } if (file_sizes.empty()) @@ -721,32 +719,38 @@ namespace libtorrent return false; } - entry const* slots_ent = rd.find_key("slots"); - if (slots_ent == 0 || slots_ent->type() != entry::list_t) + lazy_entry const* slots = rd.dict_find_list("slots"); + if (slots == 0) { error = "missing or invalid 'slots' entry in resume data"; return false; } - entry::list_type const& slots = slots_ent->list(); - bool seed = int(slots.size()) == m_files.num_pieces() - && std::find_if(slots.begin(), slots.end() - , boost::bind(std::less() - , boost::bind((size_type const& (entry::*)() const) - &entry::integer, _1), 0)) == slots.end(); + bool seed = false; + + if (int(slots->list_size()) == m_files.num_pieces()) + { + bool seed = true; + for (int i = 0; i < slots->list_size(); ++i) + { + lazy_entry const* e = slots->list_at(i); + if (e->list_int_value_at(i, -1) >= 0) continue; + seed = false; + break; + } + } bool full_allocation_mode = false; - entry const* allocation_mode = rd.find_key("allocation"); - if (allocation_mode && allocation_mode->type() == entry::string_t) - full_allocation_mode = allocation_mode->string() == "full"; + if (rd.dict_find_string_value("allocation") == "full") + full_allocation_mode = true; if (seed) { - if (m_files.num_files() != (int)file_sizes.size()) + if (files().num_files() != (int)file_sizes.size()) { error = "the number of files does not match the torrent (num: " + boost::lexical_cast(file_sizes.size()) + " actual: " - + boost::lexical_cast(m_files.num_files()) + ")"; + + boost::lexical_cast(files().num_files()) + ")"; return false; } @@ -1300,7 +1304,7 @@ namespace libtorrent m_io_thread.add_job(j, handler); } - void piece_manager::async_check_fastresume(entry const* resume_data + void piece_manager::async_check_fastresume(lazy_entry const* resume_data , boost::function const& handler) { TORRENT_ASSERT(resume_data != 0); @@ -1783,7 +1787,7 @@ namespace libtorrent // isn't return false and the full check // will be run int piece_manager::check_fastresume( - entry const& rd, std::string& error) + lazy_entry const& rd, std::string& error) { boost::recursive_mutex::scoped_lock lock(m_mutex); @@ -1792,29 +1796,25 @@ namespace libtorrent TORRENT_ASSERT(m_files.piece_length() > 0); // if we don't have any resume data, return - if (rd.type() == entry::undefined_t) return check_no_fastresume(error); + if (rd.type() == lazy_entry::none_t) return check_no_fastresume(error); - if (rd.type() != entry::dictionary_t) + if (rd.type() != lazy_entry::dict_t) { - error = "invalid fastresume data (not a bencoded dictionary)"; + error = "invalid fastresume data (not a dictionary)"; return check_no_fastresume(error); } int block_size = (std::min)(16 * 1024, m_files.piece_length()); - entry const* blocks_per_piece_ent = rd.find_key("blocks per piece"); - if (blocks_per_piece_ent != 0 - && blocks_per_piece_ent->type() == entry::int_t - && blocks_per_piece_ent->integer() != m_files.piece_length() / block_size) + int blocks_per_piece = rd.dict_find_int_value("blocks per piece", -1); + if (blocks_per_piece != -1 + && blocks_per_piece != m_files.piece_length() / block_size) { error = "invalid 'blocks per piece' entry"; return check_no_fastresume(error); } storage_mode_t storage_mode = storage_mode_compact; - entry const* allocation = rd.find_key("allocation"); - if (allocation != 0 - && allocation->type() == entry::string_t - && allocation->string() != "compact") + if (rd.dict_find_string_value("allocation") != "compact") storage_mode = storage_mode_sparse; // assume no piece is out of place (i.e. in a slot @@ -1823,20 +1823,20 @@ namespace libtorrent // if we don't have a piece map, we need the slots // if we're in compact mode, we also need the slots map - if (storage_mode == storage_mode_compact || rd.find_key("pieces") == 0) + if (storage_mode == storage_mode_compact || rd.dict_find("pieces") == 0) { // read slots map - entry const* slots = rd.find_key("slots"); - if (slots == 0 || slots->type() != entry::list_t) + lazy_entry const* slots = rd.dict_find_list("slots"); + if (slots == 0) { error = "missing slot list"; return check_no_fastresume(error); } - if ((int)slots->list().size() > m_files.num_pieces()) + if ((int)slots->list_size() > m_files.num_pieces()) { error = "file has more slots than torrent (slots: " - + boost::lexical_cast(slots->list().size()) + " size: " + + boost::lexical_cast(slots->list_size()) + " size: " + boost::lexical_cast(m_files.num_pieces()) + " )"; return check_no_fastresume(error); } @@ -1846,17 +1846,16 @@ namespace libtorrent int num_pieces = int(m_files.num_pieces()); m_slot_to_piece.resize(num_pieces, unallocated); m_piece_to_slot.resize(num_pieces, has_no_slot); - int slot = 0; - for (entry::list_type::const_iterator i = slots->list().begin(); - i != slots->list().end(); ++i, ++slot) + for (int i = 0; i < slots->list_size(); ++i) { - if (i->type() != entry::int_t) + lazy_entry const* e = slots->list_at(i); + if (e->type() != lazy_entry::int_t) { error = "invalid entry type in slot list"; return check_no_fastresume(error); } - int index = int(i->integer()); + int index = int(e->int_value()); if (index >= num_pieces || index < -2) { error = "too high index number in slot map (index: " @@ -1866,37 +1865,36 @@ namespace libtorrent } if (index >= 0) { - m_slot_to_piece[slot] = index; - m_piece_to_slot[index] = slot; - if (slot != index) out_of_place = true; + m_slot_to_piece[i] = index; + m_piece_to_slot[index] = i; + if (i != index) out_of_place = true; } else if (index == unassigned) { if (m_storage_mode == storage_mode_compact) - m_free_slots.push_back(slot); + m_free_slots.push_back(i); } else { TORRENT_ASSERT(index == unallocated); if (m_storage_mode == storage_mode_compact) - m_unallocated_slots.push_back(slot); + m_unallocated_slots.push_back(i); } } } else { - int slot = 0; - for (entry::list_type::const_iterator i = slots->list().begin(); - i != slots->list().end(); ++i, ++slot) + for (int i = 0; i < slots->list_size(); ++i) { - if (i->type() != entry::int_t) + lazy_entry const* e = slots->list_at(i); + if (e->type() != lazy_entry::int_t) { error = "invalid entry type in slot list"; return check_no_fastresume(error); } - int index = int(i->integer()); - if (index != slot && index >= 0) + int index = int(e->int_value()); + if (index != i && index >= 0) { error = "invalid slot index"; return check_no_fastresume(error); @@ -1937,17 +1935,17 @@ namespace libtorrent else if (m_storage_mode == storage_mode_compact) { // read piece map - entry const* pieces = rd.find_key("pieces"); - if (pieces == 0 || pieces->type() != entry::string_t) + lazy_entry const* pieces = rd.dict_find("pieces"); + if (pieces == 0 || pieces->type() != lazy_entry::string_t) { error = "missing pieces entry"; return check_no_fastresume(error); } - if ((int)pieces->string().size() != m_files.num_pieces()) + if ((int)pieces->string_length() != m_files.num_pieces()) { error = "file has more slots than torrent (slots: " - + boost::lexical_cast(pieces->string().size()) + " size: " + + boost::lexical_cast(pieces->string_length()) + " size: " + boost::lexical_cast(m_files.num_pieces()) + " )"; return check_no_fastresume(error); } @@ -1955,7 +1953,7 @@ namespace libtorrent int num_pieces = int(m_files.num_pieces()); m_slot_to_piece.resize(num_pieces, unallocated); m_piece_to_slot.resize(num_pieces, has_no_slot); - std::string const& have_pieces = pieces->string(); + char const* have_pieces = pieces->string_ptr(); for (int i = 0; i < num_pieces; ++i) { if (have_pieces[i] & 1) diff --git a/src/torrent.cpp b/src/torrent.cpp index 67bd9f558..048b9de41 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -144,7 +144,7 @@ namespace libtorrent , int block_size , storage_constructor_type sc , bool paused - , entry const* resume_data + , std::vector* resume_data , int seq , bool auto_managed) : m_policy(this) @@ -203,7 +203,7 @@ namespace libtorrent , m_has_incoming(false) , m_files_checked(false) { - if (resume_data) m_resume_data = *resume_data; + parse_resume_data(resume_data); } torrent::torrent( @@ -217,7 +217,7 @@ namespace libtorrent , int block_size , storage_constructor_type sc , bool paused - , entry const* resume_data + , std::vector* resume_data , int seq , bool auto_managed) : m_policy(this) @@ -274,7 +274,7 @@ namespace libtorrent , m_connections_initialized(false) , m_has_incoming(false) { - if (resume_data) m_resume_data = *resume_data; + parse_resume_data(resume_data); #ifndef NDEBUG m_files_checked = false; #endif @@ -289,6 +289,25 @@ namespace libtorrent } } + void torrent::parse_resume_data(std::vector* resume_data) + { + if (!resume_data) return; + m_resume_data.swap(*resume_data); + if (lazy_bdecode(&m_resume_data[0], &m_resume_data[0] + + m_resume_data.size(), m_resume_entry) != 0) + { + std::vector().swap(m_resume_data); + if (m_ses.m_alerts.should_post(alert::warning)) + { + m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), "parse failed")); +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING + (*m_ses.m_logger) << "fastresume data for " + << torrent_file().name() << " rejected: parse failed\n"; +#endif + } + } + } + void torrent::start() { boost::weak_ptr self(shared_from_this()); @@ -429,18 +448,17 @@ namespace libtorrent m_state = torrent_status::queued_for_checking; - if (m_resume_data.type() == entry::dictionary_t) + if (m_resume_entry.type() == lazy_entry::dict_t) { char const* error = 0; - entry const* file_format = m_resume_data.find_key("file-format"); - if (file_format->string() != "libtorrent resume file") + if (m_resume_entry.dict_find_string_value("file-format") != "libtorrent resume file") error = "invalid file format tag"; - entry const* info_hash = m_resume_data.find_key("info-hash"); - if (!error && (info_hash == 0 || info_hash->type() != entry::string_t)) + std::string info_hash = m_resume_entry.dict_find_string_value("info-hash"); + if (!error && info_hash.empty()) error = "missing info-hash"; - if (!error && sha1_hash(info_hash->string()) != m_torrent_file->info_hash()) + if (!error && sha1_hash(info_hash) != m_torrent_file->info_hash()) error = "mismatching info-hash"; if (error && m_ses.m_alerts.should_post(alert::warning)) @@ -453,11 +471,18 @@ namespace libtorrent #endif } - if (error) m_resume_data = entry(); - else read_resume_data(m_resume_data); + if (error) + { + std::vector().swap(m_resume_data); + m_resume_entry = lazy_entry(); + } + else + { + read_resume_data(m_resume_entry); + } } - m_storage->async_check_fastresume(&m_resume_data + m_storage->async_check_fastresume(&m_resume_entry , bind(&torrent::on_resume_data_checked , shared_from_this(), _1, _2)); } @@ -483,54 +508,41 @@ namespace libtorrent return; } - // parse out "peers" from the resume data and add them to the peer list - entry const* peers_entry = m_resume_data.find_key("peers"); - if (peers_entry && peers_entry->type() == entry::list_t) + if (m_resume_entry.type() == lazy_entry::dict_t) { - peer_id id; - std::fill(id.begin(), id.end(), 0); - entry::list_type const& peer_list = peers_entry->list(); - - for (entry::list_type::const_iterator i = peer_list.begin(); - i != peer_list.end(); ++i) + // parse out "peers" from the resume data and add them to the peer list + if (lazy_entry const* peers_entry = m_resume_entry.dict_find_list("peers")) { - if (i->type() != entry::dictionary_t) continue; - entry const* ip = i->find_key("ip"); - entry const* port = i->find_key("port"); - if (ip == 0 || port == 0 - || ip->type() != entry::string_t - || port->type() != entry::int_t) - continue; - tcp::endpoint a( - address::from_string(ip->string()) - , (unsigned short)port->integer()); - m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0); + peer_id id(0); + + for (int i = 0; i < peers_entry->list_size(); ++i) + { + lazy_entry const* e = peers_entry->list_at(i); + if (e->type() != lazy_entry::dict_t) continue; + std::string ip = e->dict_find_string_value("ip"); + int port = e->dict_find_int_value("port"); + if (ip.empty() || port == 0) continue; + tcp::endpoint a(address::from_string(ip), (unsigned short)port); + m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0); + } } - } - // parse out "banned_peers" and add them as banned - entry const* banned_peers_entry = m_resume_data.find_key("banned_peers"); - if (banned_peers_entry != 0 && banned_peers_entry->type() == entry::list_t) - { - peer_id id; - std::fill(id.begin(), id.end(), 0); - entry::list_type const& peer_list = banned_peers_entry->list(); - - for (entry::list_type::const_iterator i = peer_list.begin(); - i != peer_list.end(); ++i) + // parse out "banned_peers" and add them as banned + if (lazy_entry const* banned_peers_entry = m_resume_entry.dict_find_list("banned_peers")) { - if (i->type() != entry::dictionary_t) continue; - entry const* ip = i->find_key("ip"); - entry const* port = i->find_key("port"); - if (ip == 0 || port == 0 - || ip->type() != entry::string_t - || port->type() != entry::int_t) - continue; - tcp::endpoint a( - address::from_string(ip->string()) - , (unsigned short)port->integer()); - policy::peer* p = m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0); - if (p) p->banned = true; + peer_id id(0); + + for (int i = 0; i < banned_peers_entry->list_size(); ++i) + { + lazy_entry const* e = banned_peers_entry->list_at(i); + if (e->type() != lazy_entry::dict_t) continue; + std::string ip = e->dict_find_string_value("ip"); + int port = e->dict_find_int_value("port"); + if (ip.empty() || port == 0) continue; + tcp::endpoint a(address::from_string(ip), (unsigned short)port); + policy::peer* p = m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0); + if (p) p->banned = true; + } } } @@ -551,17 +563,15 @@ namespace libtorrent // there are either no files for this torrent // or the resume_data was accepted - if (!fastresume_rejected) + if (!fastresume_rejected && m_resume_entry.type() == lazy_entry::dict_t) { - TORRENT_ASSERT(m_resume_data.type() == entry::dictionary_t); - // parse have bitmask - entry const* pieces = m_resume_data.find_key("pieces"); - if (pieces && pieces->type() == entry::string_t - && int(pieces->string().length()) == m_torrent_file->num_pieces()) + lazy_entry const* pieces = m_resume_entry.dict_find("pieces"); + if (pieces && pieces->type() == lazy_entry::string_t + && int(pieces->string_length()) == m_torrent_file->num_pieces()) { - std::string const& pieces_str = pieces->string(); - for (int i = 0, end(pieces_str.size()); i < end; ++i) + char const* pieces_str = pieces->string_ptr(); + for (int i = 0, end(pieces->string_length()); i < end; ++i) { if ((pieces_str[i] & 1) == 0) continue; m_picker->we_have(i); @@ -572,27 +582,20 @@ namespace libtorrent int num_blocks_per_piece = static_cast(torrent_file().piece_length()) / block_size(); - entry const* unfinished_ent = m_resume_data.find_key("unfinished"); - if (unfinished_ent != 0 && unfinished_ent->type() == entry::list_t) + if (lazy_entry const* unfinished_ent = m_resume_entry.dict_find_list("unfinished")) { - entry::list_type const& unfinished = unfinished_ent->list(); - int index = 0; - for (entry::list_type::const_iterator i = unfinished.begin(); - i != unfinished.end(); ++i, ++index) + for (int i = 0; i < unfinished_ent->list_size(); ++i) { - if (i->type() != entry::dictionary_t) continue; - entry const* piece = i->find_key("piece"); - if (piece == 0 || piece->type() != entry::int_t) continue; - int piece_index = int(piece->integer()); - if (piece_index < 0 || piece_index >= torrent_file().num_pieces()) - continue; + lazy_entry const* e = unfinished_ent->list_at(i); + if (e->type() != lazy_entry::dict_t) continue; + int piece = e->dict_find_int_value("piece", -1); + if (piece < 0 || piece > torrent_file().num_pieces()) continue; - if (m_picker->have_piece(piece_index)) - m_picker->we_dont_have(piece_index); + if (m_picker->have_piece(piece)) + m_picker->we_dont_have(piece); - entry const* bitmask_ent = i->find_key("bitmask"); - if (bitmask_ent == 0 || bitmask_ent->type() != entry::string_t) break; - std::string const& bitmask = bitmask_ent->string(); + std::string bitmask = e->dict_find_string_value("bitmask"); + if (bitmask.empty()) continue; const int num_bitmask_bytes = (std::max)(num_blocks_per_piece / 8, 1); if ((int)bitmask.size() != num_bitmask_bytes) continue; @@ -605,10 +608,10 @@ namespace libtorrent const int bit = j * 8 + k; if (bits & (1 << k)) { - m_picker->mark_as_finished(piece_block(piece_index, bit), 0); - if (m_picker->is_piece_finished(piece_index)) - async_verify_piece(piece_index, bind(&torrent::piece_finished - , shared_from_this(), piece_index, _1)); + m_picker->mark_as_finished(piece_block(piece, bit), 0); + if (m_picker->is_piece_finished(piece)) + async_verify_piece(piece, bind(&torrent::piece_finished + , shared_from_this(), piece, _1)); } } } @@ -649,8 +652,9 @@ namespace libtorrent if (m_auto_managed) set_queue_position((std::numeric_limits::max)()); - m_resume_data = entry(); - m_storage->async_check_fastresume(&m_resume_data + std::vector().swap(m_resume_data); + m_resume_entry = lazy_entry(); + m_storage->async_check_fastresume(&m_resume_entry , bind(&torrent::on_force_recheck , shared_from_this(), _1, _2)); } @@ -2413,31 +2417,14 @@ namespace libtorrent } #endif - void torrent::read_resume_data(entry const& rd) + void torrent::read_resume_data(lazy_entry const& rd) { - entry const* e = 0; - e = rd.find_key("total_uploaded"); - m_total_uploaded = (e != 0 && e->type() == entry::int_t)?e->integer():0; - e = rd.find_key("total_downloaded"); - m_total_downloaded = (e != 0 && e->type() == entry::int_t)?e->integer():0; - - e = rd.find_key("active_time"); - m_active_time = seconds((e != 0 && e->type() == entry::int_t)?e->integer():0); - e = rd.find_key("seeding_time"); - m_seeding_time = seconds((e != 0 && e->type() == entry::int_t)?e->integer():0); - - e = rd.find_key("num_seeds"); - m_complete = (e != 0 && e->type() == entry::int_t)?e->integer():-1; - e = rd.find_key("num_downloaders"); - m_incomplete = (e != 0 && e->type() == entry::int_t)?e->integer():-1; - /* - m_total_uploaded = rd.find_int_value("total_uploaded"); - m_total_downloaded = rd.find_inte_value("total_downloaded"); - m_active_time = rd.find_int_value("active_time"); - m_seeding_time = rd.find_int_value("seeding_time"); - m_complete = rd.find_int_value("num_seeds", -1); - m_incomplete = rd.find_int_value("num_downloaders", -1); - */ + m_total_uploaded = rd.dict_find_int_value("total_uploaded"); + m_total_downloaded = rd.dict_find_int_value("total_downloaded"); + m_active_time = seconds(rd.dict_find_int_value("active_time")); + m_seeding_time = seconds(rd.dict_find_int_value("seeding_time")); + m_complete = rd.dict_find_int_value("num_seeds", -1); + m_incomplete = rd.dict_find_int_value("num_downloaders", -1); } void torrent::write_resume_data(entry& ret) const @@ -3332,8 +3319,8 @@ namespace libtorrent { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); - TORRENT_ASSERT(m_resume_data.type() == entry::dictionary_t - || m_resume_data.type() == entry::undefined_t); + TORRENT_ASSERT(m_resume_entry.type() == lazy_entry::dict_t + || m_resume_entry.type() == lazy_entry::none_t); TORRENT_ASSERT(m_bandwidth_queue[0].size() <= m_connections.size()); TORRENT_ASSERT(m_bandwidth_queue[1].size() <= m_connections.size()); diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 894b92a99..c1aa41e6a 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -58,6 +58,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/bencode.hpp" #include "libtorrent/hasher.hpp" #include "libtorrent/entry.hpp" +#include "libtorrent/file.hpp" namespace gr = boost::gregorian; @@ -282,16 +283,13 @@ namespace libtorrent , m_multifile(false) , m_private(false) { - size_type s = fs::file_size(fs::path(filename)); - // don't load torrent files larger than 2 MB - if (s > 2000000) return; - std::vector buf(s); - std::ifstream f(filename, std::ios_base::binary); - f.read(&buf[0], s); + std::vector buf; + int ret = load_file(filename, buf); + if (ret < 0) return; - std::string error; lazy_entry e; lazy_bdecode(&buf[0], &buf[0] + buf.size(), e); + std::string error; #ifndef BOOST_NO_EXCEPTIONS if (!parse_torrent_file(e, error)) throw invalid_torrent_file(); diff --git a/test/test_storage.cpp b/test/test_storage.cpp index d2f0a1d6d..925333f26 100644 --- a/test/test_storage.cpp +++ b/test/test_storage.cpp @@ -107,7 +107,7 @@ void run_storage_tests(boost::intrusive_ptr info , test_path, fp, io, default_storage_constructor, storage_mode); boost::mutex lock; - entry frd; + lazy_entry frd; pm->async_check_fastresume(&frd, &on_check_resume_data); ios.reset(); ios.run();