diff --git a/docs/manual.rst b/docs/manual.rst index cbaff9cf2..cf98b2a48 100755 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -655,6 +655,9 @@ in the torrent, you can use ``begin_files()``, ``end_files()``, ``rbegin_files()`` and ``rend_files()``. These will give you standard vector iterators with the type ``file_entry``. +The ``path`` is the full (relative) path of each file. i.e. if it is a multi-file +torrent, all the files starts with a directory with the same name as ``torrent_info::name()``. + :: struct file_entry diff --git a/examples/dump_torrent.cpp b/examples/dump_torrent.cpp index 3e8718136..2648d7fa0 100755 --- a/examples/dump_torrent.cpp +++ b/examples/dump_torrent.cpp @@ -81,8 +81,7 @@ int main(int argc, char* argv[]) std::cout << "info hash: " << t.info_hash() << "\n"; std::cout << "files:\n"; for (torrent_info::file_iterator i = t.begin_files(); - i != t.end_files(); - ++i) + i != t.end_files(); ++i) { std::cout << " " << std::setw(11) << i->size << " " << i->path.string() << "\n"; diff --git a/examples/make_torrent.cpp b/examples/make_torrent.cpp index 4973e7ca1..566c49934 100755 --- a/examples/make_torrent.cpp +++ b/examples/make_torrent.cpp @@ -62,6 +62,7 @@ void add_files( } else { + std::cerr << "adding \"" << l.string() << "\"\n"; file fi(f, file::in); fi.seek(0, file::end); libtorrent::size_type size = fi.tell(); diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index 6b6f2454f..92fe1d089 100755 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -181,6 +181,13 @@ namespace libtorrent // an optional string naming the software used // to create the torrent file std::string m_created_by; + + // this is used when creating a torrent. If there's + // only one file there are cases where it's impossible + // to know if it should be written as a multifile torrent + // or not. e.g. test/test there's one file and one directory + // and they have the same name. + bool m_multifile; }; } diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index 231ea9d24..e58fd5ddd 100755 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -386,6 +386,7 @@ namespace libtorrent assert(peer_count < 2048); m_piece_map[i].peer_count++; + assert(m_piece_map[i].peer_count != 0); // if we have the piece, we don't have to move // any entries in the piece_info vector diff --git a/src/policy.cpp b/src/policy.cpp index d3ed0a83d..e0c3aab34 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -47,6 +47,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/peer_connection.hpp" #include "libtorrent/alert_types.hpp" +#include "libtorrent/invariant_check.hpp" #if defined(_MSC_VER) && _MSC_VER < 1300 # define for if (false) {} else for @@ -339,6 +340,8 @@ namespace libtorrent // choked. policy::peer* policy::find_choke_candidate() { + INVARIANT_CHECK; + peer* worst_peer = 0; size_type min_weight = std::numeric_limits::min(); @@ -381,6 +384,8 @@ namespace libtorrent policy::peer* policy::find_unchoke_candidate() { + INVARIANT_CHECK; + // if all of our peers are unchoked, there's // no left to unchoke if (m_num_unchoked == m_torrent->num_peers()) @@ -463,8 +468,7 @@ namespace libtorrent policy::peer* candidate =0; for (std::vector::iterator i = m_peers.begin(); - i != m_peers.end(); - ++i) + i != m_peers.end(); ++i) { if(i->connection) continue; if(i->banned) continue; @@ -488,6 +492,8 @@ namespace libtorrent policy::peer* policy::find_seed_choke_candidate() { + INVARIANT_CHECK; + // first choice candidate. // it is a candidate we owe nothing to and which has been unchoked // the longest. @@ -506,8 +512,7 @@ namespace libtorrent size_type lowest_share_diff = 0; // not valid when secondCandidate==0 for (std::vector::iterator i = m_peers.begin(); - i != m_peers.end(); - ++i) + i != m_peers.end(); ++i) { peer_connection* c = i->connection; // ignore peers that are choked or @@ -520,13 +525,13 @@ namespace libtorrent // select as second candidate the one that we owe the least // to - if(!second_candidate || share_diff <= lowest_share_diff) + if (!second_candidate || share_diff <= lowest_share_diff) { lowest_share_diff = share_diff; second_candidate = &(*i); } - // select as first candidate the one that we don't owe anything to + // select as first candidate the one that we don't owe anything to // and has been waiting for an unchoke the longest if (share_diff > 0) continue; if (!candidate || last_unchoke > i->last_optimistically_unchoked) @@ -543,13 +548,14 @@ namespace libtorrent policy::peer* policy::find_seed_unchoke_candidate() { + INVARIANT_CHECK; + peer* candidate = 0; boost::posix_time::ptime last_unchoke = second_clock::universal_time(); for (std::vector::iterator i = m_peers.begin(); - i != m_peers.end(); - ++i) + i != m_peers.end(); ++i) { peer_connection* c = i->connection; if (c == 0) continue; @@ -568,6 +574,7 @@ namespace libtorrent peer* p = find_seed_unchoke_candidate(); if (p != 0) { + assert(p->connection->is_choked()); p->connection->send_unchoke(); p->last_optimistically_unchoked = second_clock::universal_time(); @@ -578,6 +585,8 @@ namespace libtorrent void policy::pulse() { + INVARIANT_CHECK; + if (m_torrent->is_paused()) return; using namespace boost::posix_time; @@ -697,6 +706,7 @@ namespace libtorrent peer* p = find_seed_choke_candidate(); assert(p != 0); + assert(!p->connection->is_choked()); p->connection->send_choke(); --m_num_unchoked; } @@ -749,6 +759,7 @@ namespace libtorrent peer* p = find_choke_candidate(); if (!p) break; assert(p); + assert(!p->connection->is_choked()); p->connection->send_choke(); --m_num_unchoked; } @@ -759,6 +770,7 @@ namespace libtorrent peer* p = find_choke_candidate(); if (p) { + assert(!p->connection->is_choked()); p->connection->send_choke(); --m_num_unchoked; unchoke_one_peer(); @@ -770,9 +782,6 @@ namespace libtorrent while (m_num_unchoked < m_torrent->m_uploads_quota.given && unchoke_one_peer()); } -#ifndef NDEBUG - check_invariant(); -#endif } void policy::ban_peer(const peer_connection& c) @@ -1016,6 +1025,7 @@ namespace libtorrent assert(p->connection); assert(!p->connection->is_disconnecting()); + assert(p->connection->is_choked()); p->connection->send_unchoke(); p->last_optimistically_unchoked = second_clock::universal_time(); ++m_num_unchoked; @@ -1068,6 +1078,10 @@ namespace libtorrent // this is called whenever a peer connection is closed void policy::connection_closed(const peer_connection& c) { + INVARIANT_CHECK; + + bool unchoked = false; + std::vector::iterator i = std::find_if( m_peers.begin() , m_peers.end() @@ -1080,11 +1094,7 @@ namespace libtorrent i->connected = second_clock::universal_time(); if (!i->connection->is_choked() && !m_torrent->is_aborted()) { - // if the peer that is diconnecting is unchoked - // then unchoke another peer in order to maintain - // the total number of unchoked peers - --m_num_unchoked; - unchoke_one_peer(); + unchoked = true; } if (c.failed()) @@ -1105,6 +1115,15 @@ namespace libtorrent i->prev_amount_download += c.statistics().total_payload_download(); i->prev_amount_upload += c.statistics().total_payload_upload(); i->connection = 0; + + if (unchoked) + { + // if the peer that is diconnecting is unchoked + // then unchoke another peer in order to maintain + // the total number of unchoked peers + --m_num_unchoked; + unchoke_one_peer(); + } } void policy::peer_is_interesting(peer_connection& c) @@ -1129,13 +1148,13 @@ namespace libtorrent assert(m_torrent->m_uploads_quota.given >= 2); int actual_unchoked = 0; for (std::vector::const_iterator i = m_peers.begin(); - i != m_peers.end(); - ++i) + i != m_peers.end(); ++i) { if (!i->connection) continue; if (!i->connection->is_choked()) actual_unchoked++; } - assert(actual_unchoked <= m_torrent->m_uploads_quota.given); +// assert(actual_unchoked <= m_torrent->m_uploads_quota.given); + assert(actual_unchoked == m_num_unchoked); } #endif diff --git a/src/session.cpp b/src/session.cpp index b834f5d14..a382b55aa 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -343,10 +343,6 @@ namespace libtorrent { namespace detail void session_impl::operator()() { eh_initializer(); -#ifndef NDEBUG - try - { -#endif if (m_listen_port_range.first != 0 && m_listen_port_range.second != 0) { @@ -364,6 +360,8 @@ namespace libtorrent { namespace detail #endif for(;;) { + try + { #ifndef NDEBUG { @@ -747,6 +745,23 @@ namespace libtorrent { namespace detail } m_tracker_manager.tick(); + + } + catch (std::bad_cast& e) + { + std::cerr << e.what() << "\n"; + assert(false); + } + catch (std::exception& e) + { + std::cerr << e.what() << "\n"; + assert(false); + } + catch (...) + { + std::cerr << "error!\n"; + assert(false); + } } while (!m_tracker_manager.send_finished()) @@ -758,24 +773,6 @@ namespace libtorrent { namespace detail boost::thread::sleep(t); } -#ifndef NDEBUG - } - catch (std::bad_cast& e) - { - std::cerr << e.what() << "\n"; - assert(false); - } - catch (std::exception& e) - { - std::cerr << e.what() << "\n"; - assert(false); - } - catch (...) - { - std::cerr << "error!\n"; - assert(false); - } -#endif } @@ -915,6 +912,7 @@ namespace libtorrent = m_checker_impl.m_torrents.begin() , end(m_checker_impl.m_torrents.end()); i != end; ++i) { + if (i->abort) continue; ret.push_back(torrent_handle(&m_impl, &m_checker_impl , i->info_hash)); } diff --git a/src/storage.cpp b/src/storage.cpp index 4c195ae81..9d30674e4 100755 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -98,17 +98,6 @@ namespace log.flush(); } - path get_filename( - libtorrent::torrent_info const& t - , path const& p) - { - assert(t.num_files() > 0); - if (t.num_files() == 1) - return p; - else - return t.name() / p; - } - struct file_entry { file_entry(boost::shared_ptr const& f_) @@ -183,7 +172,7 @@ namespace libtorrent std::time_t time = 0; try { - path f = p / get_filename(t, i->path); + path f = p / i->path; size = file_size(f); time = last_write_time(f); } @@ -211,7 +200,7 @@ namespace libtorrent std::time_t time = 0; try { - path f = p / get_filename(t, i->path); + path f = p / i->path; size = file_size(f); time = last_write_time(f); } @@ -399,7 +388,7 @@ namespace libtorrent } boost::shared_ptr in(m_pimpl->files.open_file( - m_pimpl->save_path / get_filename(m_pimpl->info, file_iter->path) + m_pimpl->save_path / file_iter->path , file::in)); assert(file_offset < file_iter->size); @@ -449,7 +438,7 @@ namespace libtorrent if (left_to_read > 0) { ++file_iter; - path path = m_pimpl->save_path / get_filename(m_pimpl->info, file_iter->path); + path path = m_pimpl->save_path / file_iter->path; file_offset = 0; in = m_pimpl->files.open_file(path, file::in); @@ -491,7 +480,7 @@ namespace libtorrent assert(file_iter != m_pimpl->info.end_files()); } - path p(m_pimpl->save_path / get_filename(m_pimpl->info, file_iter->path)); + path p(m_pimpl->save_path / file_iter->path); boost::shared_ptr out = m_pimpl->files.open_file(p, file::out | file::in); assert(file_offset < file_iter->size); @@ -547,7 +536,7 @@ namespace libtorrent ++file_iter; assert(file_iter != m_pimpl->info.end_files()); - path p = m_pimpl->save_path / get_filename(m_pimpl->info, file_iter->path); + path p = m_pimpl->save_path / file_iter->path; file_offset = 0; out = m_pimpl->files.open_file(p, file::out | file::in); out->seek(0); @@ -1080,7 +1069,7 @@ namespace libtorrent for (torrent_info::file_iterator file_iter = m_info.begin_files(), end_iter = m_info.end_files(); file_iter != end_iter; ++file_iter) { - path dir = m_save_path / get_filename(m_info, file_iter->path); + path dir = m_save_path / file_iter->path; if (!exists(dir.branch_path())) create_directories(dir.branch_path()); } diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 241899f84..72ea6d19d 100755 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -62,27 +62,30 @@ using namespace boost::filesystem; namespace { - void extract_single_file(const entry& dict, file_entry& target) + void extract_single_file(const entry& dict, file_entry& target + , std::string const& root_dir) { target.size = dict["length"].integer(); + target.path = root_dir; const entry::list_type& list = dict["path"].list(); for (entry::list_type::const_iterator i = list.begin(); - i != list.end(); - ++i) + i != list.end(); ++i) { - target.path /= i->string(); + if (i->string() != "..") + target.path /= i->string(); } if (target.path.is_complete()) throw std::runtime_error("torrent contains " "a file with an absolute path: '" + target.path.native_file_string() + "'"); } - void extract_files(const entry::list_type& list, std::vector& target) + void extract_files(const entry::list_type& list, std::vector& target + , std::string const& root_dir) { for (entry::list_type::const_iterator i = list.begin(); i != list.end(); ++i) { target.push_back(file_entry()); - extract_single_file(*i, target.back()); + extract_single_file(*i, target.back(), root_dir); } } @@ -105,6 +108,7 @@ namespace libtorrent // standard constructor that parses a torrent file torrent_info::torrent_info(const entry& torrent_file) : m_creation_date(date(not_a_date_time)) + , m_multifile(false) { try { @@ -125,6 +129,7 @@ namespace libtorrent , m_info_hash(info_hash) , m_name() , m_creation_date(second_clock::universal_time()) + , m_multifile(false) { } @@ -134,6 +139,7 @@ namespace libtorrent , m_info_hash(0) , m_name() , m_creation_date(second_clock::universal_time()) + , m_multifile(false) { } @@ -181,7 +187,12 @@ namespace libtorrent // extract file name (or the directory name if it's a multifile libtorrent) m_name = info["name"].string(); - + path tmp = m_name; + if (tmp.is_complete()) throw std::runtime_error("torrent contains " + "a file with an absolute path: '" + m_name + "'"); + if (tmp.has_branch_path()) throw std::runtime_error( + "torrent contains name with directories: '" + m_name + "'"); + // extract file list entry const* i = info.find_key("files"); if (i == 0) @@ -190,14 +201,13 @@ namespace libtorrent // field. file_entry e; e.path = m_name; - if (e.path.is_complete()) throw std::runtime_error("torrent contains " - "a file with an absolute path: '" + e.path.native_file_string() + "'"); e.size = info["length"].integer(); m_files.push_back(e); } else { - extract_files(i->list(), m_files); + extract_files(i->list(), m_files, m_name); + m_multifile = true; } // calculate total size of all pieces @@ -321,22 +331,24 @@ namespace libtorrent { assert(file.begin() != file.end()); - if (m_files.empty()) + 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. + assert(m_files.empty()); + assert(!m_multifile); m_name = file.string(); } else { #ifndef NDEBUG - if (m_files.size() == 1) - assert(*m_files.front().path.begin() == *file.begin()); - else + if (!m_files.empty()) assert(m_name == *file.begin()); #endif + m_multifile = true; m_name = *file.begin(); - if (m_files.size() == 1) - remove_dir(m_files.front().path); - remove_dir(file); } file_entry e; @@ -352,8 +364,7 @@ namespace libtorrent m_piece_hash.resize(num_pieces); for (std::vector::iterator i = m_piece_hash.begin() + old_num_pieces; - i != m_piece_hash.end(); - ++i) + i != m_piece_hash.end(); ++i) { i->clear(); } @@ -374,28 +385,23 @@ namespace libtorrent { namespace fs = boost::filesystem; + // you have to add files to the torrent first + assert(!m_files.empty()); + entry info(entry::dictionary_t); - assert(!m_files.empty()); - - if (m_files.size() == 1) + info["name"] = m_name; + if (!m_multifile) { - info["name"] = m_name; info["length"] = m_files.front().size; } else - { - info["name"] = m_name; - } - - if (m_files.size() > 1) { entry& files = info["files"]; files = entry(entry::list_t); for (std::vector::const_iterator i = m_files.begin(); - i != m_files.end(); - ++i) + i != m_files.end(); ++i) { files.list().push_back(entry(entry::dictionary_t)); entry& file_e = files.list().back(); @@ -403,11 +409,12 @@ namespace libtorrent entry& path_e = file_e["path"]; path_e = entry(entry::list_t); - fs::path file_path(i->path); + fs::path const& file_path(i->path); + assert(file_path.has_branch_path()); + assert(*file_path.begin() == m_name); - for (fs::path::iterator j = file_path.begin(); - j != file_path.end(); - ++j) + for (fs::path::iterator j = boost::next(file_path.begin()); + j != file_path.end(); ++j) { path_e.list().push_back(*j); }