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
|
||||
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
|
||||
|
@@ -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";
|
||||
|
@@ -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();
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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<int>::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<peer>::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<peer>::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,7 +525,7 @@ 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);
|
||||
@@ -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<peer>::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<peer>::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<peer>::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
|
||||
|
||||
|
@@ -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,18 +745,7 @@ namespace libtorrent { namespace detail
|
||||
}
|
||||
|
||||
m_tracker_manager.tick();
|
||||
}
|
||||
|
||||
while (!m_tracker_manager.send_finished())
|
||||
{
|
||||
m_tracker_manager.tick();
|
||||
boost::xtime t;
|
||||
boost::xtime_get(&t, boost::TIME_UTC);
|
||||
t.nsec += 100000000;
|
||||
boost::thread::sleep(t);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
}
|
||||
catch (std::bad_cast& e)
|
||||
{
|
||||
@@ -775,7 +762,17 @@ namespace libtorrent { namespace detail
|
||||
std::cerr << "error!\n";
|
||||
assert(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while (!m_tracker_manager.send_finished())
|
||||
{
|
||||
m_tracker_manager.tick();
|
||||
boost::xtime t;
|
||||
boost::xtime_get(&t, boost::TIME_UTC);
|
||||
t.nsec += 100000000;
|
||||
boost::thread::sleep(t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
@@ -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<file> 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<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));
|
||||
|
||||
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<file> 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());
|
||||
}
|
||||
|
@@ -62,14 +62,16 @@ 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)
|
||||
{
|
||||
if (i->string() != "..")
|
||||
target.path /= i->string();
|
||||
}
|
||||
if (target.path.is_complete()) throw std::runtime_error("torrent contains "
|
||||
@@ -77,12 +79,13 @@ namespace
|
||||
+ 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)
|
||||
{
|
||||
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,6 +187,11 @@ 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");
|
||||
@@ -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<sha1_hash>::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;
|
||||
|
||||
entry info(entry::dictionary_t);
|
||||
|
||||
// you have to add files to the torrent first
|
||||
assert(!m_files.empty());
|
||||
|
||||
if (m_files.size() == 1)
|
||||
{
|
||||
entry info(entry::dictionary_t);
|
||||
|
||||
info["name"] = m_name;
|
||||
if (!m_multifile)
|
||||
{
|
||||
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<file_entry>::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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user