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