From 772f80e622e07d6c0a7005bb286266eb941f97b7 Mon Sep 17 00:00:00 2001 From: Andrew Resch Date: Mon, 2 Jun 2008 17:40:37 +0000 Subject: [PATCH] lt sync 2370 --- libtorrent/bindings/python/src/peer_info.cpp | 3 +- .../bindings/python/src/peer_plugin.cpp | 20 +- .../bindings/python/src/torrent_info.cpp | 16 +- .../bindings/python/src/torrent_status.cpp | 3 +- libtorrent/include/libtorrent/alert_types.hpp | 15 + .../include/libtorrent/aux_/session_impl.hpp | 4 - libtorrent/include/libtorrent/bitfield.hpp | 241 +++++++++++++ .../include/libtorrent/bt_peer_connection.hpp | 2 +- .../include/libtorrent/chained_buffer.hpp | 1 + .../include/libtorrent/create_torrent.hpp | 108 ++++-- .../include/libtorrent/disk_io_thread.hpp | 3 +- libtorrent/include/libtorrent/extensions.hpp | 3 +- libtorrent/include/libtorrent/file_pool.hpp | 1 + .../include/libtorrent/file_storage.hpp | 146 ++++++++ .../include/libtorrent/peer_connection.hpp | 7 +- libtorrent/include/libtorrent/peer_info.hpp | 5 +- .../include/libtorrent/piece_picker.hpp | 19 +- libtorrent/include/libtorrent/session.hpp | 2 +- .../include/libtorrent/session_settings.hpp | 6 + libtorrent/include/libtorrent/socket.hpp | 2 + libtorrent/include/libtorrent/storage.hpp | 32 +- libtorrent/include/libtorrent/time.hpp | 1 + libtorrent/include/libtorrent/torrent.hpp | 25 +- .../include/libtorrent/torrent_handle.hpp | 11 +- .../include/libtorrent/torrent_info.hpp | 171 ++-------- libtorrent/src/broadcast_socket.cpp | 2 + libtorrent/src/bt_peer_connection.cpp | 43 +-- libtorrent/src/create_torrent.cpp | 164 ++++----- libtorrent/src/disk_io_thread.cpp | 7 + libtorrent/src/file_pool.cpp | 10 + libtorrent/src/file_storage.cpp | 150 ++++++++ libtorrent/src/kademlia/node.cpp | 2 +- libtorrent/src/lazy_bdecode.cpp | 2 +- libtorrent/src/mapped_storage.cpp | 128 ++++--- libtorrent/src/natpmp.cpp | 2 + libtorrent/src/peer_connection.cpp | 38 +-- libtorrent/src/piece_picker.cpp | 36 +- libtorrent/src/policy.cpp | 123 ++++--- libtorrent/src/session_impl.cpp | 42 ++- libtorrent/src/storage.cpp | 323 ++++++++++-------- libtorrent/src/torrent.cpp | 204 ++++++++--- libtorrent/src/torrent_handle.cpp | 36 ++ libtorrent/src/torrent_info.cpp | 219 ++---------- libtorrent/src/web_peer_connection.cpp | 16 +- 44 files changed, 1497 insertions(+), 897 deletions(-) create mode 100644 libtorrent/include/libtorrent/bitfield.hpp create mode 100644 libtorrent/include/libtorrent/file_storage.hpp create mode 100644 libtorrent/src/file_storage.cpp diff --git a/libtorrent/bindings/python/src/peer_info.cpp b/libtorrent/bindings/python/src/peer_info.cpp index 3c22820fe..9ceeead7a 100755 --- a/libtorrent/bindings/python/src/peer_info.cpp +++ b/libtorrent/bindings/python/src/peer_info.cpp @@ -3,6 +3,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include +#include #include #include @@ -35,7 +36,7 @@ list get_pieces(peer_info const& pi) { list ret; - for (std::vector::const_iterator i = pi.pieces.begin() + for (bitfield::const_iterator i = pi.pieces.begin() , end(pi.pieces.end()); i != end; ++i) { ret.append(*i); diff --git a/libtorrent/bindings/python/src/peer_plugin.cpp b/libtorrent/bindings/python/src/peer_plugin.cpp index ddc94f16a..ea431c3d5 100755 --- a/libtorrent/bindings/python/src/peer_plugin.cpp +++ b/libtorrent/bindings/python/src/peer_plugin.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include using namespace boost::python; @@ -119,17 +120,26 @@ namespace return this->peer_plugin::on_have(index); } - bool on_bitfield(std::vector const& bitfield) + bool on_bitfield(list _bf) { + //Convert list to a bitfield + bitfield bf(len(_bf)); + for (int i = 0; i < len(_bf); ++i) + { + if (_bf[i]) + bf.set_bit(i); + else + bf.clear_bit(i); + } if (override f = this->get_override("on_bitfield")) - return f(bitfield); + return f(bf); else - return peer_plugin::on_bitfield(bitfield); + return peer_plugin::on_bitfield(bf); } - bool default_on_bitfield(std::vector const& bitfield) + bool default_on_bitfield(const bitfield &bf) { - return this->peer_plugin::on_bitfield(bitfield); + return this->peer_plugin::on_bitfield(bf); } bool on_request(peer_request const& req) diff --git a/libtorrent/bindings/python/src/torrent_info.cpp b/libtorrent/bindings/python/src/torrent_info.cpp index a9ba952d8..55e7fd6b9 100755 --- a/libtorrent/bindings/python/src/torrent_info.cpp +++ b/libtorrent/bindings/python/src/torrent_info.cpp @@ -41,14 +41,14 @@ namespace return result; } - std::vector::const_iterator begin_files(torrent_info& i, bool storage) + file_storage::iterator begin_files(torrent_info& i) { - return i.begin_files(storage); + return i.begin_files(); } - std::vector::const_iterator end_files(torrent_info& i, bool storage) + file_storage::iterator end_files(torrent_info& i) { - return i.end_files(storage); + return i.end_files(); } //list files(torrent_info const& ti, bool storage) { @@ -57,7 +57,7 @@ namespace typedef std::vector list_type; - for (list_type::const_iterator i = ti.begin_files(storage); i != ti.end_files(storage); ++i) + for (list_type::const_iterator i = ti.begin_files(); i != ti.end_files(); ++i) result.append(*i); return result; @@ -70,10 +70,12 @@ void bind_torrent_info() { return_value_policy copy; - class_ >("torrent_info") + class_ >("torrent_info", no_init) .def(init()) .def(init()) - + .def(init()) + .def(init()) + .def("add_tracker", &torrent_info::add_tracker, (arg("url"), arg("tier")=0)) .def("add_url_seed", &torrent_info::add_url_seed) diff --git a/libtorrent/bindings/python/src/torrent_status.cpp b/libtorrent/bindings/python/src/torrent_status.cpp index 3947e156b..acccea668 100755 --- a/libtorrent/bindings/python/src/torrent_status.cpp +++ b/libtorrent/bindings/python/src/torrent_status.cpp @@ -4,6 +4,7 @@ #include #include +#include using namespace boost::python; using namespace libtorrent; @@ -12,7 +13,7 @@ object pieces(torrent_status const& s) { list result; - for (std::vector::const_iterator i(s.pieces->begin()), e(s.pieces->end()); i != e; ++i) + for (bitfield::const_iterator i(s.pieces->begin()), e(s.pieces->end()); i != e; ++i) result.append(*i); return result; diff --git a/libtorrent/include/libtorrent/alert_types.hpp b/libtorrent/include/libtorrent/alert_types.hpp index cb72cc6aa..042ec1683 100755 --- a/libtorrent/include/libtorrent/alert_types.hpp +++ b/libtorrent/include/libtorrent/alert_types.hpp @@ -53,6 +53,21 @@ namespace libtorrent torrent_handle handle; }; + struct TORRENT_EXPORT file_renamed_alert: torrent_alert + { + file_renamed_alert(torrent_handle const& h + , std::string const& name_ + , std::string const& msg) + : torrent_alert(h, alert::warning, msg) + , name(name_) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new file_renamed_alert(*this)); } + + std::string name; + }; + struct TORRENT_EXPORT tracker_alert: torrent_alert { tracker_alert(torrent_handle const& h diff --git a/libtorrent/include/libtorrent/aux_/session_impl.hpp b/libtorrent/include/libtorrent/aux_/session_impl.hpp index 20e2a9860..79abf3cc7 100644 --- a/libtorrent/include/libtorrent/aux_/session_impl.hpp +++ b/libtorrent/include/libtorrent/aux_/session_impl.hpp @@ -514,10 +514,6 @@ namespace libtorrent // port we'll bind the next outgoing socket to int m_next_port; - // the sequence number to assign to the - // next torrent that's added - int m_torrent_sequence; - #ifndef TORRENT_DISABLE_DHT boost::intrusive_ptr m_dht; dht_settings m_dht_settings; diff --git a/libtorrent/include/libtorrent/bitfield.hpp b/libtorrent/include/libtorrent/bitfield.hpp new file mode 100644 index 000000000..fe14cfe1c --- /dev/null +++ b/libtorrent/include/libtorrent/bitfield.hpp @@ -0,0 +1,241 @@ +/* + +Copyright (c) 2008, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_BITFIELD_HPP_INCLUDED +#define TORRENT_BITFIELD_HPP_INCLUDED + +#include "libtorrent/assert.hpp" +#include "libtorrent/config.hpp" + +namespace libtorrent +{ + struct TORRENT_EXPORT bitfield + { + bitfield(): m_bytes(0), m_size(0), m_own(false) {} + bitfield(int bits): m_bytes(0), m_size(0) + { resize(bits); } + bitfield(int bits, bool val): m_bytes(0), m_size(0) + { resize(bits, val); } + bitfield(char const* bytes, int bits): m_bytes(0), m_size(0) + { assign(bytes, bits); } + bitfield(bitfield const& rhs): m_bytes(0), m_size(0), m_own(false) + { assign(rhs.bytes(), rhs.size()); } + + void borrow_bytes(char* bytes, int bits) + { + dealloc(); + m_bytes = (unsigned char*)bytes; + m_size = bits; + m_own = false; + } + ~bitfield() { dealloc(); } + + void assign(char const* bytes, int bits) + { resize(bits); memcpy(m_bytes, bytes, (bits + 7) / 8); } + + bool operator[](int index) const + { return get_bit(index); } + + bool get_bit(int index) const + { + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < m_size); + return m_bytes[index / 8] & (0x80 >> (index & 7)); + } + + void clear_bit(int index) + { + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < m_size); + m_bytes[index / 8] &= ~(0x80 >> (index & 7)); + } + + void set_bit(int index) + { + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < m_size); + m_bytes[index / 8] |= (0x80 >> (index & 7)); + } + + std::size_t size() const { return m_size; } + bool empty() const { return m_size == 0; } + + char const* bytes() const { return (char*)m_bytes; } + + bitfield& operator=(bitfield const& rhs) + { + assign(rhs.bytes(), rhs.size()); + return *this; + } + + int count() const + { + // 0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111, + // 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111 + const static char num_bits[] = + { + 0, 1, 1, 2, 1, 2, 2, 3, + 1, 2, 2, 3, 2, 3, 3, 4 + }; + + int ret = 0; + const int num_bytes = m_size / 8; + for (int i = 0; i < num_bytes; ++i) + { + ret += num_bits[m_bytes[i] & 0xf] + num_bits[m_bytes[i] >> 4]; + } + + int rest = m_size - num_bytes * 8; + for (int i = 0; i < rest; ++i) + { + ret += (m_bytes[num_bytes] >> (7-i)) & 1; + } + TORRENT_ASSERT(ret <= m_size); + TORRENT_ASSERT(ret >= 0); + return ret; + } + + struct const_iterator + { + friend struct bitfield; + + typedef bool value_type; + typedef ptrdiff_t difference_type; + typedef bool const* pointer; + typedef bool& reference; + typedef std::forward_iterator_tag iterator_category; + + bool operator*() { return *byte & bit; } + const_iterator& operator++() { inc(); return *this; } + const_iterator operator++(int) + { const_iterator ret(*this); inc(); return ret; } + const_iterator& operator--() { dec(); return *this; } + const_iterator operator--(int) + { const_iterator ret(*this); dec(); return ret; } + + const_iterator(): byte(0), bit(0x80) {} + bool operator==(const_iterator const& rhs) const + { return byte == rhs.byte && bit == rhs.bit; } + + bool operator!=(const_iterator const& rhs) const + { return byte != rhs.byte || bit != rhs.bit; } + + private: + void inc() + { + TORRENT_ASSERT(byte); + if (bit == 0x01) + { + bit = 0x80; + ++byte; + } + else + { + bit >>= 1; + } + } + void dec() + { + TORRENT_ASSERT(byte); + if (bit == 0x80) + { + bit = 0x01; + --byte; + } + else + { + bit <<= 1; + } + } + const_iterator(unsigned char const* ptr, int offset) + : byte(ptr), bit(0x80 >> offset) {} + unsigned char const* byte; + int bit; + }; + + const_iterator begin() const { return const_iterator(m_bytes, 0); } + const_iterator end() const { return const_iterator(m_bytes + m_size / 8, m_size & 7); } + + void resize(int bits, bool val) + { + resize(bits); + if (val) set_all(); else clear_all(); + } + + void set_all() + { + memset(m_bytes, 0xff, (m_size + 7) / 8); + } + + void clear_all() + { + memset(m_bytes, 0x00, (m_size + 7) / 8); + } + + void resize(int bits) + { + const int bytes = (bits + 7) / 8; + if (m_bytes) + { + if (m_own) + { + m_bytes = (unsigned char*)realloc(m_bytes, bytes); + m_own = true; + } + else if (bits > m_size) + { + unsigned char* tmp = (unsigned char*)malloc(bytes); + memcpy(tmp, m_bytes, (std::min)((m_size + 7)/ 8, bytes)); + m_bytes = tmp; + m_own = true; + } + } + else + { + m_bytes = (unsigned char*)malloc(bytes); + m_own = true; + } + m_size = bits; + } + + private: + + void dealloc() { if (m_own) free(m_bytes); m_bytes = 0; } + unsigned char* m_bytes; + int m_size; // in bits + bool m_own; + }; + +} + +#endif // TORRENT_BITFIELD_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/bt_peer_connection.hpp b/libtorrent/include/libtorrent/bt_peer_connection.hpp index f82d5070c..370bd3ab8 100755 --- a/libtorrent/include/libtorrent/bt_peer_connection.hpp +++ b/libtorrent/include/libtorrent/bt_peer_connection.hpp @@ -209,7 +209,7 @@ namespace libtorrent void write_not_interested(); void write_request(peer_request const& r); void write_cancel(peer_request const& r); - void write_bitfield(std::vector const& bitfield); + void write_bitfield(bitfield const& bits); void write_have(int index); void write_piece(peer_request const& r, disk_buffer_holder& buffer); void write_handshake(); diff --git a/libtorrent/include/libtorrent/chained_buffer.hpp b/libtorrent/include/libtorrent/chained_buffer.hpp index 22eba1e97..caf2e89be 100644 --- a/libtorrent/include/libtorrent/chained_buffer.hpp +++ b/libtorrent/include/libtorrent/chained_buffer.hpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_CHAINED_BUFFER_HPP_INCLUDED #include +#include #if BOOST_VERSION < 103500 #include #else diff --git a/libtorrent/include/libtorrent/create_torrent.hpp b/libtorrent/include/libtorrent/create_torrent.hpp index c97174d4c..32c7a41f2 100644 --- a/libtorrent/include/libtorrent/create_torrent.hpp +++ b/libtorrent/include/libtorrent/create_torrent.hpp @@ -35,6 +35,12 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/bencode.hpp" #include "libtorrent/peer_id.hpp" +#include "libtorrent/file_storage.hpp" +#include "libtorrent/file_pool.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/storage.hpp" +#include "libtorrent/hasher.hpp" + #include #include #include @@ -44,8 +50,10 @@ POSSIBILITY OF SUCH DAMAGE. #endif #include +#include #include #include +#include #ifdef _MSC_VER #pragma warning(pop) @@ -56,26 +64,29 @@ namespace libtorrent namespace fs = boost::filesystem; namespace pt = boost::posix_time; - struct create_torrent + struct TORRENT_EXPORT create_torrent { - create_torrent(); + create_torrent(file_storage& fs, int piece_size); + create_torrent(file_storage& fs); entry generate() const; + file_storage const& files() const { return m_files; } + void set_comment(char const* str); void set_creator(char const* str); - void set_piece_size(int size); void set_hash(int index, sha1_hash const& h); - void add_file(fs::path file, size_type size); void add_url_seed(std::string const& url); void add_node(std::pair const& node); void add_tracker(std::string const& url, int tier = 0); - int num_pieces() const { return m_num_pieces; } - int piece_length() const { return m_piece_length; } - int piece_size(int i) const; + int num_pieces() const { return m_files.num_pieces(); } + int piece_length() const { return m_files.piece_length(); } + int piece_size(int i) const { return m_files.piece_size(i); } private: + file_storage& m_files; + // the urls to the trackers typedef std::pair announce_entry; std::vector m_urls; @@ -84,32 +95,15 @@ namespace libtorrent std::vector m_piece_hash; - // the length of one piece - // if this is 0, the torrent_info is - // in an uninitialized state - int m_piece_length; - - typedef std::pair file_entry; - // the list of files that this torrent consists of - std::vector m_files; - // dht nodes to add to the routing table/bootstrap from typedef std::vector > nodes_t; nodes_t m_nodes; - // the sum of all filesizes - size_type m_total_size; - - // the number of pieces in the torrent - int m_num_pieces; - // the hash that identifies this torrent // is mutable because it's calculated // lazily mutable sha1_hash m_info_hash; - std::string m_name; - // if a creation date is found in the torrent file // this will be set to that, otherwise it'll be // 1970, Jan 1 @@ -134,6 +128,72 @@ namespace libtorrent // be announced on the dht bool m_private; }; + + namespace detail + { + inline bool default_pred(boost::filesystem::path const&) { return true; } + + inline void nop(int i) {} + + template + void add_files_impl(file_storage& fs, boost::filesystem::path const& p + , boost::filesystem::path const& l, Pred pred) + { + using boost::filesystem::path; + using boost::filesystem::directory_iterator; + std::string const& leaf = l.leaf(); + if (leaf == ".." || leaf == ".") return; + if (!pred(l)) return; + path f(p / l); + if (is_directory(f)) + { + for (directory_iterator i(f), end; i != end; ++i) + add_files_impl(fs, p, l / i->leaf(), pred); + } + else + { + fs.add_file(l, file_size(f)); + } + } + } + + template + void add_files(file_storage& fs, boost::filesystem::path const& file, Pred p) + { + detail::add_files_impl(fs, complete(file).branch_path(), file.leaf(), p); + } + + inline void add_files(file_storage& fs, boost::filesystem::path const& file) + { + detail::add_files_impl(fs, complete(file).branch_path(), file.leaf(), detail::default_pred); + } + + template + void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p, Fun f) + { + file_pool fp; + boost::scoped_ptr st( + default_storage_constructor(const_cast(t.files()), p, fp)); + + // calculate the hash for all pieces + int num = t.num_pieces(); + std::vector buf(t.piece_length()); + for (int i = 0; i < num; ++i) + { + // read hits the disk and will block. Progress should + // be updated in between reads + st->read(&buf[0], i, 0, t.piece_size(i)); + hasher h(&buf[0], t.piece_size(i)); + t.set_hash(i, h.final()); + f(i); + } + } + + inline void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p) + { + set_piece_hashes(t, p, detail::nop); + } + } #endif diff --git a/libtorrent/include/libtorrent/disk_io_thread.hpp b/libtorrent/include/libtorrent/disk_io_thread.hpp index b66cc6014..198915588 100644 --- a/libtorrent/include/libtorrent/disk_io_thread.hpp +++ b/libtorrent/include/libtorrent/disk_io_thread.hpp @@ -82,6 +82,7 @@ namespace libtorrent , check_fastresume , check_files , save_resume_data + , rename_file }; action_t action; @@ -91,7 +92,7 @@ namespace libtorrent boost::intrusive_ptr storage; // arguments used for read and write int piece, offset; - // used for move_storage. On errors, this is set + // used for move_storage and rename_file. On errors, this is set // to the error message std::string str; diff --git a/libtorrent/include/libtorrent/extensions.hpp b/libtorrent/include/libtorrent/extensions.hpp index c4c2c748d..3e85b125b 100644 --- a/libtorrent/include/libtorrent/extensions.hpp +++ b/libtorrent/include/libtorrent/extensions.hpp @@ -57,6 +57,7 @@ namespace libtorrent class peer_connection; class entry; struct disk_buffer_holder; + struct bitfield; struct TORRENT_EXPORT torrent_plugin { @@ -129,7 +130,7 @@ namespace libtorrent virtual bool on_have(int index) { return false; } - virtual bool on_bitfield(std::vector const& bitfield) + virtual bool on_bitfield(bitfield const& bitfield) { return false; } virtual bool on_have_all() diff --git a/libtorrent/include/libtorrent/file_pool.hpp b/libtorrent/include/libtorrent/file_pool.hpp index d57f6def5..69116d675 100644 --- a/libtorrent/include/libtorrent/file_pool.hpp +++ b/libtorrent/include/libtorrent/file_pool.hpp @@ -68,6 +68,7 @@ namespace libtorrent boost::shared_ptr open_file(void* st, fs::path const& p , file::open_mode m, std::string& error); void release(void* st); + void release(fs::path const& p); void resize(int size); private: diff --git a/libtorrent/include/libtorrent/file_storage.hpp b/libtorrent/include/libtorrent/file_storage.hpp new file mode 100644 index 000000000..bbb606bf6 --- /dev/null +++ b/libtorrent/include/libtorrent/file_storage.hpp @@ -0,0 +1,146 @@ +/* + +Copyright (c) 2003-2008, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_FILE_STORAGE_HPP_INCLUDED +#define TORRENT_FILE_STORAGE_HPP_INCLUDED + +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/size_type.hpp" +#include "libtorrent/assert.hpp" +#include "libtorrent/peer_request.hpp" + +namespace libtorrent +{ + namespace fs = boost::filesystem; + + struct TORRENT_EXPORT file_entry + { + file_entry(): offset(0), size(0), file_base(0) {} + + fs::path path; + size_type offset; // the offset of this file inside the torrent + size_type size; // the size of this file + // the offset in the file where the storage starts. + // This is always 0 unless parts of the torrent is + // compressed into a single file, such as a so-called part file. + size_type file_base; + }; + + struct TORRENT_EXPORT file_slice + { + int file_index; + size_type offset; + size_type size; + }; + + class TORRENT_EXPORT file_storage + { + friend class torrent_info; + public: + file_storage(); + ~file_storage() {} + + bool is_valid() const { return m_piece_length > 0; } + + void add_file(file_entry const& e); + void add_file(fs::path const& p, size_type size); + void rename_file(int index, std::string const& new_filename); + + std::vector map_block(int piece, size_type offset + , int size) const; + peer_request map_file(int file, size_type offset, int size) const; + + typedef std::vector::const_iterator iterator; + typedef std::vector::const_reverse_iterator reverse_iterator; + + iterator begin() const { return m_files.begin(); } + iterator end() const { return m_files.end(); } + reverse_iterator rbegin() const { return m_files.rbegin(); } + reverse_iterator rend() const { return m_files.rend(); } + int num_files() const + { return int(m_files.size()); } + + file_entry const& at(int index) const + { + TORRENT_ASSERT(index >= 0 && index < int(m_files.size())); + return m_files[index]; + } + + size_type total_size() const { TORRENT_ASSERT(m_piece_length > 0); return m_total_size; } + void set_num_pieces(int n) { m_num_pieces = n; } + int num_pieces() const { TORRENT_ASSERT(m_piece_length > 0); return m_num_pieces; } + void set_piece_length(int l) { m_piece_length = l; } + int piece_length() const { TORRENT_ASSERT(m_piece_length > 0); return m_piece_length; } + int piece_size(int index) const; + + void set_name(std::string const& n) { m_name = n; } + const std::string& name() const { TORRENT_ASSERT(m_piece_length > 0); return m_name; } + + void swap(file_storage& ti) + { + using std::swap; + swap(ti.m_piece_length, m_piece_length); + swap(ti.m_files, m_files); + swap(ti.m_total_size, m_total_size); + swap(ti.m_num_pieces, m_num_pieces); + swap(ti.m_name, m_name); + } + + private: + int m_piece_length; + + // the list of files that this torrent consists of + std::vector m_files; + + // the sum of all filesizes + size_type m_total_size; + + // the number of pieces in the torrent + int m_num_pieces; + std::string m_name; + }; +} + +#endif // TORRENT_FILE_STORAGE_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/peer_connection.hpp b/libtorrent/include/libtorrent/peer_connection.hpp index a0a799200..669187d61 100755 --- a/libtorrent/include/libtorrent/peer_connection.hpp +++ b/libtorrent/include/libtorrent/peer_connection.hpp @@ -76,6 +76,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/assert.hpp" #include "libtorrent/chained_buffer.hpp" #include "libtorrent/disk_buffer_holder.hpp" +#include "libtorrent/bitfield.hpp" namespace libtorrent { @@ -242,7 +243,7 @@ namespace libtorrent boost::shared_ptr get_socket() const { return m_socket; } tcp::endpoint const& remote() const { return m_remote; } - std::vector const& get_bitfield() const; + bitfield const& get_bitfield() const; std::vector const& allowed_fast(); std::vector const& suggested_pieces() const { return m_suggested_pieces; } @@ -328,7 +329,7 @@ namespace libtorrent void incoming_interested(); void incoming_not_interested(); void incoming_have(int piece_index); - void incoming_bitfield(std::vector const& bitfield); + void incoming_bitfield(bitfield const& bits); void incoming_request(peer_request const& r); void incoming_piece(peer_request const& p, disk_buffer_holder& data); void incoming_piece(peer_request const& p, char const* data); @@ -629,7 +630,7 @@ namespace libtorrent peer_id m_peer_id; // the pieces the other end have - std::vector m_have_piece; + bitfield m_have_piece; // the queue of requests we have got // from this peer diff --git a/libtorrent/include/libtorrent/peer_info.hpp b/libtorrent/include/libtorrent/peer_info.hpp index b45b5dcbd..c778bf8d4 100755 --- a/libtorrent/include/libtorrent/peer_info.hpp +++ b/libtorrent/include/libtorrent/peer_info.hpp @@ -33,12 +33,11 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_PEER_INFO_HPP_INCLUDED #define TORRENT_PEER_INFO_HPP_INCLUDED -#include - #include "libtorrent/socket.hpp" #include "libtorrent/peer_id.hpp" #include "libtorrent/size_type.hpp" #include "libtorrent/config.hpp" +#include "libtorrent/bitfield.hpp" namespace libtorrent { @@ -96,7 +95,7 @@ namespace libtorrent size_type total_download; size_type total_upload; peer_id pid; - std::vector pieces; + bitfield pieces; int upload_limit; int download_limit; diff --git a/libtorrent/include/libtorrent/piece_picker.hpp b/libtorrent/include/libtorrent/piece_picker.hpp index 581975af9..6be92ffa1 100755 --- a/libtorrent/include/libtorrent/piece_picker.hpp +++ b/libtorrent/include/libtorrent/piece_picker.hpp @@ -58,6 +58,7 @@ namespace libtorrent class torrent; class peer_connection; + class bitfield; struct TORRENT_EXPORT piece_block { @@ -138,7 +139,7 @@ namespace libtorrent // the vector tells which pieces we already have // and which we don't have. - void init(std::vector const& pieces); + void init(bitfield const& pieces); // increases the peer count for the given piece // (is used when a HAVE message is received) @@ -147,10 +148,10 @@ namespace libtorrent // increases the peer count for the given piece // (is used when a BITFIELD message is received) - void inc_refcount(std::vector const& bitmask); + void inc_refcount(bitfield const& bitmask); // decreases the peer count for the given piece // (used when a peer disconnects) - void dec_refcount(std::vector const& bitmask); + void dec_refcount(bitfield const& bitmask); // these will increase and decrease the peer count // of all pieces. They are used when seeds join @@ -193,7 +194,7 @@ namespace libtorrent // THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION! // The last argument is the policy::peer pointer for the peer that // we'll download from. - void pick_pieces(std::vector const& pieces + void pick_pieces(bitfield const& pieces , std::vector& interesting_blocks , int num_pieces, int prefer_whole_pieces , void* peer, piece_state_t speed @@ -207,14 +208,14 @@ namespace libtorrent // blocks to be picked. Blocks are not picked from pieces // that are being downloaded int add_blocks(std::vector const& piece_list - , const std::vector& pieces + , bitfield const& pieces , std::vector& interesting_blocks , int num_blocks, int prefer_whole_pieces , void* peer, std::vector const& ignore) const; // picks blocks only from downloading pieces int add_blocks_downloading( - std::vector const& pieces + bitfield const& pieces , std::vector& interesting_blocks , std::vector& backup_blocks , int num_blocks, int prefer_whole_pieces @@ -280,7 +281,7 @@ namespace libtorrent void verify_priority(int start, int end, int prio) const; void check_invariant(const torrent* t = 0) const; void verify_pick(std::vector const& picked - , std::vector const& bitfield) const; + , bitfield const& bits) const; void print_pieces() const; #endif @@ -302,9 +303,9 @@ namespace libtorrent friend struct piece_pos; - bool can_pick(int piece, std::vector const& bitmask) const; + bool can_pick(int piece, bitfield const& bitmask) const; std::pair expand_piece(int piece, int whole_pieces - , std::vector const& have) const; + , bitfield const& have) const; struct piece_pos { diff --git a/libtorrent/include/libtorrent/session.hpp b/libtorrent/include/libtorrent/session.hpp index fcae0be32..ebd6b7ea5 100755 --- a/libtorrent/include/libtorrent/session.hpp +++ b/libtorrent/include/libtorrent/session.hpp @@ -129,7 +129,7 @@ namespace libtorrent , resume_data(0) , storage_mode(storage_mode_sparse) , paused(true) - , auto_managed(true) + , auto_managed(false) , duplicate_is_error(false) , storage(sc) , userdata(0) diff --git a/libtorrent/include/libtorrent/session_settings.hpp b/libtorrent/include/libtorrent/session_settings.hpp index 30e76b825..677bd8b84 100644 --- a/libtorrent/include/libtorrent/session_settings.hpp +++ b/libtorrent/include/libtorrent/session_settings.hpp @@ -135,6 +135,7 @@ namespace libtorrent , close_redundant_connections(true) , auto_scrape_interval(1800) , auto_scrape_min_interval(300) + , max_peerlist_size(8000) {} // this is the user agent that will be sent to the tracker @@ -402,6 +403,11 @@ namespace libtorrent // the minimum number of seconds between any // automatic scrape (regardless of torrent) int auto_scrape_min_interval; + + // the max number of peers in the peer list + // per torrent. This is the peers we know + // about, not necessarily connected to. + int max_peerlist_size; }; #ifndef TORRENT_DISABLE_DHT diff --git a/libtorrent/include/libtorrent/socket.hpp b/libtorrent/include/libtorrent/socket.hpp index 0bca27da5..d041024bb 100755 --- a/libtorrent/include/libtorrent/socket.hpp +++ b/libtorrent/include/libtorrent/socket.hpp @@ -45,6 +45,8 @@ POSSIBILITY OF SUCH DAMAGE. #define Protocol Protocol_ #endif +#include + #if BOOST_VERSION < 103500 #include #include diff --git a/libtorrent/include/libtorrent/storage.hpp b/libtorrent/include/libtorrent/storage.hpp index 51c7b3c01..1c27388f7 100755 --- a/libtorrent/include/libtorrent/storage.hpp +++ b/libtorrent/include/libtorrent/storage.hpp @@ -87,11 +87,11 @@ namespace libtorrent #endif TORRENT_EXPORT std::vector > get_filesizes( - torrent_info const& t + file_storage const& t , fs::path p); TORRENT_EXPORT bool match_filesizes( - torrent_info const& t + file_storage const& t , fs::path p , std::vector > const& sizes , bool compact_mode @@ -157,6 +157,9 @@ namespace libtorrent // non-zero return value indicates an error virtual bool release_files() = 0; + // this will rename the file specified by index. + virtual bool rename_file(int index, std::string const& new_filename) = 0; + // this will close all open files and delete them // non-zero return value indicates an error virtual bool delete_files() = 0; @@ -178,16 +181,12 @@ namespace libtorrent }; typedef storage_interface* (&storage_constructor_type)( - boost::intrusive_ptr, fs::path const& - , file_pool&); + file_storage const&, fs::path const&, file_pool&); TORRENT_EXPORT storage_interface* default_storage_constructor( - boost::intrusive_ptr ti - , fs::path const& path, file_pool& fp); - + file_storage const&, fs::path const&, file_pool&); TORRENT_EXPORT storage_interface* mapped_storage_constructor( - boost::intrusive_ptr ti - , fs::path const& path, file_pool& fp); + file_storage const&, fs::path const&, file_pool&); struct disk_io_thread; @@ -201,7 +200,7 @@ namespace libtorrent piece_manager( boost::shared_ptr const& torrent - , boost::intrusive_ptr ti + , boost::intrusive_ptr info , fs::path const& path , file_pool& fp , disk_io_thread& io @@ -210,8 +209,7 @@ namespace libtorrent ~piece_manager(); - torrent_info const* info() const { return m_info.get(); } - + boost::intrusive_ptr info() const { return m_info; } void write_resume_data(entry& rd) const; void async_check_fastresume(entry const* resume_data @@ -219,6 +217,9 @@ namespace libtorrent void async_check_files(boost::function const& handler); + void async_rename_file(int index, std::string const& name + , boost::function const& handler); + void async_read( peer_request const& r , boost::function const& handler @@ -316,6 +317,8 @@ namespace libtorrent int release_files_impl() { return m_storage->release_files(); } int delete_files_impl() { return m_storage->delete_files(); } + int rename_file_impl(int index, std::string const& new_filename) + { return m_storage->rename_file(index, new_filename); } bool move_storage_impl(fs::path const& save_path); @@ -326,12 +329,13 @@ namespace libtorrent void debug_log() const; #endif #endif + boost::intrusive_ptr m_info; + file_storage const& m_files; + boost::scoped_ptr m_storage; storage_mode_t m_storage_mode; - boost::intrusive_ptr m_info; - // slots that haven't had any file storage allocated std::vector m_unallocated_slots; // slots that have file storage, but isn't assigned to a piece diff --git a/libtorrent/include/libtorrent/time.hpp b/libtorrent/include/libtorrent/time.hpp index f768c7fe2..e74247ebb 100644 --- a/libtorrent/include/libtorrent/time.hpp +++ b/libtorrent/include/libtorrent/time.hpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_TIME_HPP_INCLUDED #include +#include #ifndef _WIN32 #include diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp index 39aa2fe4b..dec649c24 100755 --- a/libtorrent/include/libtorrent/torrent.hpp +++ b/libtorrent/include/libtorrent/torrent.hpp @@ -70,6 +70,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/storage.hpp" #include "libtorrent/hasher.hpp" #include "libtorrent/assert.hpp" +#include "libtorrent/bitfield.hpp" namespace libtorrent { @@ -79,6 +80,7 @@ namespace libtorrent class piece_manager; struct torrent_plugin; + struct bitfield; namespace aux { @@ -167,6 +169,9 @@ namespace libtorrent void set_sequential_download(bool sd); + void set_queue_position(int p); + int queue_position() const { return m_sequence_number; } + void second_tick(stat& accumulator, float tick_interval); // debug purpose only @@ -181,6 +186,7 @@ namespace libtorrent void ip_filter_updated() { m_policy.ip_filter_updated(); } + bool has_error() const { return !m_error.empty(); } void pause(); void resume(); bool is_paused() const { return m_paused; } @@ -375,7 +381,7 @@ namespace libtorrent return m_have_pieces[index]; } - const std::vector& pieces() const + bitfield const& pieces() const { return m_have_pieces; } int num_pieces() const { return m_num_pieces; } @@ -398,12 +404,12 @@ namespace libtorrent } // when we get a bitfield message, this is called for that piece - void peer_has(std::vector const& bitfield) + void peer_has(bitfield const& bits) { if (m_picker.get()) { TORRENT_ASSERT(!is_seed()); - m_picker->inc_refcount(bitfield); + m_picker->inc_refcount(bits); } #ifndef NDEBUG else @@ -562,8 +568,14 @@ namespace libtorrent int max_uploads() const { return m_max_uploads; } void set_max_connections(int limit); int max_connections() const { return m_max_connections; } + void move_storage(fs::path const& save_path); + // renames the file with the given index to the new name + // the name may include a directory path + // returns false on failure + bool rename_file(int index, std::string const& name); + // unless this returns true, new connections must wait // with their initialization. bool ready_for_connections() const @@ -587,6 +599,7 @@ namespace libtorrent void on_torrent_paused(int ret, disk_io_job const& j); void on_storage_moved(int ret, disk_io_job const& j); void on_save_resume_data(int ret, disk_io_job const& j); + void on_file_renamed(int ret, disk_io_job const& j); void on_piece_verified(int ret, disk_io_job const& j , boost::function f); @@ -728,7 +741,7 @@ namespace libtorrent // this is an index into m_trackers // the bitmask that says which pieces we have - std::vector m_have_pieces; + bitfield m_have_pieces; // the number of bytes that has been // downloaded that failed the hash-test @@ -750,6 +763,10 @@ namespace libtorrent // the state of this torrent (queued, checking, downloading) torrent_status::state_t m_state; + // if there's an error on this torrent, this is the + // error message + std::string m_error; + entry m_resume_data; // if the torrent is started without metadata, it may diff --git a/libtorrent/include/libtorrent/torrent_handle.hpp b/libtorrent/include/libtorrent/torrent_handle.hpp index e6e7e55f4..cd499a033 100755 --- a/libtorrent/include/libtorrent/torrent_handle.hpp +++ b/libtorrent/include/libtorrent/torrent_handle.hpp @@ -137,6 +137,8 @@ namespace libtorrent state_t state; bool paused; float progress; + std::string error; + boost::posix_time::time_duration next_announce; boost::posix_time::time_duration announce_interval; @@ -198,7 +200,7 @@ namespace libtorrent // we potentially could connect to int connect_candidates; - const std::vector* pieces; + bitfield const* pieces; // this is the number of pieces the client has // downloaded. it is equal to: @@ -344,6 +346,12 @@ namespace libtorrent bool is_auto_managed() const; void auto_managed(bool m) const; + int queue_position() const; + void queue_position_up() const; + void queue_position_down() const; + void queue_position_top() const; + void queue_position_bottom() const; + #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES void resolve_countries(bool r); bool resolve_countries() const; @@ -440,6 +448,7 @@ namespace libtorrent // post condition: save_path() == save_path if true is returned void move_storage(fs::path const& save_path) const; + void rename_file(int index, fs::path const& new_name) const; sha1_hash info_hash() const; diff --git a/libtorrent/include/libtorrent/torrent_info.hpp b/libtorrent/include/libtorrent/torrent_info.hpp index f6baa476c..148d77c8f 100755 --- a/libtorrent/include/libtorrent/torrent_info.hpp +++ b/libtorrent/include/libtorrent/torrent_info.hpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2003, Arvid Norberg +Copyright (c) 2003-2008, Arvid Norberg All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,9 +30,8 @@ POSSIBILITY OF SUCH DAMAGE. */ -#ifndef TORRENT_TORRENT_INFO_HPP_INCLUDE -#define TORRENT_TORRENT_INFO_HPP_INCLUDE - +#ifndef TORRENT_TORRENT_INFO_HPP_INCLUDED +#define TORRENT_TORRENT_INFO_HPP_INCLUDED #include #include @@ -44,7 +43,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#include #include #ifdef _MSC_VER @@ -56,44 +54,17 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/peer_id.hpp" #include "libtorrent/size_type.hpp" -#include "libtorrent/peer_request.hpp" #include "libtorrent/config.hpp" #include "libtorrent/time.hpp" #include "libtorrent/intrusive_ptr_base.hpp" #include "libtorrent/assert.hpp" +#include "libtorrent/file_storage.hpp" namespace libtorrent { namespace pt = boost::posix_time; namespace gr = boost::gregorian; - namespace fs = boost::filesystem; - - struct TORRENT_EXPORT file_entry - { - file_entry(): offset(0), size(0), file_base(0) {} - - fs::path path; - size_type offset; // the offset of this file inside the torrent - size_type size; // the size of this file - // the offset in the file where the storage starts. - // This is always 0 unless parts of the torrent is - // compressed into a single file, such as a so-called part file. - size_type file_base; - // if the path was incorrectly encoded, this is - // the original corrupt encoded string. It is - // preserved in order to be able to reproduce - // the correct info-hash - boost::shared_ptr orig_path; - }; - - struct TORRENT_EXPORT file_slice - { - int file_index; - size_type offset; - size_type size; - }; - struct TORRENT_EXPORT announce_entry { announce_entry(std::string const& u): url(u), tier(0) {} @@ -101,124 +72,73 @@ namespace libtorrent int tier; }; +#ifndef BOOST_NO_EXCEPTIONS struct TORRENT_EXPORT invalid_torrent_file: std::exception { virtual const char* what() const throw() { return "invalid torrent file"; } }; +#endif class TORRENT_EXPORT torrent_info : public intrusive_ptr_base { public: - torrent_info(); torrent_info(sha1_hash const& info_hash); torrent_info(lazy_entry const& torrent_file); torrent_info(char const* buffer, int size); torrent_info(char const* filename); ~torrent_info(); + file_storage const& files() const { return m_files; } + void add_tracker(std::string const& url, int tier = 0); + std::vector const& trackers() const { return m_urls; } - bool remap_files(std::vector const& map); - - std::vector map_block(int piece, size_type offset - , int size, bool storage = false) const; - peer_request map_file(int file, size_type offset, int size - , bool storage = false) const; - std::vector const& url_seeds() const { return m_url_seeds; } void add_url_seed(std::string const& url) { m_url_seeds.push_back(url); } - typedef std::vector::const_iterator file_iterator; - typedef std::vector::const_reverse_iterator reverse_file_iterator; - - // list the files in the torrent file - file_iterator begin_files(bool storage = false) const - { - if (!storage || m_remapped_files.empty()) - return m_files.begin(); - else - return m_remapped_files.begin(); - } - - file_iterator end_files(bool storage = false) const - { - if (!storage || m_remapped_files.empty()) - return m_files.end(); - else - return m_remapped_files.end(); - } - - reverse_file_iterator rbegin_files(bool storage = false) const - { - if (!storage || m_remapped_files.empty()) - return m_files.rbegin(); - else - return m_remapped_files.rbegin(); - } - - reverse_file_iterator rend_files(bool storage = false) const - { - if (!storage || m_remapped_files.empty()) - return m_files.rend(); - else - return m_remapped_files.rend(); - } - - int num_files(bool storage = false) const - { - TORRENT_ASSERT(m_piece_length > 0); - if (!storage || m_remapped_files.empty()) - return int(m_files.size()); - else - return int(m_remapped_files.size()); - } - - file_entry const& file_at(int index, bool storage = false) const - { - if (!storage || m_remapped_files.empty()) - { - TORRENT_ASSERT(index >= 0 && index < (int)m_files.size()); - return m_files[index]; - } - else - { - TORRENT_ASSERT(index >= 0 && index < (int)m_remapped_files.size()); - return m_remapped_files[index]; - } - } - - std::vector const& trackers() const { return m_urls; } - - size_type total_size() const { TORRENT_ASSERT(m_piece_length > 0); return m_total_size; } - int piece_length() const { TORRENT_ASSERT(m_piece_length > 0); return m_piece_length; } - int num_pieces() const { TORRENT_ASSERT(m_piece_length > 0); return m_num_pieces; } + size_type total_size() const { return m_files.total_size(); } + int piece_length() const { return m_files.piece_length(); } + int num_pieces() const { return m_files.num_pieces(); } const sha1_hash& info_hash() const { return m_info_hash; } - const std::string& name() const { TORRENT_ASSERT(m_piece_length > 0); return m_name; } + const std::string& name() const { return m_files.name(); } + typedef file_storage::iterator file_iterator; + typedef file_storage::reverse_iterator reverse_file_iterator; + + file_iterator begin_files() const { return m_files.begin(); } + file_iterator end_files() const { return m_files.end(); } + reverse_file_iterator rbegin_files() const { return m_files.rbegin(); } + reverse_file_iterator rend_files() const { return m_files.rend(); } + int num_files() const { return m_files.num_files(); } + file_entry const& file_at(int index) const { return m_files.at(index); } + + std::vector map_block(int piece, size_type offset, int size) const + { return m_files.map_block(piece, offset, size); } + peer_request map_file(int file, size_type offset, int size) const + { return m_files.map_file(file, offset, size); } + // ------- start deprecation ------- // these functions will be removed in a future version torrent_info(entry const& torrent_file) TORRENT_DEPRECATED; void print(std::ostream& os) const TORRENT_DEPRECATED; // ------- end deprecation ------- - bool is_valid() const { return m_piece_length > 0; } + bool is_valid() const { return m_files.is_valid(); } bool priv() const { return m_private; } - int piece_size(int index) const; + int piece_size(int index) const { return m_files.piece_size(index); } sha1_hash hash_for_piece(int index) const - { - return sha1_hash(hash_for_piece_ptr(index)); - } + { return sha1_hash(hash_for_piece_ptr(index)); } char const* hash_for_piece_ptr(int index) const { TORRENT_ASSERT(index >= 0); - TORRENT_ASSERT(index < m_num_pieces); + TORRENT_ASSERT(index < m_files.num_pieces()); TORRENT_ASSERT(m_piece_hashes); TORRENT_ASSERT(m_piece_hashes >= m_info_section.get()); TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size); @@ -262,41 +182,18 @@ namespace libtorrent bool parse_torrent_file(lazy_entry const& libtorrent, std::string& error); + file_storage m_files; + // the urls to the trackers std::vector m_urls; - std::vector m_url_seeds; - - // the length of one piece - // if this is 0, the torrent_info is - // in an uninitialized state - int m_piece_length; - - // the list of files that this torrent consists of - std::vector m_files; - - // this vector is typically empty. If it is not - // empty, it means the user has re-mapped the - // files in this torrent to different names - // on disk. This is only used when reading and - // writing the disk. - std::vector m_remapped_files; - nodes_t m_nodes; - // the sum of all filesizes - size_type m_total_size; - - // the number of pieces in the torrent - int m_num_pieces; - // the hash that identifies this torrent // is mutable because it's calculated // lazily sha1_hash m_info_hash; - std::string m_name; - // if a creation date is found in the torrent file // this will be set to that, otherwise it'll be // 1970, Jan 1 diff --git a/libtorrent/src/broadcast_socket.cpp b/libtorrent/src/broadcast_socket.cpp index 2a087ef79..cfb1a9f1a 100644 --- a/libtorrent/src/broadcast_socket.cpp +++ b/libtorrent/src/broadcast_socket.cpp @@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE. */ +#include + #if BOOST_VERSION < 103500 #include #include diff --git a/libtorrent/src/bt_peer_connection.cpp b/libtorrent/src/bt_peer_connection.cpp index 80ee9fe1c..eeb40e478 100755 --- a/libtorrent/src/bt_peer_connection.cpp +++ b/libtorrent/src/bt_peer_connection.cpp @@ -937,21 +937,11 @@ namespace libtorrent buffer::const_interval recv_buffer = receive_buffer(); - std::vector bitfield; + bitfield bits; + bits.borrow_bytes((char*)recv_buffer.begin + 1 + , t->valid_metadata()?get_bitfield().size():(packet_size()-1)*8); - if (!t->valid_metadata()) - bitfield.resize((packet_size() - 1) * 8); - else - bitfield.resize(get_bitfield().size()); - - // if we don't have metadata yet - // just remember the bitmask - // don't update the piecepicker - // (since it doesn't exist yet) - for (int i = 0; i < (int)bitfield.size(); ++i) - bitfield[i] = (recv_buffer[1 + (i>>3)] & (1 << (7 - (i&7)))) != 0; - - incoming_bitfield(bitfield); + incoming_bitfield(bits); } // ----------------------------- @@ -1426,7 +1416,7 @@ namespace libtorrent send_buffer(msg, sizeof(msg)); } - void bt_peer_connection::write_bitfield(std::vector const& bitfield) + void bt_peer_connection::write_bitfield(bitfield const& bits) { INVARIANT_CHECK; @@ -1459,12 +1449,14 @@ namespace libtorrent return; } - int num_pieces = bitfield.size(); + int num_pieces = bits.size(); int lazy_pieces[50]; int num_lazy_pieces = 0; int lazy_piece = 0; - TORRENT_ASSERT(t->is_seed() == (std::count(bitfield.begin(), bitfield.end(), true) == num_pieces)); + TORRENT_ASSERT(t->is_seed() == (bits.count() + == num_pieces)); + if (t->is_seed() && m_ses.settings().lazy_bitfields) { num_lazy_pieces = (std::min)(50, num_pieces / 10); @@ -1491,7 +1483,7 @@ namespace libtorrent ++lazy_piece; continue; } - if (bitfield[i]) bitfield_string << "1"; + if (bits[i]) bitfield_string << "1"; else bitfield_string << "0"; } bitfield_string << "\n"; @@ -1506,18 +1498,9 @@ namespace libtorrent detail::write_int32(packet_size - 4, i.begin); detail::write_uint8(msg_bitfield, i.begin); - std::fill(i.begin, i.end, 0); - for (int c = 0; c < num_pieces; ++c) - { - if (lazy_piece < num_lazy_pieces - && lazy_pieces[lazy_piece] == c) - { - ++lazy_piece; - continue; - } - if (bitfield[c]) - i.begin[c >> 3] |= 1 << (7 - (c & 7)); - } + memcpy(i.begin, bits.bytes(), packet_size - 5); + for (int c = 0; c < num_lazy_pieces; ++c) + i.begin[lazy_pieces[c] / 8] &= ~(0x80 >> (lazy_pieces[c] & 7)); TORRENT_ASSERT(i.end - i.begin == (num_pieces + 7) / 8); #ifndef NDEBUG diff --git a/libtorrent/src/create_torrent.cpp b/libtorrent/src/create_torrent.cpp index 8d408fe2c..98f590d20 100644 --- a/libtorrent/src/create_torrent.cpp +++ b/libtorrent/src/create_torrent.cpp @@ -31,7 +31,8 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "libtorrent/create_torrent.hpp" -#include "libtorrent/hasher.hpp" +#include "libtorrent/file_pool.hpp" +#include "libtorrent/storage.hpp" #include #include @@ -41,22 +42,61 @@ namespace gr = boost::gregorian; namespace libtorrent { - create_torrent::create_torrent() - : m_piece_length(0) - , m_total_size(0) - , m_num_pieces(0) - , m_info_hash() - , m_name() + create_torrent::create_torrent(file_storage& fs, int size) + : m_files(fs) , m_creation_date(pt::second_clock::universal_time()) - , m_multifile(false) + , m_multifile(fs.num_files() > 1) , m_private(false) - {} + { + TORRENT_ASSERT(fs.num_files() > 0); + if (!m_multifile && m_files.at(0).path.has_branch_path()) m_multifile = true; + // make sure the size is an even power of 2 +#ifndef NDEBUG + for (int i = 0; i < 32; ++i) + { + if (size & (1 << i)) + { + TORRENT_ASSERT((size & ~(1 << i)) == 0); + break; + } + } +#endif + m_files.set_piece_length(size); + m_files.set_num_pieces(static_cast( + (m_files.total_size() + m_files.piece_length() - 1) / m_files.piece_length())); + m_piece_hash.resize(m_files.num_pieces()); + } + + create_torrent::create_torrent(file_storage& fs) + : m_files(fs) + , m_creation_date(pt::second_clock::universal_time()) + , m_multifile(fs.num_files() > 1) + , m_private(false) + { + TORRENT_ASSERT(fs.num_files() > 0); + if (!m_multifile && m_files.at(0).path.has_branch_path()) m_multifile = true; + + const int target_size = 40 * 1024; + int size = fs.total_size() / (target_size / 20); + + for (int i = 4*1024*1024; i > 16*1024; i /= 2) + { + if (size < i) continue; + size = i; + break; + } + + m_files.set_piece_length(size); + m_files.set_num_pieces(static_cast( + (m_files.total_size() + m_files.piece_length() - 1) / m_files.piece_length())); + m_piece_hash.resize(m_files.num_pieces()); + } entry create_torrent::generate() const { - TORRENT_ASSERT(m_piece_length > 0); + TORRENT_ASSERT(m_files.piece_length() > 0); - if (m_files.empty()) + if (m_files.num_files() == 0) { // TODO: throw something here // throw @@ -128,15 +168,13 @@ namespace libtorrent } entry& info = dict["info"]; - - info["name"] = m_name; - + info["name"] = m_files.name(); if (m_private) info["private"] = 1; if (!m_multifile) { - info["length"] = m_files.front().second; + info["length"] = m_files.at(0).size; } else { @@ -144,19 +182,19 @@ namespace libtorrent { entry& files = info["files"]; - for (std::vector::const_iterator i = m_files.begin(); + for (file_storage::iterator i = m_files.begin(); i != m_files.end(); ++i) { files.list().push_back(entry()); entry& file_e = files.list().back(); - file_e["length"] = i->second; + file_e["length"] = i->size; entry& path_e = file_e["path"]; - TORRENT_ASSERT(i->first.has_branch_path()); - TORRENT_ASSERT(*i->first.begin() == m_name); + TORRENT_ASSERT(i->path.has_branch_path()); + TORRENT_ASSERT(*i->path.begin() == m_files.name()); - for (fs::path::iterator j = boost::next(i->first.begin()); - j != i->first.end(); ++j) + for (fs::path::iterator j = boost::next(i->path.begin()); + j != i->path.end(); ++j) { path_e.list().push_back(entry(*j)); } @@ -164,7 +202,7 @@ namespace libtorrent } } - info["piece length"] = m_piece_length; + info["piece length"] = m_files.piece_length(); entry& pieces = info["pieces"]; std::string& p = pieces.string(); @@ -183,21 +221,6 @@ namespace libtorrent } - int create_torrent::piece_size(int index) const - { - TORRENT_ASSERT(index >= 0 && index < num_pieces()); - if (index == num_pieces()-1) - { - int size = int(m_total_size - - (num_pieces() - 1) * piece_length()); - TORRENT_ASSERT(size > 0); - TORRENT_ASSERT(size <= piece_length()); - return int(size); - } - else - return piece_length(); - } - void create_torrent::add_tracker(std::string const& url, int tier) { m_urls.push_back(announce_entry(url, tier)); @@ -207,32 +230,6 @@ namespace libtorrent , bind(&announce_entry::second, _1) < bind(&announce_entry::second, _2)); } - void create_torrent::set_piece_size(int size) - { - // make sure the size is an even power of 2 -#ifndef NDEBUG - for (int i = 0; i < 32; ++i) - { - if (size & (1 << i)) - { - TORRENT_ASSERT((size & ~(1 << i)) == 0); - break; - } - } -#endif - m_piece_length = size; - - m_num_pieces = static_cast( - (m_total_size + m_piece_length - 1) / m_piece_length); - int old_num_pieces = static_cast(m_piece_hash.size()); - - m_piece_hash.resize(m_num_pieces); - for (int i = old_num_pieces; i < m_num_pieces; ++i) - { - m_piece_hash[i].clear(); - } - } - void create_torrent::set_hash(int index, sha1_hash const& h) { TORRENT_ASSERT(index >= 0); @@ -240,46 +237,6 @@ namespace libtorrent m_piece_hash[index] = h; } - void create_torrent::add_file(fs::path file, size_type size) - { -// TORRENT_ASSERT(file.begin() != file.end()); - - if (!file.has_branch_path()) - { - // you have already added at least one file with a - // path to the file (branch_path), which means that - // all the other files need to be in the same top - // directory as the first file. - TORRENT_ASSERT(m_files.empty()); - TORRENT_ASSERT(!m_multifile); - m_name = file.string(); - } - else - { -#ifndef NDEBUG - if (!m_files.empty()) - TORRENT_ASSERT(m_name == *file.begin()); -#endif - m_multifile = true; - m_name = *file.begin(); - } - - m_files.push_back(file_entry(file, size)); - - m_total_size += size; - - if (m_piece_length == 0) - m_piece_length = 256 * 1024; - - m_num_pieces = int((m_total_size + m_piece_length - 1) / m_piece_length); - int old_num_pieces = int(m_piece_hash.size()); - - m_piece_hash.resize(m_num_pieces); - if (m_num_pieces > old_num_pieces) - std::for_each(m_piece_hash.begin() + old_num_pieces - , m_piece_hash.end(), boost::bind(&sha1_hash::clear, _1)); - } - void create_torrent::add_node(std::pair const& node) { m_nodes.push_back(node); @@ -299,5 +256,6 @@ namespace libtorrent { m_created_by = str; } + } diff --git a/libtorrent/src/disk_io_thread.cpp b/libtorrent/src/disk_io_thread.cpp index ac76263ce..57aa52877 100644 --- a/libtorrent/src/disk_io_thread.cpp +++ b/libtorrent/src/disk_io_thread.cpp @@ -1049,6 +1049,13 @@ namespace libtorrent ret = 0; break; } + case disk_io_job::rename_file: + { +#ifdef TORRENT_DISK_STATS + m_log << log_time() << " rename file" << std::endl; +#endif + ret = j.storage->rename_file_impl(j.piece, j.str); + } } #ifndef BOOST_NO_EXCEPTIONS } catch (std::exception& e) diff --git a/libtorrent/src/file_pool.cpp b/libtorrent/src/file_pool.cpp index 6baeb64d0..19bdb4162 100644 --- a/libtorrent/src/file_pool.cpp +++ b/libtorrent/src/file_pool.cpp @@ -115,6 +115,16 @@ namespace libtorrent return e.file_ptr; } + void file_pool::release(fs::path const& p) + { + boost::mutex::scoped_lock l(m_mutex); + + typedef nth_index::type path_view; + path_view& pt = get<0>(m_files); + path_view::iterator i = pt.find(p); + if (i != pt.end()) pt.erase(i); + } + void file_pool::release(void* st) { boost::mutex::scoped_lock l(m_mutex); diff --git a/libtorrent/src/file_storage.cpp b/libtorrent/src/file_storage.cpp new file mode 100644 index 000000000..69e88d25d --- /dev/null +++ b/libtorrent/src/file_storage.cpp @@ -0,0 +1,150 @@ +/* + +Copyright (c) 2003-2008, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "libtorrent/pch.hpp" + +#include "libtorrent/file_storage.hpp" + + +namespace libtorrent +{ + file_storage::file_storage() + : m_piece_length(0) + , m_total_size(0) + , m_num_pieces(0) + {} + + int file_storage::piece_size(int index) const + { + TORRENT_ASSERT(index >= 0 && index < num_pieces()); + if (index == num_pieces()-1) + { + int size = int(total_size() + - size_type(num_pieces() - 1) * piece_length()); + TORRENT_ASSERT(size > 0); + TORRENT_ASSERT(size <= piece_length()); + return int(size); + } + else + return piece_length(); + } + + void file_storage::rename_file(int index, std::string const& new_filename) + { + TORRENT_ASSERT(index >= 0 && index < int(m_files.size())); + m_files[index].path = new_filename; + } + + std::vector file_storage::map_block(int piece, size_type offset + , int size_) const + { + TORRENT_ASSERT(num_files() > 0); + std::vector ret; + + size_type start = piece * (size_type)m_piece_length + offset; + size_type size = size_; + TORRENT_ASSERT(start + size <= m_total_size); + + // find the file iterator and file offset + // TODO: make a vector that can map piece -> file index in O(1) + size_type file_offset = start; + std::vector::const_iterator file_iter; + + int counter = 0; + for (file_iter = begin();; ++counter, ++file_iter) + { + TORRENT_ASSERT(file_iter != end()); + if (file_offset < file_iter->size) + { + file_slice f; + f.file_index = counter; + f.offset = file_offset + file_iter->file_base; + f.size = (std::min)(file_iter->size - file_offset, (size_type)size); + size -= f.size; + file_offset += f.size; + ret.push_back(f); + } + + TORRENT_ASSERT(size >= 0); + if (size <= 0) break; + + file_offset -= file_iter->size; + } + return ret; + } + + peer_request file_storage::map_file(int file_index, size_type file_offset + , int size) const + { + TORRENT_ASSERT(file_index < num_files()); + TORRENT_ASSERT(file_index >= 0); + size_type offset = file_offset + at(file_index).offset; + + peer_request ret; + ret.piece = int(offset / piece_length()); + ret.start = int(offset - ret.piece * piece_length()); + ret.length = size; + return ret; + } + + void file_storage::add_file(fs::path const& file, size_type size) + { + TORRENT_ASSERT(size >= 0); + if (!file.has_branch_path()) + { + // you have already added at least one file with a + // path to the file (branch_path), which means that + // all the other files need to be in the same top + // directory as the first file. + TORRENT_ASSERT(m_files.empty()); + m_name = file.string(); + } + else + { + if (m_files.empty()) + m_name = *file.begin(); + } + TORRENT_ASSERT(m_name == *file.begin()); + file_entry e; + m_files.push_back(e); + m_files.back().size = size; + m_files.back().path = file; + m_files.back().offset = m_total_size; + m_total_size += size; + } + + void file_storage::add_file(file_entry const& e) + { + add_file(e.path, e.size); + } +} + diff --git a/libtorrent/src/kademlia/node.cpp b/libtorrent/src/kademlia/node.cpp index 904523753..63a8ac84b 100644 --- a/libtorrent/src/kademlia/node.cpp +++ b/libtorrent/src/kademlia/node.cpp @@ -408,7 +408,7 @@ void node_impl::on_announce(msg const& m, msg& reply) torrent_entry& v = m_map[m.info_hash]; peer_entry e; - e.addr = tcp::endpoint(m.addr.address(), m.addr.port()); + e.addr = tcp::endpoint(m.addr.address(), m.port); e.added = time_now(); std::set::iterator i = v.peers.find(e); if (i != v.peers.end()) v.peers.erase(i++); diff --git a/libtorrent/src/lazy_bdecode.cpp b/libtorrent/src/lazy_bdecode.cpp index bee91b49a..ffb15f87a 100644 --- a/libtorrent/src/lazy_bdecode.cpp +++ b/libtorrent/src/lazy_bdecode.cpp @@ -206,7 +206,7 @@ namespace libtorrent int num_digits(int val) { int ret = 1; - while (val > 10) + while (val >= 10) { ++ret; val /= 10; diff --git a/libtorrent/src/mapped_storage.cpp b/libtorrent/src/mapped_storage.cpp index f0c4d1b8b..97d961ab9 100644 --- a/libtorrent/src/mapped_storage.cpp +++ b/libtorrent/src/mapped_storage.cpp @@ -64,7 +64,9 @@ namespace libtorrent { namespace fs = boost::filesystem; #if BOOST_VERSION >= 103500 - using boost::system::error_code; + typedef boost::system::error_code ec_t; +#else + typedef error_code ec_t; #endif struct mapped_file_pool @@ -85,7 +87,7 @@ namespace libtorrent #ifndef NDEBUG if (file_size > 0) { - error_code ec; + ec_t ec; fs::file_status st = fs::status(path, ec); TORRENT_ASSERT(!fs::exists(st)); } @@ -207,7 +209,7 @@ namespace libtorrent #if BOOST_VERSION < 103500 fs::system_error_type ec; #else - error_code ec; + ec_t ec; #endif fs::file_status st = fs::status(p, ec); @@ -260,8 +262,8 @@ namespace libtorrent struct mapped_storage: storage_interface { - mapped_storage(boost::intrusive_ptr const& info, fs::path save_path) - : m_info(info) + mapped_storage(file_storage const& fs, fs::path save_path) + : m_files(fs) , m_save_path(save_path) {} @@ -270,9 +272,9 @@ namespace libtorrent int read(char* buf, int slot, int offset, int size) { TORRENT_ASSERT(buf != 0); - TORRENT_ASSERT(slot >= 0 && slot < m_info->num_pieces()); + TORRENT_ASSERT(slot >= 0 && slot < m_files.num_pieces()); TORRENT_ASSERT(offset >= 0); - TORRENT_ASSERT(offset < m_info->piece_size(slot)); + TORRENT_ASSERT(offset < m_files.piece_size(slot)); TORRENT_ASSERT(size > 0); size_type result = -1; @@ -281,17 +283,17 @@ namespace libtorrent #ifndef NDEBUG std::vector slices - = m_info->map_block(slot, offset, size, true); + = files().map_block(slot, offset, size); TORRENT_ASSERT(!slices.empty()); #endif - size_type start = slot * (size_type)m_info->piece_length() + offset; - TORRENT_ASSERT(start + size <= m_info->total_size()); + size_type start = slot * (size_type)m_files.piece_length() + offset; + TORRENT_ASSERT(start + size <= m_files.total_size()); // find the file iterator and file offset size_type file_offset = start; std::vector::const_iterator file_iter; - for (file_iter = m_info->begin_files(true);;) + for (file_iter = files().begin();;) { if (file_offset < file_iter->size) break; @@ -331,7 +333,7 @@ namespace libtorrent TORRENT_ASSERT(int(slices.size()) > counter); size_type slice_size = slices[counter].size; TORRENT_ASSERT(slice_size == read_bytes); - TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path + TORRENT_ASSERT(files().at(slices[counter].file_index).path == file_iter->path); #endif @@ -351,7 +353,7 @@ namespace libtorrent { ++file_iter; // skip empty files - while (file_iter != m_info->end_files(true) && file_iter->size == 0) + while (file_iter != files().end() && file_iter->size == 0) ++file_iter; #ifndef NDEBUG @@ -388,24 +390,24 @@ namespace libtorrent int write(const char* buf, int slot, int offset, int size) { TORRENT_ASSERT(buf != 0); - TORRENT_ASSERT(slot >= 0 && slot < m_info->num_pieces()); + TORRENT_ASSERT(slot >= 0 && slot < m_files.num_pieces()); TORRENT_ASSERT(offset >= 0); - TORRENT_ASSERT(offset < m_info->piece_size(slot)); + TORRENT_ASSERT(offset < m_files.piece_size(slot)); TORRENT_ASSERT(size > 0); #ifndef NDEBUG std::vector slices - = m_info->map_block(slot, offset, size, true); + = files().map_block(slot, offset, size); TORRENT_ASSERT(!slices.empty()); #endif - size_type start = slot * (size_type)m_info->piece_length() + offset; - TORRENT_ASSERT(start + size <= m_info->total_size()); + size_type start = slot * (size_type)m_files.piece_length() + offset; + TORRENT_ASSERT(start + size <= m_files.total_size()); // find the file iterator and file offset size_type file_offset = start; std::vector::const_iterator file_iter; - for (file_iter = m_info->begin_files(true);;) + for (file_iter = files().begin();;) { if (file_offset < file_iter->size) break; @@ -447,7 +449,7 @@ namespace libtorrent TORRENT_ASSERT(int(slices.size()) > counter); size_type slice_size = slices[counter].size; TORRENT_ASSERT(slice_size == write_bytes); - TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path + TORRENT_ASSERT(files().at(slices[counter].file_index).path == file_iter->path); #endif @@ -466,7 +468,7 @@ namespace libtorrent if (left_to_write > 0) { ++file_iter; - while (file_iter != m_info->end_files(true) && file_iter->size == 0) + while (file_iter != files().end() && file_iter->size == 0) ++file_iter; #ifndef NDEBUG // empty files are not returned by map_block, so if @@ -531,11 +533,11 @@ namespace libtorrent m_pool.release(this); #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400 - old_path = safe_convert((m_save_path / m_info->name()).string()); - new_path = safe_convert((save_path / m_info->name()).string()); + old_path = safe_convert((m_save_path / files().name()).string()); + new_path = safe_convert((save_path / files().name()).string()); #else - old_path = m_save_path / m_info->name(); - new_path = save_path / m_info->name(); + old_path = m_save_path / files().name(); + new_path = save_path / files().name(); #endif try @@ -602,7 +604,7 @@ namespace libtorrent } entry::list_type const& slots = slots_ent->list(); - bool seed = int(slots.size()) == m_info->num_pieces() + 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) @@ -615,11 +617,11 @@ namespace libtorrent if (seed) { - if (m_info->num_files(true) != (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_info->num_files(true)) + ")"; + + boost::lexical_cast(files().num_files()) + ")"; return false; } @@ -627,8 +629,8 @@ namespace libtorrent fs = file_sizes.begin(); // the resume data says we have the entire torrent // make sure the file sizes are the right ones - for (torrent_info::file_iterator i = m_info->begin_files(true) - , end(m_info->end_files(true)); i != end; ++i, ++fs) + for (file_storage::iterator i = files().begin() + , end(files().end()); i != end; ++i, ++fs) { if (i->size != fs->first) { @@ -641,7 +643,7 @@ namespace libtorrent return true; } - return match_filesizes(*m_info, m_save_path, file_sizes + return match_filesizes(files(), m_save_path, file_sizes , !full_allocation_mode, &error); } @@ -653,7 +655,7 @@ namespace libtorrent return true; } std::vector > file_sizes - = get_filesizes(*m_info, m_save_path); + = get_filesizes(m_files, m_save_path); entry::list_type& fl = rd["file sizes"].list(); for (std::vector >::iterator i @@ -670,7 +672,7 @@ namespace libtorrent bool move_slot(int src_slot, int dst_slot) { // TODO: this can be optimized by mapping both slots and do a straight memcpy - int piece_size = m_info->piece_size(dst_slot); + int piece_size = m_files.piece_size(dst_slot); m_scratch_buffer.resize(piece_size); size_type ret1 = read(&m_scratch_buffer[0], src_slot, 0, piece_size); size_type ret2 = write(&m_scratch_buffer[0], dst_slot, 0, piece_size); @@ -681,9 +683,9 @@ namespace libtorrent { // TODO: this can be optimized by mapping both slots and do a straight memcpy // the size of the target slot is the size of the piece - int piece_size = m_info->piece_length(); - int piece1_size = m_info->piece_size(slot2); - int piece2_size = m_info->piece_size(slot1); + int piece_size = m_files.piece_length(); + int piece1_size = m_files.piece_size(slot2); + int piece2_size = m_files.piece_size(slot1); m_scratch_buffer.resize(piece_size * 2); size_type ret1 = read(&m_scratch_buffer[0], slot1, 0, piece1_size); size_type ret2 = read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size); @@ -697,10 +699,10 @@ namespace libtorrent { // TODO: this can be optimized by mapping both slots and do a straight memcpy // the size of the target slot is the size of the piece - int piece_size = m_info->piece_length(); - int piece1_size = m_info->piece_size(slot2); - int piece2_size = m_info->piece_size(slot3); - int piece3_size = m_info->piece_size(slot1); + int piece_size = m_files.piece_length(); + int piece1_size = m_files.piece_size(slot2); + int piece2_size = m_files.piece_size(slot3); + int piece3_size = m_files.piece_size(slot1); m_scratch_buffer.resize(piece_size * 2); size_type ret1 = read(&m_scratch_buffer[0], slot1, 0, piece1_size); size_type ret2 = read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size); @@ -743,6 +745,39 @@ namespace libtorrent #endif } + bool rename_file(int index, std::string const& new_filename) + { + if (index < 0 || index >= m_files.num_files()) return true; + fs::path old_name = m_save_path / files().at(index).path; + m_pool.release(this); + +#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400 + fs::wpath old_path = safe_convert(old_name); + fs::wpath new_path = safe_convert(m_save_path / new_filename); +#else + fs::path const& old_path = old_name; + fs::path new_path = m_save_path / new_filename; +#endif + +#ifndef BOOST_NO_EXCEPTIONS + try + { +#endif + rename(old_path, new_path); + if (!m_mapped_files) + { m_mapped_files.reset(new file_storage(m_files)); } + m_mapped_files->rename_file(index, new_filename); +#ifndef BOOST_NO_EXCEPTIONS + } + catch (std::exception& e) + { + set_error(old_name.string(), e.what()); + return true; + } +#endif + return false; + } + bool release_files() { m_pool.release(this); @@ -762,8 +797,8 @@ namespace libtorrent // delete the files from disk std::set directories; typedef std::set::iterator iter_t; - for (torrent_info::file_iterator i = m_info->begin_files(true) - , end(m_info->end_files(true)); i != end; ++i) + for (file_storage::iterator i = m_files.begin() + , end(m_files.end()); i != end; ++i) { std::string p = (m_save_path / i->path).string(); fs::path bp = i->path.branch_path(); @@ -802,7 +837,10 @@ namespace libtorrent private: - boost::intrusive_ptr m_info; + file_storage const& files() const { return m_mapped_files?*m_mapped_files:m_files; } + + boost::scoped_ptr m_mapped_files; + file_storage const& m_files; fs::path m_save_path; // temporary storage for moving pieces @@ -811,10 +849,10 @@ namespace libtorrent static mapped_file_pool m_pool; }; - storage_interface* mapped_storage_constructor(boost::intrusive_ptr ti + storage_interface* mapped_storage_constructor(file_storage const& fs , fs::path const& path, file_pool& fp) { - return new mapped_storage(ti, path); + return new mapped_storage(fs, path); } mapped_file_pool mapped_storage::m_pool; diff --git a/libtorrent/src/natpmp.cpp b/libtorrent/src/natpmp.cpp index 56f109761..55b274774 100644 --- a/libtorrent/src/natpmp.cpp +++ b/libtorrent/src/natpmp.cpp @@ -32,7 +32,9 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/pch.hpp" +#include #include + #if BOOST_VERSION < 103500 #include #else diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index 29c7689fd..1a72ca148 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -326,7 +326,7 @@ namespace libtorrent TORRENT_ASSERT(t); bool interested = false; - const std::vector& we_have = t->pieces(); + bitfield const& we_have = t->pieces(); for (int j = 0; j != (int)we_have.size(); ++j) { if (!we_have[j] @@ -579,7 +579,7 @@ namespace libtorrent m_statistics.add_stat(downloaded, uploaded); } - std::vector const& peer_connection::get_bitfield() const + bitfield const& peer_connection::get_bitfield() const { return m_have_piece; } @@ -749,7 +749,7 @@ namespace libtorrent // if we don't have valid metadata yet, // leave the vector unallocated TORRENT_ASSERT(m_num_pieces == 0); - std::fill(m_have_piece.begin(), m_have_piece.end(), false); + m_have_piece.clear_all(); TORRENT_ASSERT(!m_torrent.expired()); } @@ -1082,7 +1082,7 @@ namespace libtorrent } else { - m_have_piece[index] = true; + m_have_piece.set_bit(index); // only update the piece_picker if // we have the metadata and if @@ -1127,7 +1127,7 @@ namespace libtorrent // --------- BITFIELD ---------- // ----------------------------- - void peer_connection::incoming_bitfield(std::vector const& bitfield) + void peer_connection::incoming_bitfield(bitfield const& bits) { INVARIANT_CHECK; @@ -1138,7 +1138,7 @@ namespace libtorrent for (extension_list_t::iterator i = m_extensions.begin() , end(m_extensions.end()); i != end; ++i) { - if ((*i)->on_bitfield(bitfield)) return; + if ((*i)->on_bitfield(bits)) return; } #endif @@ -1147,9 +1147,9 @@ namespace libtorrent #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << time_now_string() << " <== BITFIELD "; - for (int i = 0; i < int(bitfield.size()); ++i) + for (int i = 0; i < int(bits.size()); ++i) { - if (bitfield[i]) (*m_logger) << "1"; + if (bits[i]) (*m_logger) << "1"; else (*m_logger) << "0"; } (*m_logger) << "\n"; @@ -1158,10 +1158,10 @@ namespace libtorrent // if we don't have the metedata, we cannot // verify the bitfield size if (t->valid_metadata() - && (bitfield.size() / 8) != (m_have_piece.size() / 8)) + && (bits.size() / 8) != (m_have_piece.size() / 8)) { std::stringstream msg; - msg << "got bitfield with invalid size: " << (bitfield.size() / 8) + msg << "got bitfield with invalid size: " << (bits.size() / 8) << "bytes. expected: " << (m_have_piece.size() / 8) << " bytes"; disconnect(msg.str().c_str(), 2); @@ -1174,15 +1174,15 @@ namespace libtorrent // (since it doesn't exist yet) if (!t->ready_for_connections()) { - m_have_piece = bitfield; - m_num_pieces = std::count(bitfield.begin(), bitfield.end(), true); - if (m_peer_info) m_peer_info->seed = (m_num_pieces == int(bitfield.size())); + m_have_piece = bits; + m_num_pieces = bits.count(); + if (m_peer_info) m_peer_info->seed = (m_num_pieces == int(bits.size())); return; } TORRENT_ASSERT(t->valid_metadata()); - int num_pieces = std::count(bitfield.begin(), bitfield.end(), true); + int num_pieces = bits.count(); if (num_pieces == int(m_have_piece.size())) { #ifdef TORRENT_VERBOSE_LOGGING @@ -1197,7 +1197,7 @@ namespace libtorrent return; } - std::fill(m_have_piece.begin(), m_have_piece.end(), true); + m_have_piece.set_all(); m_num_pieces = num_pieces; t->peer_has_all(); if (!t->is_finished()) @@ -1211,11 +1211,11 @@ namespace libtorrent bool interesting = false; if (!t->is_seed()) { - t->peer_has(bitfield); + t->peer_has(bits); for (int i = 0; i < (int)m_have_piece.size(); ++i) { - bool have = bitfield[i]; + bool have = bits[i]; if (have && !m_have_piece[i]) { if (!t->have_piece(i) && t->picker().piece_priority(i) != 0) @@ -1229,7 +1229,7 @@ namespace libtorrent } } - m_have_piece = bitfield; + m_have_piece = bits; m_num_pieces = num_pieces; if (interesting) t->get_policy().peer_is_interesting(*this); @@ -1764,7 +1764,7 @@ namespace libtorrent } TORRENT_ASSERT(!m_have_piece.empty()); - std::fill(m_have_piece.begin(), m_have_piece.end(), true); + m_have_piece.set_all(); m_num_pieces = m_have_piece.size(); t->peer_has_all(); diff --git a/libtorrent/src/piece_picker.cpp b/libtorrent/src/piece_picker.cpp index bbacb9889..0b75b425e 100755 --- a/libtorrent/src/piece_picker.cpp +++ b/libtorrent/src/piece_picker.cpp @@ -42,6 +42,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/piece_picker.hpp" #include "libtorrent/aux_/session_impl.hpp" +#include "libtorrent/bitfield.hpp" #ifndef NDEBUG #include "libtorrent/peer_connection.hpp" @@ -122,16 +123,17 @@ namespace libtorrent } // pieces is a bitmask with the pieces we have - void piece_picker::init(std::vector const& pieces) + void piece_picker::init(bitfield const& pieces) { TORRENT_PIECE_PICKER_INVARIANT_CHECK; #ifndef NDEBUG m_files_checked_called = true; #endif - for (std::vector::const_iterator i = pieces.begin(); - i != pieces.end(); ++i) + int index = 0; + for (bitfield::const_iterator i = pieces.begin(); + i != pieces.end(); ++i, ++index) { - int index = static_cast(i - pieces.begin()); + TORRENT_ASSERT(index < pieces.size()); piece_pos& p = m_piece_map[index]; if (*i) we_have(index); else TORRENT_ASSERT(p.index == 0); @@ -214,15 +216,15 @@ namespace libtorrent #ifndef NDEBUG void piece_picker::verify_pick(std::vector const& picked - , std::vector const& bitfield) const + , bitfield const& bits) const { - TORRENT_ASSERT(bitfield.size() == m_piece_map.size()); + TORRENT_ASSERT(bits.size() == m_piece_map.size()); for (std::vector::const_iterator i = picked.begin() , end(picked.end()); i != end; ++i) { TORRENT_ASSERT(i->piece_index >= 0); - TORRENT_ASSERT(i->piece_index < int(bitfield.size())); - TORRENT_ASSERT(bitfield[i->piece_index]); + TORRENT_ASSERT(i->piece_index < int(bits.size())); + TORRENT_ASSERT(bits[i->piece_index]); TORRENT_ASSERT(!m_piece_map[i->piece_index].have()); } } @@ -887,14 +889,14 @@ namespace libtorrent if (prev_priority >= 0) update(prev_priority, p.index); } - void piece_picker::inc_refcount(std::vector const& bitmask) + void piece_picker::inc_refcount(bitfield const& bitmask) { TORRENT_PIECE_PICKER_INVARIANT_CHECK; TORRENT_ASSERT(bitmask.size() == m_piece_map.size()); int index = 0; bool updated = false; - for (std::vector::const_iterator i = bitmask.begin() + for (bitfield::const_iterator i = bitmask.begin() , end(bitmask.end()); i != end; ++i, ++index) { if (*i) @@ -907,14 +909,14 @@ namespace libtorrent if (updated && m_sequential_download == -1) m_dirty = true; } - void piece_picker::dec_refcount(std::vector const& bitmask) + void piece_picker::dec_refcount(bitfield const& bitmask) { TORRENT_PIECE_PICKER_INVARIANT_CHECK; TORRENT_ASSERT(bitmask.size() == m_piece_map.size()); int index = 0; bool updated = false; - for (std::vector::const_iterator i = bitmask.begin() + for (bitfield::const_iterator i = bitmask.begin() , end(bitmask.end()); i != end; ++i, ++index) { if (*i) @@ -1156,7 +1158,7 @@ namespace libtorrent // to pick blocks from the same pieces as fast peers, and vice // versa. Downloading pieces are marked as being fast, medium // or slow once they're started. - void piece_picker::pick_pieces(const std::vector& pieces + void piece_picker::pick_pieces(bitfield const& pieces , std::vector& interesting_blocks , int num_blocks, int prefer_whole_pieces , void* peer, piece_state_t speed, bool rarest_first @@ -1279,7 +1281,7 @@ namespace libtorrent , backup_blocks.begin(), backup_blocks.end()); } - bool piece_picker::can_pick(int piece, std::vector const& bitmask) const + bool piece_picker::can_pick(int piece, bitfield const& bitmask) const { TORRENT_ASSERT(piece >= 0 && piece < int(m_piece_map.size())); return bitmask[piece] @@ -1326,7 +1328,7 @@ namespace libtorrent } int piece_picker::add_blocks(std::vector const& piece_list - , std::vector const& pieces + , bitfield const& pieces , std::vector& interesting_blocks , int num_blocks, int prefer_whole_pieces , void* peer, std::vector const& ignore) const @@ -1388,7 +1390,7 @@ namespace libtorrent return num_blocks; } - int piece_picker::add_blocks_downloading(std::vector const& pieces + int piece_picker::add_blocks_downloading(bitfield const& pieces , std::vector& interesting_blocks , std::vector& backup_blocks , int num_blocks, int prefer_whole_pieces @@ -1580,7 +1582,7 @@ namespace libtorrent } std::pair piece_picker::expand_piece(int piece, int whole_pieces - , std::vector const& have) const + , bitfield const& have) const { if (whole_pieces == 0) return std::make_pair(piece, piece + 1); diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp index c87eb4056..8c01d09ec 100755 --- a/libtorrent/src/policy.cpp +++ b/libtorrent/src/policy.cpp @@ -150,18 +150,7 @@ namespace tcp::endpoint const& m_ep; }; - struct match_peer_id - { - match_peer_id(peer_id const& id_) - : m_id(id_) - {} - - bool operator()(std::pair const& p) const - { return p.second.connection && p.second.connection->pid() == m_id; } - - peer_id const& m_id; - }; - +#ifndef NDEBUG struct match_peer_connection { match_peer_connection(peer_connection const& c) @@ -177,7 +166,7 @@ namespace peer_connection const& m_conn; }; - +#endif } @@ -244,7 +233,7 @@ namespace libtorrent busy_pieces.reserve(num_requests); std::vector const& suggested = c.suggested_pieces(); - std::vector const& bitfield = c.get_bitfield(); + bitfield const& bits = c.get_bitfield(); if (c.has_peer_choked()) { @@ -254,10 +243,10 @@ namespace libtorrent std::vector const& allowed_fast = c.allowed_fast(); // build a bitmask with only the allowed pieces in it - std::vector mask(c.get_bitfield().size(), false); + bitfield mask(c.get_bitfield().size(), false); for (std::vector::const_iterator i = allowed_fast.begin() , end(allowed_fast.end()); i != end; ++i) - if (bitfield[*i]) mask[*i] = true; + if (bits[*i]) mask.set_bit(*i); p.pick_pieces(mask, interesting_pieces , num_requests, prefer_whole_pieces, c.peer_info_struct() @@ -273,7 +262,7 @@ namespace libtorrent // the last argument is if we should prefer whole pieces // for this peer. If we're downloading one piece in 20 seconds // then use this mode. - p.pick_pieces(bitfield, interesting_pieces + p.pick_pieces(bits, interesting_pieces , num_requests, prefer_whole_pieces, c.peer_info_struct() , state, rarest_first, c.on_parole(), suggested); } @@ -445,21 +434,57 @@ namespace libtorrent if (m_round_robin == m_peers.end()) m_round_robin = m_peers.begin(); +#ifndef TORRENT_DISABLE_DHT + bool pinged = false; +#endif + for (int iterations = (std::min)(int(m_peers.size()), 300); - iterations > 0; ++m_round_robin, --iterations) + iterations > 0; --iterations) { if (m_round_robin == m_peers.end()) m_round_robin = m_peers.begin(); - if (!is_connect_candidate(m_round_robin->second, finished)) continue; + peer& pe = m_round_robin->second; + iterator current = m_round_robin; + +#ifndef TORRENT_DISABLE_DHT + // try to send a DHT ping to this peer + // as well, to figure out if it supports + // DHT (uTorrent and BitComet doesn't + // advertise support) + if (!pinged && !pe.added_to_dht) + { + udp::endpoint node(pe.ip.address(), pe.ip.port()); + m_torrent->session().add_dht_node(node); + pe.added_to_dht = true; + pinged = true; + } +#endif + // this timeout has to be customizable! + // don't remove banned peers, they should + // remain banned + if (pe.connection == 0 + && pe.connected != min_time() + && !pe.banned + && (now - pe.connected > minutes(120) + || m_peers.size() >= m_torrent->settings().max_peerlist_size * 0.9)) + { + erase_peer(m_round_robin++); + continue; + } + + ++m_round_robin; + + + if (!is_connect_candidate(pe, finished)) continue; if (candidate != m_peers.end() - && !compare_peer(candidate->second, m_round_robin->second, external_ip)) continue; + && !compare_peer(candidate->second, pe, external_ip)) continue; - if (now - m_round_robin->second.connected < - seconds(m_round_robin->second.failcount * min_reconnect_time)) + if (now - pe.connected < + seconds(pe.failcount * min_reconnect_time)) continue; - candidate = m_round_robin; + candidate = current; } #if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING @@ -484,45 +509,6 @@ namespace libtorrent if (m_torrent->is_paused()) return; -#ifndef TORRENT_DISABLE_DHT - bool pinged = false; -#endif - - ptime now = time_now(); - // remove old disconnected peers from the list - for (iterator i = m_peers.begin(); i != m_peers.end();) - { - peer& pe = i->second; - -#ifndef TORRENT_DISABLE_DHT - // try to send a DHT ping to this peer - // as well, to figure out if it supports - // DHT (uTorrent and BitComet doesn't - // advertise support) - if (!pinged && !pe.added_to_dht) - { - udp::endpoint node(pe.ip.address(), pe.ip.port()); - m_torrent->session().add_dht_node(node); - pe.added_to_dht = true; - pinged = true; - } -#endif - // this timeout has to be customizable! - // don't remove banned peers, they should - // remain banned - if (pe.connection == 0 - && pe.connected != min_time() - && !pe.banned - && now - pe.connected > minutes(120)) - { - erase_peer(i++); - } - else - { - ++i; - } - } - // ------------------------ // upload shift // ------------------------ @@ -658,6 +644,12 @@ namespace libtorrent error_code ec; TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint(ec) || ec); + if (m_peers.size() >= m_torrent->settings().max_peerlist_size) + { + c.disconnect("peer list size exceeded, refusing incoming connection"); + return false; + } + peer p(c.remote(), peer::not_connectable, 0); i = m_peers.insert(std::make_pair(c.remote().address(), p)); #ifndef TORRENT_DISABLE_GEO_IP @@ -750,7 +742,7 @@ namespace libtorrent if (ses.m_alerts.should_post(alert::info)) { ses.m_alerts.post_alert(peer_blocked_alert(remote.address() - , "outgoing port blocked, peer not added to peer list")); + , "outgoing port blocked, peer not added to peer list")); } return 0; } @@ -776,11 +768,14 @@ namespace libtorrent if (ses.m_alerts.should_post(alert::info)) { ses.m_alerts.post_alert(peer_blocked_alert(remote.address() - , "blocked peer not added to peer list")); + , "blocked peer not added to peer list")); } return 0; } + if (m_peers.size() >= m_torrent->settings().max_peerlist_size) + return 0; + // we don't have any info about this peer. // add a new entry i = m_peers.insert(std::make_pair(remote.address() diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index 5e70cb6e7..446693e6e 100755 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -169,7 +169,6 @@ namespace aux { , m_auto_scrape_time_scaler(180) , m_incoming_connection(false) , m_last_tick(time_now()) - , m_torrent_sequence(0) #ifndef TORRENT_DISABLE_DHT , m_dht_same_port(true) , m_external_udp_port(0) @@ -1043,7 +1042,7 @@ namespace aux { else ++uncongested_torrents; - if (t.is_auto_managed() && t.is_paused()) + if (t.is_auto_managed() && t.is_paused() && !t.has_error()) { ++num_paused_auto_managed; if (!least_recently_scraped->second->is_auto_managed() @@ -1308,7 +1307,7 @@ namespace aux { { torrent* t = i->second.get(); TORRENT_ASSERT(t); - if (t->is_auto_managed()) + if (t->is_auto_managed() && !t->has_error()) { // this torrent is auto managed, add it to // the list (depending on if it's a seed or not) @@ -1661,7 +1660,7 @@ namespace aux { { TORRENT_ASSERT(!params.save_path.empty()); - if (params.ti && params.ti->num_files() == 0) + if (params.ti && params.ti->files().num_files() == 0) { #ifndef BOOST_NO_EXCEPTIONS throw std::runtime_error("no files in torrent"); @@ -1703,6 +1702,14 @@ namespace aux { #endif } + int queue_pos = 0; + for (torrent_map::const_iterator i = m_torrents.begin() + , end(m_torrents.end()); i != end; ++i) + { + int pos = i->second->queue_position(); + if (pos >= queue_pos) queue_pos = pos + 1; + } + // create the torrent and the data associated with // the checker thread and store it before starting // the thread @@ -1711,17 +1718,16 @@ namespace aux { torrent_ptr.reset(new torrent(*this, params.ti, params.save_path , m_listen_interface, params.storage_mode, 16 * 1024 , params.storage, params.paused, params.resume_data - , m_torrent_sequence, params.auto_managed)); + , queue_pos, params.auto_managed)); } else { torrent_ptr.reset(new torrent(*this, params.tracker_url, *ih, params.name , params.save_path, m_listen_interface, params.storage_mode, 16 * 1024 , params.storage, params.paused, params.resume_data - , m_torrent_sequence, params.auto_managed)); + , queue_pos, params.auto_managed)); } torrent_ptr->start(); - ++m_torrent_sequence; #ifndef TORRENT_DISABLE_EXTENSIONS for (extension_list_t::iterator i = m_extensions.begin() @@ -1745,6 +1751,11 @@ namespace aux { m_torrents.insert(std::make_pair(*ih, torrent_ptr)); + // if this is an auto managed torrent, force a recalculation + // of which torrents to have active + if (params.auto_managed && m_auto_manage_time_scaler > 2) + m_auto_manage_time_scaler = 2; + return torrent_handle(torrent_ptr); } @@ -1816,6 +1827,7 @@ namespace aux { #ifndef NDEBUG sha1_hash i_hash = t.torrent_file().info_hash(); #endif + i->second->set_queue_position(-1); m_torrents.erase(i); TORRENT_ASSERT(m_torrents.find(i_hash) == m_torrents.end()); return; @@ -2440,6 +2452,22 @@ namespace aux { #ifndef NDEBUG void session_impl::check_invariant() const { + std::set unique; + int total_downloaders = 0; + for (torrent_map::const_iterator i = m_torrents.begin() + , end(m_torrents.end()); i != end; ++i) + { + int pos = i->second->queue_position(); + if (pos < 0) + { + TORRENT_ASSERT(pos == -1); + continue; + } + ++total_downloaders; + unique.insert(i->second->queue_position()); + } + TORRENT_ASSERT(unique.size() == total_downloaders); + TORRENT_ASSERT(m_max_connections > 0); TORRENT_ASSERT(m_max_uploads > 0); TORRENT_ASSERT(m_allowed_upload_slots >= m_max_uploads); diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp index e86d3d58d..bb9c49264 100755 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -251,12 +251,12 @@ namespace libtorrent { std::vector > get_filesizes( - torrent_info const& t, fs::path p) + file_storage const& s, fs::path p) { p = complete(p); std::vector > sizes; - for (torrent_info::file_iterator i = t.begin_files(true); - i != t.end_files(true); ++i) + for (file_storage::iterator i = s.begin() + , end(s.end());i != end; ++i) { size_type size = 0; std::time_t time = 0; @@ -289,13 +289,13 @@ namespace libtorrent // pieces, so any older version of the resume data will // still be a correct subset of the actual data on disk. bool match_filesizes( - torrent_info const& t + file_storage const& fs , fs::path p , std::vector > const& sizes , bool compact_mode , std::string* error) { - if ((int)sizes.size() != t.num_files(true)) + if ((int)sizes.size() != fs.num_files()) { if (error) *error = "mismatching number of files"; return false; @@ -304,8 +304,8 @@ namespace libtorrent std::vector >::const_iterator s = sizes.begin(); - for (torrent_info::file_iterator i = t.begin_files(true); - i != t.end_files(true); ++i, ++s) + for (file_storage::iterator i = fs.begin() + , end(fs.end());i != end; ++i, ++s) { size_type size = 0; std::time_t time = 0; @@ -354,15 +354,16 @@ namespace libtorrent class storage : public storage_interface, boost::noncopyable { public: - storage(boost::intrusive_ptr info, fs::path const& path, file_pool& fp) - : m_info(info) - , m_files(fp) + storage(file_storage const& fs, fs::path const& path, file_pool& fp) + : m_files(fs) + , m_pool(fp) { - TORRENT_ASSERT(info->begin_files(true) != info->end_files(true)); + TORRENT_ASSERT(m_files.begin() != m_files.end()); m_save_path = fs::complete(path); TORRENT_ASSERT(m_save_path.is_complete()); } + bool rename_file(int index, std::string const& new_filename); bool release_files(); bool delete_files(); bool initialize(bool allocate_files); @@ -379,14 +380,18 @@ namespace libtorrent int read_impl(char* buf, int slot, int offset, int size, bool fill_zero); ~storage() - { m_files.release(this); } + { m_pool.release(this); } + + file_storage const& files() const { return m_mapped_files?*m_mapped_files:m_files; } + + boost::scoped_ptr m_mapped_files; + file_storage const& m_files; - boost::intrusive_ptr m_info; fs::path m_save_path; // the file pool is typically stored in // the session, to make all storage // instances use the same pool - file_pool& m_files; + file_pool& m_pool; // temporary storage for moving pieces buffer m_scratch_buffer; @@ -399,7 +404,7 @@ namespace libtorrent hasher whole; int slot_size1 = piece_size; m_scratch_buffer.resize(slot_size1); - int read_result = read_impl(&m_scratch_buffer[0], slot, 0, slot_size1, true); + read_impl(&m_scratch_buffer[0], slot, 0, slot_size1, true); if (ph.offset > 0) partial.update(&m_scratch_buffer[0], ph.offset); whole.update(&m_scratch_buffer[0], slot_size1); @@ -426,8 +431,8 @@ namespace libtorrent { // first, create all missing directories fs::path last_path; - for (torrent_info::file_iterator file_iter = m_info->begin_files(true), - end_iter = m_info->end_files(true); file_iter != end_iter; ++file_iter) + for (file_storage::iterator file_iter = files().begin(), + end_iter = files().end(); file_iter != end_iter; ++file_iter) { fs::path dir = (m_save_path / file_iter->path).branch_path(); @@ -475,7 +480,7 @@ namespace libtorrent if (allocate_files) { std::string error; - boost::shared_ptr f = m_files.open_file(this + boost::shared_ptr f = m_pool.open_file(this , m_save_path / file_iter->path, file::in | file::out , error); if (f && f->error().empty()) @@ -491,13 +496,46 @@ namespace libtorrent #endif } // close files that were opened in write mode - m_files.release(this); + m_pool.release(this); + return false; + } + + bool storage::rename_file(int index, std::string const& new_filename) + { + if (index < 0 || index >= m_files.num_files()) return true; + fs::path old_name = m_save_path / files().at(index).path; + m_pool.release(old_name); + +#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400 + fs::wpath old_path = safe_convert(old_name); + fs::wpath new_path = safe_convert(m_save_path / new_filename); +#else + fs::path const& old_path = old_name; + fs::path new_path = m_save_path / new_filename; +#endif + +#ifndef BOOST_NO_EXCEPTIONS + try + { +#endif + rename(old_path, new_path); + if (!m_mapped_files) + { m_mapped_files.reset(new file_storage(m_files)); } + m_mapped_files->rename_file(index, new_filename); +#ifndef BOOST_NO_EXCEPTIONS + } + catch (std::exception& e) + { + set_error(old_name.string(), e.what()); + return true; + } +#endif return false; } bool storage::release_files() { - m_files.release(this); + m_pool.release(this); buffer().swap(m_scratch_buffer); return false; } @@ -505,7 +543,7 @@ namespace libtorrent bool storage::delete_files() { // make sure we don't have the files open - m_files.release(this); + m_pool.release(this); buffer().swap(m_scratch_buffer); int result = 0; @@ -515,8 +553,8 @@ namespace libtorrent // delete the files from disk std::set directories; typedef std::set::iterator iter_t; - for (torrent_info::file_iterator i = m_info->begin_files(true) - , end(m_info->end_files(true)); i != end; ++i) + for (file_storage::iterator i = files().begin() + , end(files().end()); i != end; ++i) { std::string p = (m_save_path / i->path).string(); fs::path bp = i->path.branch_path(); @@ -584,7 +622,7 @@ namespace libtorrent TORRENT_ASSERT(rd.type() == entry::dictionary_t); std::vector > file_sizes - = get_filesizes(*m_info, m_save_path); + = get_filesizes(files(), m_save_path); entry::list_type& fl = rd["file sizes"].list(); for (std::vector >::iterator i @@ -642,7 +680,7 @@ namespace libtorrent } entry::list_type const& slots = slots_ent->list(); - bool seed = int(slots.size()) == m_info->num_pieces() + 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) @@ -655,11 +693,11 @@ namespace libtorrent if (seed) { - if (m_info->num_files(true) != (int)file_sizes.size()) + if (m_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_info->num_files(true)) + ")"; + + boost::lexical_cast(m_files.num_files()) + ")"; return false; } @@ -667,8 +705,8 @@ namespace libtorrent fs = file_sizes.begin(); // the resume data says we have the entire torrent // make sure the file sizes are the right ones - for (torrent_info::file_iterator i = m_info->begin_files(true) - , end(m_info->end_files(true)); i != end; ++i, ++fs) + for (file_storage::iterator i = files().begin() + , end(files().end()); i != end; ++i, ++fs) { if (i->size != fs->first) { @@ -680,7 +718,7 @@ namespace libtorrent } } - return match_filesizes(*m_info, m_save_path, file_sizes + return match_filesizes(files(), m_save_path, file_sizes , !full_allocation_mode, &error); } @@ -716,14 +754,14 @@ namespace libtorrent return false; #endif - m_files.release(this); + m_pool.release(this); #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400 - old_path = safe_convert((m_save_path / m_info->name()).string()); - new_path = safe_convert((save_path / m_info->name()).string()); + old_path = safe_convert((m_save_path / files().name()).string()); + new_path = safe_convert((save_path / files().name()).string()); #else - old_path = m_save_path / m_info->name(); - new_path = save_path / m_info->name(); + old_path = m_save_path / files().name(); + new_path = save_path / files().name(); #endif #ifndef BOOST_NO_EXCEPTIONS @@ -740,16 +778,20 @@ namespace libtorrent return true; #ifndef BOOST_NO_EXCEPTIONS } - catch (std::exception&) {} - return false; + catch (std::exception& e) + { + set_error((m_save_path / files().name()).string(), e.what()); + return true; + } #endif + return false; } #ifndef NDEBUG /* void storage::shuffle() { - int num_pieces = m_info->num_pieces(); + int num_pieces = files().num_pieces(); std::vector pieces(num_pieces); for (std::vector::iterator i = pieces.begin(); @@ -766,7 +808,7 @@ namespace libtorrent { const int slot_index = targets[i]; const int piece_index = pieces[i]; - const int slot_size =static_cast(m_info->piece_size(slot_index)); + const int slot_size =static_cast(m_files.piece_size(slot_index)); std::vector buf(slot_size); read(&buf[0], piece_index, 0, slot_size); write(&buf[0], slot_index, 0, slot_size); @@ -777,7 +819,7 @@ namespace libtorrent bool storage::move_slot(int src_slot, int dst_slot) { - int piece_size = m_info->piece_size(dst_slot); + int piece_size = m_files.piece_size(dst_slot); m_scratch_buffer.resize(piece_size); int ret1 = read_impl(&m_scratch_buffer[0], src_slot, 0, piece_size, true); int ret2 = write(&m_scratch_buffer[0], dst_slot, 0, piece_size); @@ -787,9 +829,9 @@ namespace libtorrent bool storage::swap_slots(int slot1, int slot2) { // the size of the target slot is the size of the piece - int piece_size = m_info->piece_length(); - int piece1_size = m_info->piece_size(slot2); - int piece2_size = m_info->piece_size(slot1); + int piece_size = m_files.piece_length(); + int piece1_size = m_files.piece_size(slot2); + int piece2_size = m_files.piece_size(slot1); m_scratch_buffer.resize(piece_size * 2); int ret1 = read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true); int ret2 = read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true); @@ -802,10 +844,10 @@ namespace libtorrent bool storage::swap_slots3(int slot1, int slot2, int slot3) { // the size of the target slot is the size of the piece - int piece_size = m_info->piece_length(); - int piece1_size = m_info->piece_size(slot2); - int piece2_size = m_info->piece_size(slot3); - int piece3_size = m_info->piece_size(slot1); + int piece_size = m_files.piece_length(); + int piece1_size = m_files.piece_size(slot2); + int piece2_size = m_files.piece_size(slot3); + int piece3_size = m_files.piece_size(slot1); m_scratch_buffer.resize(piece_size * 2); int ret1 = read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true); int ret2 = read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true); @@ -835,25 +877,25 @@ namespace libtorrent , bool fill_zero) { TORRENT_ASSERT(buf != 0); - TORRENT_ASSERT(slot >= 0 && slot < m_info->num_pieces()); + TORRENT_ASSERT(slot >= 0 && slot < m_files.num_pieces()); TORRENT_ASSERT(offset >= 0); - TORRENT_ASSERT(offset < m_info->piece_size(slot)); + TORRENT_ASSERT(offset < m_files.piece_size(slot)); TORRENT_ASSERT(size > 0); #ifndef NDEBUG std::vector slices - = m_info->map_block(slot, offset, size, true); + = files().map_block(slot, offset, size); TORRENT_ASSERT(!slices.empty()); #endif - size_type start = slot * (size_type)m_info->piece_length() + offset; - TORRENT_ASSERT(start + size <= m_info->total_size()); + size_type start = slot * (size_type)m_files.piece_length() + offset; + TORRENT_ASSERT(start + size <= m_files.total_size()); // find the file iterator and file offset size_type file_offset = start; std::vector::const_iterator file_iter; - for (file_iter = m_info->begin_files(true);;) + for (file_iter = files().begin();;) { if (file_offset < file_iter->size) break; @@ -864,7 +906,7 @@ namespace libtorrent int buf_pos = 0; std::string error; - boost::shared_ptr in(m_files.open_file( + boost::shared_ptr in(m_pool.open_file( this, m_save_path / file_iter->path, file::in , error)); if (!in) @@ -899,7 +941,7 @@ namespace libtorrent #endif int left_to_read = size; - int slot_size = static_cast(m_info->piece_size(slot)); + int slot_size = static_cast(m_files.piece_size(slot)); if (offset + left_to_read > slot_size) left_to_read = slot_size - offset; @@ -924,7 +966,7 @@ namespace libtorrent TORRENT_ASSERT(int(slices.size()) > counter); size_type slice_size = slices[counter].size; TORRENT_ASSERT(slice_size == read_bytes); - TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path + TORRENT_ASSERT(files().at(slices[counter].file_index).path == file_iter->path); #endif @@ -961,7 +1003,7 @@ namespace libtorrent file_offset = 0; std::string error; - in = m_files.open_file( + in = m_pool.open_file( this, path, file::in, error); if (!in) { @@ -997,35 +1039,35 @@ namespace libtorrent { TORRENT_ASSERT(buf != 0); TORRENT_ASSERT(slot >= 0); - TORRENT_ASSERT(slot < m_info->num_pieces()); + TORRENT_ASSERT(slot < m_files.num_pieces()); TORRENT_ASSERT(offset >= 0); TORRENT_ASSERT(size > 0); #ifndef NDEBUG std::vector slices - = m_info->map_block(slot, offset, size, true); + = files().map_block(slot, offset, size); TORRENT_ASSERT(!slices.empty()); #endif - size_type start = slot * (size_type)m_info->piece_length() + offset; + size_type start = slot * (size_type)m_files.piece_length() + offset; // find the file iterator and file offset size_type file_offset = start; std::vector::const_iterator file_iter; - for (file_iter = m_info->begin_files(true);;) + for (file_iter = files().begin();;) { if (file_offset < file_iter->size) break; file_offset -= file_iter->size; ++file_iter; - TORRENT_ASSERT(file_iter != m_info->end_files(true)); + TORRENT_ASSERT(file_iter != files().end()); } fs::path p(m_save_path / file_iter->path); std::string error; - boost::shared_ptr out = m_files.open_file( + boost::shared_ptr out = m_pool.open_file( this, p, file::out | file::in, error); if (!out) @@ -1050,7 +1092,7 @@ namespace libtorrent } int left_to_write = size; - int slot_size = static_cast(m_info->piece_size(slot)); + int slot_size = static_cast(m_files.piece_size(slot)); if (offset + left_to_write > slot_size) left_to_write = slot_size - offset; @@ -1074,7 +1116,7 @@ namespace libtorrent { TORRENT_ASSERT(int(slices.size()) > counter); TORRENT_ASSERT(slices[counter].size == write_bytes); - TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path + TORRENT_ASSERT(files().at(slices[counter].file_index).path == file_iter->path); TORRENT_ASSERT(buf_pos >= 0); @@ -1101,11 +1143,11 @@ namespace libtorrent #endif ++file_iter; - TORRENT_ASSERT(file_iter != m_info->end_files(true)); + TORRENT_ASSERT(file_iter != files().end()); fs::path p = m_save_path / file_iter->path; file_offset = 0; std::string error; - out = m_files.open_file( + out = m_pool.open_file( this, p, file::out | file::in, error); if (!out) @@ -1131,25 +1173,26 @@ namespace libtorrent return size; } - storage_interface* default_storage_constructor(boost::intrusive_ptr ti + storage_interface* default_storage_constructor(file_storage const& fs , fs::path const& path, file_pool& fp) { - return new storage(ti, path, fp); + return new storage(fs, path, fp); } // -- piece_manager ----------------------------------------------------- piece_manager::piece_manager( boost::shared_ptr const& torrent - , boost::intrusive_ptr ti + , boost::intrusive_ptr info , fs::path const& save_path , file_pool& fp , disk_io_thread& io , storage_constructor_type sc , storage_mode_t sm) - : m_storage(sc(ti, save_path, fp)) + : m_info(info) + , m_files(m_info->files()) + , m_storage(sc(m_files, save_path, fp)) , m_storage_mode(sm) - , m_info(ti) , m_save_path(complete(save_path)) , m_state(state_none) , m_current_slot(0) @@ -1213,6 +1256,17 @@ namespace libtorrent m_io_thread.add_job(j, handler); } + void piece_manager::async_rename_file(int index, std::string const& name + , boost::function const& handler) + { + disk_io_job j; + j.storage = this; + j.piece = index; + j.str = name; + j.action = disk_io_job::rename_file; + m_io_thread.add_job(j, handler); + } + void piece_manager::async_check_files( boost::function const& handler) { @@ -1241,6 +1295,8 @@ namespace libtorrent m_io_thread.add_job(j, handler); #ifndef NDEBUG boost::recursive_mutex::scoped_lock l(m_mutex); + // if this assert is hit, it suggests + // that check_files was not successful TORRENT_ASSERT(slot_for(r.piece) >= 0); #endif } @@ -1295,7 +1351,7 @@ namespace libtorrent int slot = slot_for(piece); TORRENT_ASSERT(slot != has_no_slot); - return m_storage->hash_for_slot(slot, ph, m_info->piece_size(piece)); + return m_storage->hash_for_slot(slot, ph, m_files.piece_size(piece)); } bool piece_manager::move_storage_impl(fs::path const& save_path) @@ -1373,7 +1429,7 @@ namespace libtorrent TORRENT_ASSERT(buf); TORRENT_ASSERT(offset >= 0); TORRENT_ASSERT(size > 0); - TORRENT_ASSERT(piece_index >= 0 && piece_index < m_info->num_pieces()); + TORRENT_ASSERT(piece_index >= 0 && piece_index < m_files.num_pieces()); int slot = allocate_slot_for_piece(piece_index); int ret = m_storage->write(buf, slot, offset, size); @@ -1455,9 +1511,9 @@ namespace libtorrent { // INVARIANT_CHECK; - const int piece_size = static_cast(m_info->piece_length()); - const int last_piece_size = static_cast(m_info->piece_size( - m_info->num_pieces() - 1)); + const int piece_size = static_cast(m_files.piece_length()); + const int last_piece_size = static_cast(m_files.piece_size( + m_files.num_pieces() - 1)); TORRENT_ASSERT((int)piece_data.size() >= last_piece_size); @@ -1579,8 +1635,8 @@ namespace libtorrent int piece_manager::check_no_fastresume(std::string& error) { - torrent_info::file_iterator i = m_info->begin_files(true); - torrent_info::file_iterator end = m_info->end_files(true); + file_storage::iterator i = m_files.begin(); + file_storage::iterator end = m_files.end(); for (; i != end; ++i) { @@ -1612,9 +1668,9 @@ namespace libtorrent { m_state = state_full_check; m_piece_to_slot.clear(); - m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot); + m_piece_to_slot.resize(m_files.num_pieces(), has_no_slot); m_slot_to_piece.clear(); - m_slot_to_piece.resize(m_info->num_pieces(), unallocated); + m_slot_to_piece.resize(m_files.num_pieces(), unallocated); if (m_storage_mode == storage_mode_compact) { m_unallocated_slots.clear(); @@ -1629,12 +1685,12 @@ namespace libtorrent // in compact mode without checking, we need to // populate the unallocated list TORRENT_ASSERT(m_unallocated_slots.empty()); - for (int i = 0, end(m_info->num_pieces()); i < end; ++i) + for (int i = 0, end(m_files.num_pieces()); i < end; ++i) m_unallocated_slots.push_back(i); m_piece_to_slot.clear(); - m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot); + m_piece_to_slot.resize(m_files.num_pieces(), has_no_slot); m_slot_to_piece.clear(); - m_slot_to_piece.resize(m_info->num_pieces(), unallocated); + m_slot_to_piece.resize(m_files.num_pieces(), unallocated); } return check_init_storage(error); @@ -1675,7 +1731,7 @@ namespace libtorrent INVARIANT_CHECK; - TORRENT_ASSERT(m_info->piece_length() > 0); + 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); @@ -1686,38 +1742,11 @@ namespace libtorrent return check_no_fastresume(error); } - entry const* file_format = rd.find_key("file-format"); - - if (file_format == 0 || file_format->type() != entry::string_t) - { - error = "missing file format tag"; - return check_no_fastresume(error); - } - - if (file_format->string() != "libtorrent resume file") - { - error = "invalid file format tag"; - return check_no_fastresume(error); - } - - entry const* info_hash = rd.find_key("info-hash"); - if (info_hash == 0 || info_hash->type() != entry::string_t) - { - error = "missing info-hash"; - return check_no_fastresume(error); - } - - if (sha1_hash(info_hash->string()) != m_info->info_hash()) - { - error = "mismatching info-hash"; - return check_no_fastresume(error); - } - - int block_size = (std::min)(16 * 1024, m_info->piece_length()); + 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_info->piece_length() / block_size) + && blocks_per_piece_ent->integer() != m_files.piece_length() / block_size) { error = "invalid 'blocks per piece' entry"; return check_no_fastresume(error); @@ -1746,17 +1775,17 @@ namespace libtorrent return check_no_fastresume(error); } - if ((int)slots->list().size() > m_info->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(m_info->num_pieces()) + " )"; + + boost::lexical_cast(m_files.num_pieces()) + " )"; return check_no_fastresume(error); } if (storage_mode == storage_mode_compact) { - int num_pieces = int(m_info->num_pieces()); + 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; @@ -1877,7 +1906,7 @@ namespace libtorrent // is finished int piece_manager::check_files(int& current_slot, int& have_piece, std::string& error) { - TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_info->num_pieces()); + TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces()); current_slot = m_current_slot; have_piece = -1; @@ -1894,9 +1923,9 @@ namespace libtorrent if (other_piece >= 0) { if (m_scratch_buffer2.empty()) - m_scratch_buffer2.resize(m_info->piece_length()); + m_scratch_buffer2.resize(m_files.piece_length()); - int piece_size = m_info->piece_size(other_piece); + int piece_size = m_files.piece_size(other_piece); if (m_storage->read(&m_scratch_buffer2[0], piece, 0, piece_size) != piece_size) { @@ -1910,7 +1939,7 @@ namespace libtorrent // the slot where this piece belongs is // free. Just move the piece there. - int piece_size = m_info->piece_size(piece); + int piece_size = m_files.piece_size(piece); if (m_storage->write(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size) { error = m_storage->error(); @@ -1926,19 +1955,19 @@ namespace libtorrent return need_full_check; } - while (m_current_slot < m_info->num_pieces() + while (m_current_slot < m_files.num_pieces() && (m_slot_to_piece[m_current_slot] == m_current_slot || m_slot_to_piece[m_current_slot] < 0)) { ++m_current_slot; } - if (m_current_slot == m_info->num_pieces()) + if (m_current_slot == m_files.num_pieces()) { return check_init_storage(error); } - TORRENT_ASSERT(m_current_slot < m_info->num_pieces()); + TORRENT_ASSERT(m_current_slot < m_files.num_pieces()); int piece = m_slot_to_piece[m_current_slot]; TORRENT_ASSERT(piece >= 0); @@ -1949,9 +1978,9 @@ namespace libtorrent // where this one goes. Store it in the scratch // buffer until next iteration. if (m_scratch_buffer.empty()) - m_scratch_buffer.resize(m_info->piece_length()); + m_scratch_buffer.resize(m_files.piece_length()); - int piece_size = m_info->piece_size(other_piece); + int piece_size = m_files.piece_size(other_piece); if (m_storage->read(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size) { error = m_storage->error(); @@ -1975,7 +2004,7 @@ namespace libtorrent TORRENT_ASSERT(m_state == state_full_check); bool skip = check_one_piece(have_piece); - TORRENT_ASSERT(m_current_slot <= m_info->num_pieces()); + TORRENT_ASSERT(m_current_slot <= m_files.num_pieces()); if (skip) { @@ -1984,9 +2013,9 @@ namespace libtorrent // completely. We should skip all pieces belonging to that file. // find the file that failed, and skip all the pieces in that file size_type file_offset = 0; - size_type current_offset = size_type(m_current_slot) * m_info->piece_length(); - for (torrent_info::file_iterator i = m_info->begin_files(true); - i != m_info->end_files(true); ++i) + size_type current_offset = size_type(m_current_slot) * m_files.piece_length(); + for (file_storage::iterator i = m_files.begin() + , end(m_files.end()); i != end; ++i) { file_offset += i->size; if (file_offset > current_offset) break; @@ -1994,8 +2023,8 @@ namespace libtorrent TORRENT_ASSERT(file_offset > current_offset); int skip_blocks = static_cast( - (file_offset - current_offset + m_info->piece_length() - 1) - / m_info->piece_length()); + (file_offset - current_offset + m_files.piece_length() - 1) + / m_files.piece_length()); if (m_storage_mode == storage_mode_compact) { @@ -2008,15 +2037,15 @@ namespace libtorrent // current slot will increase by one at the end of the for-loop too m_current_slot += skip_blocks - 1; - TORRENT_ASSERT(m_current_slot <= m_info->num_pieces()); + TORRENT_ASSERT(m_current_slot <= m_files.num_pieces()); } ++m_current_slot; current_slot = m_current_slot; - if (m_current_slot >= m_info->num_pieces()) + if (m_current_slot >= m_files.num_pieces()) { - TORRENT_ASSERT(m_current_slot == m_info->num_pieces()); + TORRENT_ASSERT(m_current_slot == m_files.num_pieces()); // clear the memory we've been using std::vector().swap(m_piece_data); @@ -2059,19 +2088,19 @@ namespace libtorrent // DO THE FULL CHECK // ------------------------ - TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_info->num_pieces()); - TORRENT_ASSERT(int(m_slot_to_piece.size()) == m_info->num_pieces()); + TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces()); + TORRENT_ASSERT(int(m_slot_to_piece.size()) == m_files.num_pieces()); TORRENT_ASSERT(have_piece == -1); // initialization for the full check if (m_hash_to_piece.empty()) { - for (int i = 0; i < m_info->num_pieces(); ++i) + for (int i = 0; i < m_files.num_pieces(); ++i) m_hash_to_piece.insert(std::make_pair(m_info->hash_for_piece(i), i)); } - m_piece_data.resize(int(m_info->piece_length())); - int piece_size = m_info->piece_size(m_current_slot); + m_piece_data.resize(int(m_files.piece_length())); + int piece_size = m_files.piece_size(m_current_slot); int num_read = m_storage->read(&m_piece_data[0] , m_current_slot, 0, piece_size); @@ -2348,7 +2377,7 @@ namespace libtorrent // special case to make sure we don't use the last slot // when we shouldn't, since it's smaller than ordinary slots - if (*iter == m_info->num_pieces() - 1 && piece_index != *iter) + if (*iter == m_files.num_pieces() - 1 && piece_index != *iter) { if (m_free_slots.size() == 1) allocate_slots(1); @@ -2481,14 +2510,14 @@ namespace libtorrent { boost::recursive_mutex::scoped_lock lock(m_mutex); - TORRENT_ASSERT(m_current_slot <= m_info->num_pieces()); + TORRENT_ASSERT(m_current_slot <= m_files.num_pieces()); if (m_unallocated_slots.empty() && m_free_slots.empty() && m_state == state_finished) { TORRENT_ASSERT(m_storage_mode != storage_mode_compact - || m_info->num_pieces() == 0); + || m_files.num_pieces() == 0); } if (m_storage_mode != storage_mode_compact) @@ -2508,8 +2537,8 @@ namespace libtorrent { if (m_piece_to_slot.empty()) return; - TORRENT_ASSERT((int)m_piece_to_slot.size() == m_info->num_pieces()); - TORRENT_ASSERT((int)m_slot_to_piece.size() == m_info->num_pieces()); + TORRENT_ASSERT((int)m_piece_to_slot.size() == m_files.num_pieces()); + TORRENT_ASSERT((int)m_slot_to_piece.size() == m_files.num_pieces()); for (std::vector::const_iterator i = m_free_slots.begin(); i != m_free_slots.end(); ++i) @@ -2531,7 +2560,7 @@ namespace libtorrent == m_unallocated_slots.end()); } - for (int i = 0; i < m_info->num_pieces(); ++i) + for (int i = 0; i < m_files.num_pieces(); ++i) { // Check domain of piece_to_slot's elements if (m_piece_to_slot[i] != has_no_slot) @@ -2620,7 +2649,7 @@ namespace libtorrent s << "index\tslot\tpiece\n"; - for (int i = 0; i < m_info->num_pieces(); ++i) + for (int i = 0; i < m_files.num_pieces(); ++i) { s << i << "\t" << m_slot_to_piece[i] << "\t"; s << m_piece_to_slot[i] << "\n"; diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index 25cb02558..54358e9fe 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -424,8 +424,34 @@ namespace libtorrent m_state = torrent_status::queued_for_checking; - if (m_resume_data.type() == entry::dictionary_t) read_resume_data(m_resume_data); - + if (m_resume_data.type() == entry::dictionary_t) + { + char const* error = 0; + entry const* file_format = m_resume_data.find_key("file-format"); + if (file_format->string() != "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)) + error = "missing info-hash"; + + if (!error && sha1_hash(info_hash->string()) != m_torrent_file->info_hash()) + error = "mismatching info-hash"; + + if (error && m_ses.m_alerts.should_post(alert::warning)) + { + m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), error)); +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING + (*m_ses.m_logger) << "fastresume data for " + << torrent_file().name() << " rejected: " + << error << "\n"; +#endif + } + + if (error) m_resume_data = entry(); + else read_resume_data(m_resume_data); + } + m_storage->async_check_fastresume(&m_resume_data , bind(&torrent::on_resume_data_checked , shared_from_this(), _1, _2)); @@ -447,9 +473,9 @@ namespace libtorrent " ]\n"; #endif } - std::fill(m_have_pieces.begin(), m_have_pieces.end(), false); + m_have_pieces.clear_all(); m_num_pieces = 0; - auto_managed(false); + m_error = j.str; pause(); return; } @@ -523,7 +549,7 @@ namespace libtorrent // or the resume_data was accepted m_num_pieces = 0; - std::fill(m_have_pieces.begin(), m_have_pieces.end(), false); + m_have_pieces.clear_all(); if (!fastresume_rejected) { TORRENT_ASSERT(m_resume_data.type() == entry::dictionary_t); @@ -531,14 +557,14 @@ namespace libtorrent // parse have bitmask entry const* pieces = m_resume_data.find_key("pieces"); if (pieces && pieces->type() == entry::string_t - && pieces->string().length() == m_torrent_file->num_pieces()) + && 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) { - bool have = pieces_str[i] & 1; - m_have_pieces[i] = have; - m_num_pieces += have; + if ((pieces_str[i] & 1) == 0) continue; + m_have_pieces.set_bit(i); + ++m_num_pieces; } } @@ -563,7 +589,7 @@ namespace libtorrent if (m_have_pieces[piece_index]) { - m_have_pieces[piece_index] = false; + m_have_pieces.clear_bit(piece_index); --m_num_pieces; } @@ -593,7 +619,7 @@ namespace libtorrent } int index = 0; - for (std::vector::iterator i = m_have_pieces.begin() + for (bitfield::const_iterator i = m_have_pieces.begin() , end(m_have_pieces.end()); i != end; ++i, ++index) { if (*i) m_picker->we_have(index); @@ -635,9 +661,9 @@ namespace libtorrent " ]\n"; #endif } - std::fill(m_have_pieces.begin(), m_have_pieces.end(), false); + m_have_pieces.clear_all(); m_num_pieces = 0; - auto_managed(false); + m_error = j.str; pause(); m_ses.done_checking(shared_from_this()); return; @@ -647,7 +673,7 @@ namespace libtorrent if (j.offset >= 0 && !m_have_pieces[j.offset]) { - m_have_pieces[j.offset] = true; + m_have_pieces.set_bit(j.offset); ++m_num_pieces; TORRENT_ASSERT(m_picker); m_picker->we_have(j.offset); @@ -1169,7 +1195,6 @@ namespace libtorrent ?"disk failed":"failed") << " ]\n"; #endif - bool was_seed = is_seed(); bool was_finished = m_picker->num_filtered() + num_pieces() == torrent_file().num_pieces(); @@ -1186,17 +1211,6 @@ namespace libtorrent TORRENT_ASSERT(valid_metadata()); // if we just became a seed, picker is now invalid, since it // is deallocated by the torrent once it starts seeding - if (!was_finished - && (is_seed() - || m_picker->num_filtered() + num_pieces() - == torrent_file().num_pieces())) - { - // torrent finished - // i.e. all the pieces we're interested in have - // been downloaded. Release the files (they will open - // in read only mode if needed) - finished(); - } } else if (passed_hash_check == -2) { @@ -1210,10 +1224,17 @@ namespace libtorrent m_policy.piece_finished(index, passed_hash_check == 0); - if (!was_seed && is_seed()) + if (!was_finished + && (is_seed() + || m_picker->num_filtered() + num_pieces() + == torrent_file().num_pieces())) { TORRENT_ASSERT(passed_hash_check == 0); - completed(); + // torrent finished + // i.e. all the pieces we're interested in have + // been downloaded. Release the files (they will open + // in read only mode if needed) + finished(); } } @@ -1425,6 +1446,21 @@ namespace libtorrent } } + void torrent::on_file_renamed(int ret, disk_io_job const& j) + { + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + + if (alerts().should_post(alert::warning)) + { + + if (ret == 0) + alerts().post_alert(file_renamed_alert(get_handle(), j.str + , "renamed file: " + j.str)); + else + alerts().post_alert(file_renamed_alert(get_handle(), "", j.str)); + } + } + void torrent::on_torrent_paused(int ret, disk_io_job const& j) { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -1452,7 +1488,7 @@ namespace libtorrent if (!m_have_pieces[index]) m_num_pieces++; - m_have_pieces[index] = true; + m_have_pieces.set_bit(index); TORRENT_ASSERT(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0) == m_num_pieces); @@ -1486,11 +1522,6 @@ namespace libtorrent #endif } #endif - if (is_seed()) - { - m_state = torrent_status::seeding; - m_picker.reset(); - } } std::string torrent::tracker_login() const @@ -1619,7 +1650,7 @@ namespace libtorrent for (int i = 0; i < int(files.size()); ++i) { size_type start = position; - size_type size = m_torrent_file->file_at(i).size; + size_type size = m_torrent_file->files().at(i).size; if (size == 0) continue; position += size; // mark all pieces of the file with this file's priority @@ -1750,7 +1781,7 @@ namespace libtorrent for (int i = 0; i < (int)bitmask.size(); ++i) { size_type start = position; - position += m_torrent_file->file_at(i).size; + position += m_torrent_file->files().at(i).size; // is the file selected for download? if (!bitmask[i]) { @@ -1872,9 +1903,8 @@ namespace libtorrent { if (m_picker.get()) { - const std::vector& pieces = p->get_bitfield(); - TORRENT_ASSERT(std::count(pieces.begin(), pieces.end(), true) - < int(pieces.size())); + bitfield const& pieces = p->get_bitfield(); + TORRENT_ASSERT(pieces.count() < int(pieces.size())); m_picker->dec_refcount(pieces); } } @@ -2956,6 +2986,12 @@ namespace libtorrent } m_state = torrent_status::finished; + set_queue_position(-1); + + // we have to call completed() before we start + // disconnecting peers, since there's an assert + // to make sure we're cleared the piece picker + if (is_seed()) completed(); // disconnect all seeds // TODO: should disconnect all peers that have the pieces we have @@ -2990,6 +3026,7 @@ namespace libtorrent INVARIANT_CHECK; m_state = torrent_status::downloading; + set_queue_position((std::numeric_limits::max)()); } // called when torrent is complete (all pieces downloaded) @@ -2997,6 +3034,8 @@ namespace libtorrent { INVARIANT_CHECK; + m_picker.reset(); + // make the next tracker request // be a completed-event m_event = tracker_request::completed; @@ -3095,11 +3134,7 @@ namespace libtorrent } #endif - if (is_seed()) - { - m_state = torrent_status::seeding; - m_picker.reset(); - } + if (is_seed()) finished(); if (!m_connections_initialized) { @@ -3149,6 +3184,20 @@ namespace libtorrent return m_save_path; } + bool torrent::rename_file(int index, std::string const& name) + { + INVARIANT_CHECK; + + TORRENT_ASSERT(index >= 0); + TORRENT_ASSERT(index < m_torrent_file->num_files()); + + if (!m_owning_storage.get()) return false; + + m_owning_storage->async_rename_file(index, name + , bind(&torrent::on_file_renamed, shared_from_this(), _1, _2)); + return true; + } + void torrent::move_storage(fs::path const& save_path) { INVARIANT_CHECK; @@ -3315,6 +3364,55 @@ namespace libtorrent } } + void torrent::set_queue_position(int p) + { + if (p == m_sequence_number) return; + + session_impl::torrent_map& torrents = m_ses.m_torrents; + if (p < 0) + { + for (session_impl::torrent_map::iterator i = torrents.begin() + , end(torrents.end()); i != end; ++i) + { + torrent* t = i->second.get(); + if (t == this) continue; + if (t->m_sequence_number >= m_sequence_number + && t->m_sequence_number != -1) + --t->m_sequence_number; + } + m_sequence_number = p; + } + else if (p < m_sequence_number) + { + for (session_impl::torrent_map::iterator i = torrents.begin() + , end(torrents.end()); i != end; ++i) + { + torrent* t = i->second.get(); + if (t == this) continue; + if (t->m_sequence_number >= p + && t->m_sequence_number != -1) + ++t->m_sequence_number; + } + m_sequence_number = p; + } + else if (p > m_sequence_number) + { + int max_seq = 0; + for (session_impl::torrent_map::iterator i = torrents.begin() + , end(torrents.end()); i != end; ++i) + { + torrent* t = i->second.get(); + if (t == this) continue; + int pos = t->m_sequence_number; + if (pos <= p + && pos > m_sequence_number + && pos != -1) + --t->m_sequence_number; + if (pos > max_seq) max_seq = pos; + } + m_sequence_number = (std::min)(max_seq + 1, p); + } + } void torrent::set_max_uploads(int limit) { @@ -3564,6 +3662,7 @@ namespace libtorrent m_paused = false; m_started = time_now(); + m_error.clear(); // tell the tracker that we're back m_event = tracker_request::started; @@ -3750,6 +3849,7 @@ namespace libtorrent { alerts().post_alert(file_error_alert(j.error_file, get_handle(), j.str)); } + m_error = j.str; pause(); } f(ret); @@ -3769,8 +3869,8 @@ namespace libtorrent for (int i = 0; i < m_torrent_file->num_files(); ++i) { - peer_request ret = m_torrent_file->map_file(i, 0, 0); - size_type size = m_torrent_file->file_at(i).size; + peer_request ret = m_torrent_file->files().map_file(i, 0, 0); + size_type size = m_torrent_file->files().at(i).size; // zero sized files are considered // 100% done all the time @@ -3792,7 +3892,7 @@ namespace libtorrent } TORRENT_ASSERT(size == 0); - fp[i] = static_cast(done) / m_torrent_file->file_at(i).size; + fp[i] = static_cast(done) / m_torrent_file->files().at(i).size; } } @@ -3809,6 +3909,8 @@ namespace libtorrent torrent_status st; + st.error = m_error; + if (m_last_scrape == min_time()) { st.last_scrape = -1; @@ -3902,20 +4004,22 @@ namespace libtorrent st.total_wanted = m_torrent_file->total_size(); TORRENT_ASSERT(st.total_wanted >= 0); + TORRENT_ASSERT(st.total_wanted >= m_torrent_file->piece_length() + * (m_torrent_file->num_pieces() - 1)); if (m_picker.get() && (m_picker->num_filtered() > 0 || m_picker->num_have_filtered() > 0)) { - int filtered_pieces = m_picker->num_filtered() + int num_filtered_pieces = m_picker->num_filtered() + m_picker->num_have_filtered(); int last_piece_index = m_torrent_file->num_pieces() - 1; if (m_picker->piece_priority(last_piece_index) == 0) { st.total_wanted -= m_torrent_file->piece_size(last_piece_index); - --filtered_pieces; + --num_filtered_pieces; } - st.total_wanted -= filtered_pieces * m_torrent_file->piece_length(); + st.total_wanted -= size_type(num_filtered_pieces) * m_torrent_file->piece_length(); } TORRENT_ASSERT(st.total_wanted >= st.total_wanted_done); diff --git a/libtorrent/src/torrent_handle.cpp b/libtorrent/src/torrent_handle.cpp index 79cac2e7d..257a05563 100755 --- a/libtorrent/src/torrent_handle.cpp +++ b/libtorrent/src/torrent_handle.cpp @@ -215,6 +215,12 @@ namespace libtorrent TORRENT_FORWARD(move_storage(save_path)); } + void torrent_handle::rename_file(int index, fs::path const& new_name) const + { + INVARIANT_CHECK; + TORRENT_FORWARD(rename_file(index, new_name.string())); + } + void torrent_handle::add_extension( boost::function(torrent*, void*)> const& ext , void* userdata) @@ -277,6 +283,36 @@ namespace libtorrent TORRENT_FORWARD(auto_managed(m)); } + int torrent_handle::queue_position() const + { + INVARIANT_CHECK; + TORRENT_FORWARD_RETURN(queue_position(), -1); + } + + void torrent_handle::queue_position_up() const + { + INVARIANT_CHECK; + TORRENT_FORWARD(set_queue_position(t->queue_position() - 1)); + } + + void torrent_handle::queue_position_down() const + { + INVARIANT_CHECK; + TORRENT_FORWARD(set_queue_position(t->queue_position() + 1)); + } + + void torrent_handle::queue_position_top() const + { + INVARIANT_CHECK; + TORRENT_FORWARD(set_queue_position(0)); + } + + void torrent_handle::queue_position_bottom() const + { + INVARIANT_CHECK; + TORRENT_FORWARD(set_queue_position((std::numeric_limits::max)())); + } + void torrent_handle::set_tracker_login(std::string const& name , std::string const& password) const { diff --git a/libtorrent/src/torrent_info.cpp b/libtorrent/src/torrent_info.cpp index 5a59cffc7..8afd2e408 100755 --- a/libtorrent/src/torrent_info.cpp +++ b/libtorrent/src/torrent_info.cpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2008, Arvid Norberg +Copyright (c) 2003-2008, Arvid Norberg All rights reserved. Redistribution and use in source and binary forms, with or without @@ -153,11 +153,7 @@ namespace // save the original encoding and replace the // commonly used path with the correctly // encoded string - if (!valid_encoding) - { - target.orig_path.reset(new fs::path(target.path)); - target.path = tmp_path; - } + if (!valid_encoding) target.path = tmp_path; } bool extract_single_file(lazy_entry const& dict, file_entry& target @@ -194,40 +190,26 @@ namespace return true; } - bool extract_files(lazy_entry const& list, std::vector& target + bool extract_files(lazy_entry const& list, file_storage& target , std::string const& root_dir) { - size_type offset = 0; if (list.type() != lazy_entry::list_t) return false; for (int i = 0, end(list.list_size()); i < end; ++i) { - target.push_back(file_entry()); - if (!extract_single_file(*list.list_at(i), target.back(), root_dir)) + file_entry e; + if (!extract_single_file(*list.list_at(i), e, root_dir)) return false; - target.back().offset = offset; - offset += target.back().size; + target.add_file(e); } return true; } -/* - void remove_dir(fs::path& p) - { - TORRENT_ASSERT(p.begin() != p.end()); - path tmp; - for (path::iterator i = boost::next(p.begin()); i != p.end(); ++i) - tmp /= *i; - p = tmp; - } -*/ } namespace libtorrent { - // standard constructor that parses a torrent file torrent_info::torrent_info(entry const& torrent_file) - : m_num_pieces(0) - , m_creation_date(pt::ptime(pt::not_a_date_time)) + : m_creation_date(pt::ptime(pt::not_a_date_time)) , m_multifile(false) , m_private(false) , m_info_section_size(0) @@ -249,8 +231,7 @@ namespace libtorrent } torrent_info::torrent_info(lazy_entry const& torrent_file) - : m_num_pieces(0) - , m_creation_date(pt::ptime(pt::not_a_date_time)) + : m_creation_date(pt::ptime(pt::not_a_date_time)) , m_multifile(false) , m_private(false) , m_info_section_size(0) @@ -266,8 +247,7 @@ namespace libtorrent } torrent_info::torrent_info(char const* buffer, int size) - : m_num_pieces(0) - , m_creation_date(pt::ptime(pt::not_a_date_time)) + : m_creation_date(pt::ptime(pt::not_a_date_time)) , m_multifile(false) , m_private(false) , m_info_section_size(0) @@ -289,36 +269,16 @@ namespace libtorrent // just the necessary to use it with piece manager // used for torrents with no metadata torrent_info::torrent_info(sha1_hash const& info_hash) - : m_piece_length(0) - , m_total_size(0) - , m_num_pieces(0) - , m_info_hash(info_hash) - , m_name() + : m_info_hash(info_hash) , m_creation_date(pt::second_clock::universal_time()) , m_multifile(false) , m_private(false) , m_info_section_size(0) , m_piece_hashes(0) - { - } - - torrent_info::torrent_info() - : m_piece_length(0) - , m_total_size(0) - , m_num_pieces(0) - , m_info_hash(0) - , m_name() - , m_creation_date(pt::second_clock::universal_time()) - , m_multifile(false) - , m_private(false) - , m_info_section_size(0) - , m_piece_hashes(0) - { - } + {} torrent_info::torrent_info(char const* filename) - : m_num_pieces(0) - , m_creation_date(pt::ptime(pt::not_a_date_time)) + : m_creation_date(pt::ptime(pt::not_a_date_time)) , m_multifile(false) , m_private(false) { @@ -349,11 +309,8 @@ namespace libtorrent m_urls.swap(ti.m_urls); m_url_seeds.swap(ti.m_url_seeds); m_files.swap(ti.m_files); - m_files.swap(ti.m_remapped_files); m_nodes.swap(ti.m_nodes); - swap(m_num_pieces, ti.m_num_pieces); swap(m_info_hash, ti.m_info_hash); - m_name.swap(ti.m_name); swap(m_creation_date, ti.m_creation_date); m_comment.swap(ti.m_comment); m_created_by.swap(ti.m_created_by); @@ -387,27 +344,27 @@ namespace libtorrent TORRENT_ASSERT(section.first[m_info_section_size-1] == 'e'); // extract piece length - m_piece_length = info.dict_find_int_value("piece length", -1); - if (m_piece_length <= 0) + int piece_length = info.dict_find_int_value("piece length", -1); + if (piece_length <= 0) { error = "invalid or missing 'piece length' entry in torrent file"; return false; } + m_files.set_piece_length(piece_length); // extract file name (or the directory name if it's a multifile libtorrent) - m_name = info.dict_find_string_value("name.utf-8"); - if (m_name.empty()) m_name = info.dict_find_string_value("name"); - - if (m_name.empty()) + std::string name = info.dict_find_string_value("name.utf-8"); + if (name.empty()) name = info.dict_find_string_value("name"); + if (name.empty()) { - error = "invalid name in torrent file"; + error = "missing name in torrent file"; return false; } - fs::path tmp = m_name; + fs::path tmp = name; if (tmp.is_complete()) { - m_name = tmp.leaf(); + name = tmp.leaf(); } else if (tmp.has_branch_path()) { @@ -418,9 +375,9 @@ namespace libtorrent if (*i == "." || *i == "..") continue; p /= *i; } - m_name = p.string(); + name = p.string(); } - if (m_name == ".." || m_name == ".") + if (name == ".." || name == ".") { error = "invalid 'name' of torrent (possible exploit attempt)"; return false; @@ -433,7 +390,7 @@ namespace libtorrent // if there's no list of files, there has to be a length // field. file_entry e; - e.path = m_name; + e.path = name; e.offset = 0; e.size = info.dict_find_int_value("length", -1); if (e.size < 0) @@ -441,29 +398,26 @@ namespace libtorrent error = "invalid length of torrent"; return false; } - m_files.push_back(e); + m_files.add_file(e); m_multifile = false; } else { - if (!extract_files(*i, m_files, m_name)) + if (!extract_files(*i, m_files, name)) { error = "failed to parse files from torrent file"; return false; } m_multifile = true; } - - // calculate total size of all pieces - m_total_size = 0; - for (std::vector::iterator i = m_files.begin(); i != m_files.end(); ++i) - m_total_size += i->size; + m_files.set_name(name); // extract sha-1 hashes for all pieces // we want this division to round upwards, that's why we have the // extra addition - m_num_pieces = static_cast((m_total_size + m_piece_length - 1) / m_piece_length); + m_files.set_num_pieces(int((m_files.total_size() + m_files.piece_length() - 1) + / m_files.piece_length())); lazy_entry const* pieces = info.dict_find("pieces"); if (pieces == 0 || pieces->type() != lazy_entry::string_t) @@ -472,7 +426,7 @@ namespace libtorrent return false; } - if (pieces->string_length() != m_num_pieces * 20) + if (pieces->string_length() != m_files.num_pieces() * 20) { error = "incorrect number of piece hashes in torrent file"; return false; @@ -630,122 +584,11 @@ namespace libtorrent os << "number of pieces: " << num_pieces() << "\n"; os << "piece length: " << piece_length() << "\n"; os << "files:\n"; - for (file_iterator i = begin_files(); i != end_files(); ++i) + for (file_storage::iterator i = m_files.begin(); i != m_files.end(); ++i) os << " " << std::setw(11) << i->size << " " << i->path.string() << "\n"; } // ------- end deprecation ------- - int torrent_info::piece_size(int index) const - { - TORRENT_ASSERT(index >= 0 && index < num_pieces()); - if (index == num_pieces()-1) - { - int size = int(total_size() - - (num_pieces() - 1) * piece_length()); - TORRENT_ASSERT(size > 0); - TORRENT_ASSERT(size <= piece_length()); - return int(size); - } - else - return piece_length(); - } - - bool torrent_info::remap_files(std::vector const& map) - { - size_type offset = 0; - m_remapped_files.resize(map.size()); - - for (int i = 0; i < int(map.size()); ++i) - { - file_entry& fe = m_remapped_files[i]; - fe.path = map[i].path; - fe.offset = offset; - fe.size = map[i].size; - fe.file_base = map[i].file_base; - fe.orig_path.reset(); - offset += fe.size; - } - if (offset != total_size()) - { - m_remapped_files.clear(); - return false; - } - -#ifndef NDEBUG - std::vector map2(m_remapped_files); - std::sort(map2.begin(), map2.end() - , bind(&file_entry::file_base, _1) < bind(&file_entry::file_base, _2)); - std::stable_sort(map2.begin(), map2.end() - , bind(&file_entry::path, _1) < bind(&file_entry::path, _2)); - fs::path last_path; - size_type last_end = 0; - for (std::vector::iterator i = map2.begin(), end(map2.end()); - i != end; ++i) - { - if (last_path == i->path) - { - assert(last_end <= i->file_base); - } - last_end = i->file_base + i->size; - last_path = i->path; - } -#endif - - return true; - } - - std::vector torrent_info::map_block(int piece, size_type offset - , int size_, bool storage) const - { - TORRENT_ASSERT(num_files() > 0); - std::vector ret; - - size_type start = piece * (size_type)m_piece_length + offset; - size_type size = size_; - TORRENT_ASSERT(start + size <= m_total_size); - - // find the file iterator and file offset - // TODO: make a vector that can map piece -> file index in O(1) - size_type file_offset = start; - std::vector::const_iterator file_iter; - - int counter = 0; - for (file_iter = begin_files(storage);; ++counter, ++file_iter) - { - TORRENT_ASSERT(file_iter != end_files(storage)); - if (file_offset < file_iter->size) - { - file_slice f; - f.file_index = counter; - f.offset = file_offset + file_iter->file_base; - f.size = (std::min)(file_iter->size - file_offset, (size_type)size); - size -= f.size; - file_offset += f.size; - ret.push_back(f); - } - - TORRENT_ASSERT(size >= 0); - if (size <= 0) break; - - file_offset -= file_iter->size; - } - return ret; - } - - peer_request torrent_info::map_file(int file_index, size_type file_offset - , int size, bool storage) const - { - TORRENT_ASSERT(file_index < num_files(storage)); - TORRENT_ASSERT(file_index >= 0); - size_type offset = file_offset + file_at(file_index, storage).offset; - - peer_request ret; - ret.piece = int(offset / piece_length()); - ret.start = int(offset - ret.piece * piece_length()); - ret.length = size; - return ret; - } - } diff --git a/libtorrent/src/web_peer_connection.cpp b/libtorrent/src/web_peer_connection.cpp index 6d7db636e..a2dc059e2 100755 --- a/libtorrent/src/web_peer_connection.cpp +++ b/libtorrent/src/web_peer_connection.cpp @@ -156,8 +156,8 @@ namespace libtorrent TORRENT_ASSERT(t); // this is always a seed - incoming_bitfield(std::vector( - t->torrent_file().num_pieces(), true)); + incoming_have_all(); + // it is always possible to request pieces incoming_unchoke(); @@ -229,7 +229,7 @@ namespace libtorrent request += "\r\nProxy-Connection: keep-alive"; } request += "\r\nRange: bytes="; - request += boost::lexical_cast(r.piece + request += boost::lexical_cast(size_type(r.piece) * info.piece_length() + r.start); request += "-"; request += boost::lexical_cast(r.piece @@ -242,7 +242,7 @@ namespace libtorrent } else { - std::vector files = info.map_block(r.piece, r.start + std::vector files = info.files().map_block(r.piece, r.start , r.length); for (std::vector::iterator i = files.begin(); @@ -254,13 +254,13 @@ namespace libtorrent if (using_proxy) { request += m_url; - std::string path = info.file_at(f.file_index).path.string(); + std::string path = info.files().at(f.file_index).path.string(); request += escape_path(path.c_str(), path.length()); } else { std::string path = m_path; - path += info.file_at(f.file_index).path.string(); + path += info.files().at(f.file_index).path.string(); request += escape_path(path.c_str(), path.length()); } request += " HTTP/1.1\r\n"; @@ -426,7 +426,7 @@ namespace libtorrent int file_index = m_file_requests.front(); torrent_info const& info = t->torrent_file(); - std::string path = info.file_at(file_index).path.string(); + std::string path = info.files().at(file_index).path.string(); path = escape_path(path.c_str(), path.length()); size_t i = location.rfind(path); if (i == std::string::npos) @@ -511,7 +511,7 @@ namespace libtorrent } int file_index = m_file_requests.front(); - peer_request in_range = info.map_file(file_index, range_start + peer_request in_range = info.files().map_file(file_index, range_start , int(range_end - range_start)); peer_request front_request = m_requests.front();