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:
Arvid Norberg
2005-05-11 23:03:12 +00:00
parent d38e66a223
commit 7814b03370
9 changed files with 119 additions and 95 deletions

View File

@@ -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

View File

@@ -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";

View File

@@ -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();

View File

@@ -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;
};
}

View File

@@ -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

View File

@@ -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
@@ -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

View File

@@ -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));
}

View File

@@ -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());
}

View File

@@ -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);
}