2003-10-23 01:00:57 +02:00
|
|
|
/*
|
|
|
|
|
2008-05-28 10:44:40 +02:00
|
|
|
Copyright (c) 2003-2008, Arvid Norberg
|
2003-10-23 01:00:57 +02:00
|
|
|
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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2007-03-17 18:15:16 +01:00
|
|
|
#include "libtorrent/pch.hpp"
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
#include <ctime>
|
2009-04-04 11:52:25 +02:00
|
|
|
|
|
|
|
#if !defined TORRENT_NO_DEPRECATE && TORRENT_USE_IOSTREAM
|
2003-10-23 01:00:57 +02:00
|
|
|
#include <iostream>
|
|
|
|
#include <iomanip>
|
2009-04-04 11:52:25 +02:00
|
|
|
#endif
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
#include <iterator>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <set>
|
|
|
|
|
2004-01-25 19:18:36 +01:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(push, 1)
|
|
|
|
#endif
|
|
|
|
|
2004-11-01 00:16:08 +01:00
|
|
|
#include <boost/bind.hpp>
|
2009-11-26 22:05:57 +01:00
|
|
|
#include <boost/assert.hpp>
|
2009-11-23 09:38:50 +01:00
|
|
|
#include <boost/date_time/posix_time/ptime.hpp>
|
|
|
|
#include <boost/date_time/posix_time/posix_time_duration.hpp>
|
|
|
|
#include <boost/date_time/time_clock.hpp>
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2004-01-25 19:18:36 +01:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma warning(pop)
|
|
|
|
#endif
|
|
|
|
|
2009-09-06 02:57:01 +02:00
|
|
|
#include "libtorrent/config.hpp"
|
2003-10-23 01:00:57 +02:00
|
|
|
#include "libtorrent/torrent_info.hpp"
|
2009-11-26 19:31:27 +01:00
|
|
|
#include "libtorrent/escape_string.hpp" // is_space
|
2003-10-23 01:00:57 +02:00
|
|
|
#include "libtorrent/bencode.hpp"
|
|
|
|
#include "libtorrent/hasher.hpp"
|
|
|
|
#include "libtorrent/entry.hpp"
|
2008-07-01 01:14:31 +02:00
|
|
|
#include "libtorrent/file.hpp"
|
2008-12-01 08:52:59 +01:00
|
|
|
#include "libtorrent/utf8.hpp"
|
2009-11-25 07:55:34 +01:00
|
|
|
#include "libtorrent/time.hpp"
|
2003-10-23 01:00:57 +02:00
|
|
|
|
2009-08-20 05:19:12 +02:00
|
|
|
#if TORRENT_USE_I2P
|
|
|
|
#include "libtorrent/parse_url.hpp"
|
|
|
|
#endif
|
|
|
|
|
2007-04-05 00:27:36 +02:00
|
|
|
namespace gr = boost::gregorian;
|
|
|
|
|
2009-03-13 07:09:39 +01:00
|
|
|
namespace libtorrent
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2007-06-10 22:46:09 +02:00
|
|
|
|
2006-10-13 01:51:10 +02:00
|
|
|
void convert_to_utf8(std::string& str, unsigned char chr)
|
|
|
|
{
|
|
|
|
str += 0xc0 | ((chr & 0xff) >> 6);
|
|
|
|
str += 0x80 | (chr & 0x3f);
|
|
|
|
}
|
|
|
|
|
2009-09-09 19:56:25 +02:00
|
|
|
bool valid_path_character(char c)
|
|
|
|
{
|
|
|
|
#ifdef TORRENT_WINDOWS
|
2009-09-25 17:08:28 +02:00
|
|
|
static const char invalid_chars[] = "?<>\"|\b*:";
|
2009-09-09 19:56:25 +02:00
|
|
|
#else
|
|
|
|
static const char invalid_chars[] = "";
|
|
|
|
#endif
|
|
|
|
if (c >= 0 && c < 32) return false;
|
|
|
|
return std::strchr(invalid_chars, c) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// fixes invalid UTF-8 sequences and
|
|
|
|
// replaces characters that are invalid
|
|
|
|
// in paths
|
2009-12-02 18:46:25 +01:00
|
|
|
TORRENT_EXPORT bool verify_encoding(std::string& target, bool fix_paths = false)
|
2006-10-13 01:51:10 +02:00
|
|
|
{
|
|
|
|
std::string tmp_path;
|
|
|
|
bool valid_encoding = true;
|
2008-12-31 11:18:19 +01:00
|
|
|
for (std::string::iterator i = target.begin()
|
|
|
|
, end(target.end()); i != end; ++i)
|
2006-10-13 01:51:10 +02:00
|
|
|
{
|
|
|
|
// valid ascii-character
|
|
|
|
if ((*i & 0x80) == 0)
|
|
|
|
{
|
2009-09-09 19:56:25 +02:00
|
|
|
// replace invalid characters with '.'
|
2009-11-13 03:50:07 +01:00
|
|
|
if (!fix_paths || valid_path_character(*i))
|
2009-09-09 19:56:25 +02:00
|
|
|
{
|
|
|
|
tmp_path += *i;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-09-25 17:08:28 +02:00
|
|
|
tmp_path += '_';
|
2009-09-09 19:56:25 +02:00
|
|
|
valid_encoding = false;
|
|
|
|
}
|
2006-10-13 01:51:10 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-08-30 09:38:52 +02:00
|
|
|
if (end - i < 2)
|
2006-10-13 01:51:10 +02:00
|
|
|
{
|
|
|
|
convert_to_utf8(tmp_path, *i);
|
|
|
|
valid_encoding = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// valid 2-byte utf-8 character
|
|
|
|
if ((i[0] & 0xe0) == 0xc0
|
|
|
|
&& (i[1] & 0xc0) == 0x80)
|
|
|
|
{
|
|
|
|
tmp_path += i[0];
|
|
|
|
tmp_path += i[1];
|
|
|
|
i += 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-08-30 09:38:52 +02:00
|
|
|
if (end - i < 3)
|
2006-10-13 01:51:10 +02:00
|
|
|
{
|
|
|
|
convert_to_utf8(tmp_path, *i);
|
|
|
|
valid_encoding = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// valid 3-byte utf-8 character
|
|
|
|
if ((i[0] & 0xf0) == 0xe0
|
|
|
|
&& (i[1] & 0xc0) == 0x80
|
|
|
|
&& (i[2] & 0xc0) == 0x80)
|
|
|
|
{
|
|
|
|
tmp_path += i[0];
|
|
|
|
tmp_path += i[1];
|
|
|
|
tmp_path += i[2];
|
|
|
|
i += 2;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-08-30 09:38:52 +02:00
|
|
|
if (end - i < 4)
|
2006-10-13 01:51:10 +02:00
|
|
|
{
|
|
|
|
convert_to_utf8(tmp_path, *i);
|
|
|
|
valid_encoding = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// valid 4-byte utf-8 character
|
|
|
|
if ((i[0] & 0xf0) == 0xe0
|
|
|
|
&& (i[1] & 0xc0) == 0x80
|
|
|
|
&& (i[2] & 0xc0) == 0x80
|
|
|
|
&& (i[3] & 0xc0) == 0x80)
|
|
|
|
{
|
|
|
|
tmp_path += i[0];
|
|
|
|
tmp_path += i[1];
|
|
|
|
tmp_path += i[2];
|
|
|
|
tmp_path += i[3];
|
|
|
|
i += 3;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
convert_to_utf8(tmp_path, *i);
|
|
|
|
valid_encoding = false;
|
|
|
|
}
|
|
|
|
// the encoding was not valid utf-8
|
|
|
|
// save the original encoding and replace the
|
|
|
|
// commonly used path with the correctly
|
|
|
|
// encoded string
|
2008-12-31 11:18:19 +01:00
|
|
|
if (!valid_encoding) target = tmp_path;
|
|
|
|
return valid_encoding;
|
|
|
|
}
|
|
|
|
|
|
|
|
void verify_encoding(file_entry& target)
|
|
|
|
{
|
2009-10-26 02:29:39 +01:00
|
|
|
std::string p = target.path;
|
2009-11-13 03:50:07 +01:00
|
|
|
if (!verify_encoding(p, true)) target.path = p;
|
2006-10-13 01:51:10 +02:00
|
|
|
}
|
|
|
|
|
2009-10-26 02:29:39 +01:00
|
|
|
// TODO: should this take a char const*?
|
2009-05-28 09:25:09 +02:00
|
|
|
bool valid_path_element(std::string const& element)
|
|
|
|
{
|
|
|
|
if (element.empty()
|
|
|
|
|| element == "." || element == ".."
|
|
|
|
|| element[0] == '/' || element[0] == '\\'
|
|
|
|
|| element[element.size()-1] == ':')
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2008-11-17 09:01:35 +01:00
|
|
|
void trim_path_element(std::string& path_element)
|
|
|
|
{
|
2009-09-10 05:54:10 +02:00
|
|
|
const int max_path_len = TORRENT_MAX_PATH;
|
2010-02-14 02:39:55 +01:00
|
|
|
if (int(path_element.size()) > max_path_len)
|
2008-11-17 09:01:35 +01:00
|
|
|
{
|
|
|
|
// truncate filenames that are too long. But keep extensions!
|
2009-10-26 02:29:39 +01:00
|
|
|
std::string ext = extension(path_element);
|
2008-11-17 09:01:35 +01:00
|
|
|
if (ext.size() > 15)
|
|
|
|
{
|
2009-01-27 09:24:48 +01:00
|
|
|
path_element.resize(max_path_len);
|
2008-11-17 09:01:35 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-01-27 09:24:48 +01:00
|
|
|
path_element.resize(max_path_len - ext.size());
|
2008-11-17 09:01:35 +01:00
|
|
|
path_element += ext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-02 18:46:25 +01:00
|
|
|
TORRENT_EXPORT std::string sanitize_path(std::string const& p)
|
2009-05-28 09:25:09 +02:00
|
|
|
{
|
2009-10-26 02:29:39 +01:00
|
|
|
std::string new_path;
|
|
|
|
std::string split = split_path(p);
|
|
|
|
for (char const* e = split.c_str(); e != 0; e = next_path_element(e))
|
2009-05-28 09:25:09 +02:00
|
|
|
{
|
2009-10-26 02:29:39 +01:00
|
|
|
std::string pe = e;
|
|
|
|
if (!valid_path_element(pe)) continue;
|
2009-05-28 09:25:09 +02:00
|
|
|
trim_path_element(pe);
|
2009-10-26 02:29:39 +01:00
|
|
|
new_path = combine_path(new_path, pe);
|
2009-05-28 09:25:09 +02:00
|
|
|
}
|
|
|
|
return new_path;
|
|
|
|
}
|
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
bool extract_single_file(lazy_entry const& dict, file_entry& target
|
2005-05-12 01:03:12 +02:00
|
|
|
, std::string const& root_dir)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2009-10-26 21:30:45 +01:00
|
|
|
if (dict.type() != lazy_entry::dict_t) return false;
|
2008-05-14 07:29:42 +02:00
|
|
|
lazy_entry const* length = dict.dict_find("length");
|
|
|
|
if (length == 0 || length->type() != lazy_entry::int_t)
|
2007-12-28 21:11:10 +01:00
|
|
|
return false;
|
2008-05-14 07:29:42 +02:00
|
|
|
target.size = length->int_value();
|
2005-05-12 01:03:12 +02:00
|
|
|
target.path = root_dir;
|
2007-11-25 11:47:05 +01:00
|
|
|
target.file_base = 0;
|
2005-08-17 03:35:37 +02:00
|
|
|
|
2009-06-23 04:50:41 +02:00
|
|
|
size_type ts = dict.dict_find_int_value("mtime", -1);
|
|
|
|
if (ts >= 0) target.mtime = std::time_t(ts);
|
|
|
|
|
2005-08-17 03:35:37 +02:00
|
|
|
// prefer the name.utf-8
|
|
|
|
// because if it exists, it is more
|
|
|
|
// likely to be correctly encoded
|
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
lazy_entry const* p = dict.dict_find("path.utf-8");
|
|
|
|
if (p == 0 || p->type() != lazy_entry::list_t)
|
|
|
|
p = dict.dict_find("path");
|
|
|
|
if (p == 0 || p->type() != lazy_entry::list_t)
|
|
|
|
return false;
|
2005-08-17 03:35:37 +02:00
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
for (int i = 0, end(p->list_size()); i < end; ++i)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-05-14 07:29:42 +02:00
|
|
|
if (p->list_at(i)->type() != lazy_entry::string_t)
|
2007-12-28 21:11:10 +01:00
|
|
|
return false;
|
2008-05-14 07:29:42 +02:00
|
|
|
std::string path_element = p->list_at(i)->string_value();
|
2008-11-17 09:01:35 +01:00
|
|
|
trim_path_element(path_element);
|
2009-10-26 02:29:39 +01:00
|
|
|
target.path = combine_path(target.path, path_element);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2009-05-28 09:25:09 +02:00
|
|
|
target.path = sanitize_path(target.path);
|
2006-10-13 01:51:10 +02:00
|
|
|
verify_encoding(target);
|
2008-10-03 07:49:41 +02:00
|
|
|
|
|
|
|
// bitcomet pad file
|
2009-10-26 02:29:39 +01:00
|
|
|
if (target.path.find("_____padding_file_") != std::string::npos)
|
2008-10-03 07:49:41 +02:00
|
|
|
target.pad_file = true;
|
|
|
|
|
2009-01-11 23:27:43 +01:00
|
|
|
lazy_entry const* attr = dict.dict_find_string("attr");
|
|
|
|
if (attr)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < attr->string_length(); ++i)
|
|
|
|
{
|
|
|
|
switch (attr->string_ptr()[i])
|
|
|
|
{
|
2009-07-01 10:35:45 +02:00
|
|
|
case 'l': target.symlink_attribute = true; target.size = 0; break;
|
2009-01-11 23:27:43 +01:00
|
|
|
case 'x': target.executable_attribute = true; break;
|
|
|
|
case 'h': target.hidden_attribute = true; break;
|
|
|
|
case 'p': target.pad_file = true; break;
|
|
|
|
}
|
|
|
|
}
|
2009-06-26 18:20:57 +02:00
|
|
|
}
|
2009-01-11 23:27:43 +01:00
|
|
|
|
2010-03-27 16:51:30 +01:00
|
|
|
lazy_entry const* fh = dict.dict_find_string("sha1");
|
|
|
|
if (fh && fh->string_length() == 20)
|
|
|
|
{
|
|
|
|
target.filehash.reset(new sha1_hash);
|
|
|
|
std::memcpy(&(*target.filehash)[0], fh->string_ptr(), 20);
|
|
|
|
}
|
|
|
|
|
2009-07-01 10:35:45 +02:00
|
|
|
lazy_entry const* s_p = dict.dict_find("symlink path");
|
|
|
|
if (s_p != 0 && s_p->type() == lazy_entry::list_t)
|
|
|
|
{
|
|
|
|
for (int i = 0, end(s_p->list_size()); i < end; ++i)
|
|
|
|
{
|
|
|
|
std::string path_element = s_p->list_at(i)->string_value();
|
|
|
|
trim_path_element(path_element);
|
2009-10-26 02:29:39 +01:00
|
|
|
target.symlink_path = combine_path(target.symlink_path, path_element);
|
2009-07-01 10:35:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-28 21:11:10 +01:00
|
|
|
return true;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2009-11-26 07:54:52 +01:00
|
|
|
struct string_less_no_case
|
2009-11-26 01:09:49 +01:00
|
|
|
{
|
2009-11-26 07:54:52 +01:00
|
|
|
bool operator()(std::string const& lhs, std::string const& rhs)
|
2009-11-26 01:09:49 +01:00
|
|
|
{
|
2009-11-26 07:54:52 +01:00
|
|
|
char c1, c2;
|
|
|
|
char const* s1 = lhs.c_str();
|
|
|
|
char const* s2 = rhs.c_str();
|
|
|
|
|
|
|
|
while (*s1 != 0 && *s2 != 0)
|
|
|
|
{
|
|
|
|
c1 = to_lower(*s1);
|
|
|
|
c2 = to_lower(*s2);
|
|
|
|
if (c1 < c2) return true;
|
|
|
|
if (c1 > c2) return false;
|
|
|
|
++s1;
|
|
|
|
++s2;
|
|
|
|
}
|
|
|
|
return false;
|
2009-11-26 01:09:49 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2008-05-28 10:44:40 +02:00
|
|
|
bool extract_files(lazy_entry const& list, file_storage& target
|
2005-05-12 01:03:12 +02:00
|
|
|
, std::string const& root_dir)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-05-14 07:29:42 +02:00
|
|
|
if (list.type() != lazy_entry::list_t) return false;
|
2009-11-26 07:54:52 +01:00
|
|
|
target.reserve(list.list_size());
|
2008-05-14 07:29:42 +02:00
|
|
|
for (int i = 0, end(list.list_size()); i < end; ++i)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-05-28 10:44:40 +02:00
|
|
|
file_entry e;
|
|
|
|
if (!extract_single_file(*list.list_at(i), e, root_dir))
|
2007-12-28 21:11:10 +01:00
|
|
|
return false;
|
2009-06-26 18:20:57 +02:00
|
|
|
int cnt = 0;
|
2009-11-26 07:54:52 +01:00
|
|
|
std::set<std::string, string_less_no_case> files;
|
|
|
|
|
2010-03-27 16:51:30 +01:00
|
|
|
// as long as this file already exists
|
2009-11-26 07:54:52 +01:00
|
|
|
// increase the counter
|
|
|
|
while (!files.insert(e.path).second)
|
2009-06-26 18:20:57 +02:00
|
|
|
{
|
2009-11-26 07:54:52 +01:00
|
|
|
++cnt;
|
|
|
|
char suffix[50];
|
|
|
|
snprintf(suffix, sizeof(suffix), ".%d%s", cnt, extension(e.path).c_str());
|
|
|
|
replace_extension(e.path, suffix);
|
2009-06-26 18:20:57 +02:00
|
|
|
}
|
2008-05-28 10:44:40 +02:00
|
|
|
target.add_file(e);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2007-12-28 21:11:10 +01:00
|
|
|
return true;
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2009-03-13 07:09:39 +01:00
|
|
|
int merkle_get_parent(int tree_node)
|
|
|
|
{
|
|
|
|
// node 0 doesn't have a parent
|
|
|
|
TORRENT_ASSERT(tree_node > 0);
|
|
|
|
return (tree_node - 1) / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
int merkle_get_sibling(int tree_node)
|
|
|
|
{
|
|
|
|
// node 0 doesn't have a sibling
|
|
|
|
TORRENT_ASSERT(tree_node > 0);
|
|
|
|
// even numbers have their sibling to the left
|
|
|
|
// odd numbers have their sibling to the right
|
|
|
|
return tree_node + (tree_node&1?1:-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int merkle_num_nodes(int leafs)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(leafs > 0);
|
|
|
|
return (leafs << 1) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int merkle_num_leafs(int pieces)
|
|
|
|
{
|
|
|
|
// round up to nearest 2 exponent
|
|
|
|
int i;
|
|
|
|
for (i = 0; pieces > 0; pieces >>= 1, ++i);
|
|
|
|
return 1 << i;
|
|
|
|
}
|
2008-07-01 13:00:00 +02:00
|
|
|
|
2009-10-26 02:29:39 +01:00
|
|
|
int load_file(std::string const& filename, std::vector<char>& v)
|
2008-07-01 13:00:00 +02:00
|
|
|
{
|
|
|
|
file f;
|
2008-07-18 01:41:46 +02:00
|
|
|
error_code ec;
|
2008-10-19 07:03:17 +02:00
|
|
|
if (!f.open(filename, file::read_only, ec)) return -1;
|
2009-01-11 03:02:34 +01:00
|
|
|
size_type s = f.get_size(ec);
|
2008-07-18 01:41:46 +02:00
|
|
|
if (ec) return -1;
|
2008-07-01 13:00:00 +02:00
|
|
|
if (s > 5000000) return -2;
|
|
|
|
v.resize(s);
|
2008-10-05 06:52:01 +02:00
|
|
|
if (s == 0) return 0;
|
2009-01-11 03:02:34 +01:00
|
|
|
file::iovec_t b = {&v[0], s};
|
|
|
|
size_type read = f.readv(0, &b, 1, ec);
|
2008-07-01 13:00:00 +02:00
|
|
|
if (read != s) return -3;
|
2008-07-18 01:41:46 +02:00
|
|
|
if (ec) return -3;
|
2008-07-01 13:00:00 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-02 05:05:24 +01:00
|
|
|
int announce_entry::next_announce_in() const
|
|
|
|
{ return total_seconds(time_now() - next_announce); }
|
|
|
|
|
|
|
|
int announce_entry::min_announce_in() const
|
|
|
|
{ return total_seconds(time_now() - min_announce); }
|
|
|
|
|
2009-12-21 10:47:32 +01:00
|
|
|
void announce_entry::failed(int retry_interval)
|
2009-11-25 07:55:34 +01:00
|
|
|
{
|
|
|
|
++fails;
|
2009-12-21 10:47:32 +01:00
|
|
|
int delay = (std::min)(tracker_retry_delay_min + int(fails) * int(fails)
|
|
|
|
* tracker_retry_delay_min, int(tracker_retry_delay_max));
|
|
|
|
delay = (std::max)(delay, retry_interval);
|
2009-11-25 07:55:34 +01:00
|
|
|
next_announce = time_now() + seconds(delay);
|
|
|
|
updating = false;
|
|
|
|
}
|
|
|
|
|
2009-11-26 19:31:27 +01:00
|
|
|
void announce_entry::trim()
|
|
|
|
{
|
|
|
|
while (!url.empty() && is_space(url[0]))
|
|
|
|
url.erase(url.begin());
|
|
|
|
}
|
|
|
|
|
2009-11-26 07:54:52 +01:00
|
|
|
torrent_info::torrent_info(torrent_info const& t)
|
|
|
|
: m_files(t.m_files)
|
|
|
|
, m_orig_files(t.m_orig_files)
|
|
|
|
, m_urls(t.m_urls)
|
|
|
|
, m_url_seeds(t.m_url_seeds)
|
|
|
|
, m_http_seeds(t.m_http_seeds)
|
|
|
|
, m_nodes(t.m_nodes)
|
|
|
|
, m_info_hash(t.m_info_hash)
|
|
|
|
, m_creation_date(t.m_creation_date)
|
|
|
|
, m_comment(t.m_comment)
|
|
|
|
, m_created_by(t.m_created_by)
|
|
|
|
, m_multifile(t.m_multifile)
|
|
|
|
, m_private(t.m_private)
|
|
|
|
, m_i2p(t.m_i2p)
|
|
|
|
, m_info_section_size(t.m_info_section_size)
|
|
|
|
, m_piece_hashes(t.m_piece_hashes)
|
|
|
|
, m_merkle_tree(t.m_merkle_tree)
|
|
|
|
, m_merkle_first_leaf(t.m_merkle_first_leaf)
|
|
|
|
{
|
|
|
|
if (m_info_section_size > 0)
|
|
|
|
{
|
|
|
|
m_info_section.reset(new char[m_info_section_size]);
|
|
|
|
memcpy(m_info_section.get(), t.m_info_section.get(), m_info_section_size);
|
|
|
|
int ret = lazy_bdecode(m_info_section.get(), m_info_section.get()
|
|
|
|
+ m_info_section_size, m_info_dict);
|
|
|
|
|
|
|
|
lazy_entry const* pieces = m_info_dict.dict_find_string("pieces");
|
|
|
|
if (pieces && pieces->string_length() == m_files.num_pieces() * 20)
|
|
|
|
{
|
|
|
|
m_piece_hashes = m_info_section.get() + (pieces->string_ptr() - m_info_section.get());
|
|
|
|
TORRENT_ASSERT(m_piece_hashes >= m_info_section.get());
|
|
|
|
TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-27 23:15:34 +01:00
|
|
|
void torrent_info::remap_files(file_storage const& f)
|
|
|
|
{
|
|
|
|
// the new specified file storage must have the exact
|
|
|
|
// same size as the current file storage
|
|
|
|
TORRENT_ASSERT(m_files.total_size() == f.total_size());
|
|
|
|
|
|
|
|
if (m_files.total_size() != f.total_size()) return;
|
|
|
|
copy_on_write();
|
|
|
|
m_files = f;
|
|
|
|
}
|
|
|
|
|
2008-08-03 17:14:08 +02:00
|
|
|
#ifndef TORRENT_NO_DEPRECATE
|
2004-03-03 14:47:12 +01:00
|
|
|
// standard constructor that parses a torrent file
|
2008-05-14 07:29:42 +02:00
|
|
|
torrent_info::torrent_info(entry const& torrent_file)
|
2008-05-28 10:44:40 +02:00
|
|
|
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
2005-05-12 01:03:12 +02:00
|
|
|
, m_multifile(false)
|
2006-08-01 17:27:08 +02:00
|
|
|
, m_private(false)
|
2009-08-20 05:19:12 +02:00
|
|
|
, m_i2p(false)
|
2008-05-14 07:29:42 +02:00
|
|
|
, m_info_section_size(0)
|
|
|
|
, m_piece_hashes(0)
|
2009-03-13 07:09:39 +01:00
|
|
|
, m_merkle_first_leaf(0)
|
2008-05-14 07:29:42 +02:00
|
|
|
{
|
|
|
|
std::vector<char> tmp;
|
|
|
|
std::back_insert_iterator<std::vector<char> > out(tmp);
|
|
|
|
bencode(out, torrent_file);
|
|
|
|
|
|
|
|
lazy_entry e;
|
2009-02-23 02:21:19 +01:00
|
|
|
if (lazy_bdecode(&tmp[0], &tmp[0] + tmp.size(), e) != 0)
|
|
|
|
{
|
|
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
2009-11-29 08:06:38 +01:00
|
|
|
throw invalid_torrent_file(errors::invalid_bencoding);
|
2009-02-23 02:21:19 +01:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2009-02-13 20:01:02 +01:00
|
|
|
error_code ec;
|
2008-05-14 07:29:42 +02:00
|
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
2009-02-13 20:01:02 +01:00
|
|
|
if (!parse_torrent_file(e, ec))
|
2009-02-23 02:21:19 +01:00
|
|
|
throw invalid_torrent_file(ec);
|
2008-05-14 07:29:42 +02:00
|
|
|
#else
|
2009-02-13 20:01:02 +01:00
|
|
|
parse_torrent_file(e, ec);
|
2007-05-10 00:54:26 +02:00
|
|
|
#endif
|
2008-05-14 07:29:42 +02:00
|
|
|
}
|
2008-08-03 17:14:08 +02:00
|
|
|
#endif
|
2008-05-14 07:29:42 +02:00
|
|
|
|
2009-02-23 02:21:19 +01:00
|
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
2008-05-14 07:29:42 +02:00
|
|
|
torrent_info::torrent_info(lazy_entry const& torrent_file)
|
2008-05-28 10:44:40 +02:00
|
|
|
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
2008-05-14 07:29:42 +02:00
|
|
|
, m_multifile(false)
|
|
|
|
, m_private(false)
|
2009-09-06 19:03:11 +02:00
|
|
|
, m_i2p(false)
|
2008-05-14 07:29:42 +02:00
|
|
|
, m_info_section_size(0)
|
|
|
|
, m_piece_hashes(0)
|
2009-03-13 07:09:39 +01:00
|
|
|
, m_merkle_first_leaf(0)
|
2004-03-03 14:47:12 +01:00
|
|
|
{
|
2009-02-13 20:01:02 +01:00
|
|
|
error_code ec;
|
|
|
|
if (!parse_torrent_file(torrent_file, ec))
|
2009-02-23 02:21:19 +01:00
|
|
|
throw invalid_torrent_file(ec);
|
2004-03-03 14:47:12 +01:00
|
|
|
}
|
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
torrent_info::torrent_info(char const* buffer, int size)
|
2008-05-28 10:44:40 +02:00
|
|
|
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
2008-05-14 07:29:42 +02:00
|
|
|
, m_multifile(false)
|
|
|
|
, m_private(false)
|
2009-09-06 19:03:11 +02:00
|
|
|
, m_i2p(false)
|
2008-05-14 07:29:42 +02:00
|
|
|
, m_info_section_size(0)
|
|
|
|
, m_piece_hashes(0)
|
2009-03-13 07:09:39 +01:00
|
|
|
, m_merkle_first_leaf(0)
|
2008-05-14 07:29:42 +02:00
|
|
|
{
|
2009-02-13 20:01:02 +01:00
|
|
|
error_code ec;
|
2008-05-14 07:29:42 +02:00
|
|
|
lazy_entry e;
|
2009-02-23 02:21:19 +01:00
|
|
|
if (lazy_bdecode(buffer, buffer + size, e) != 0)
|
2009-11-29 08:06:38 +01:00
|
|
|
throw invalid_torrent_file(errors::invalid_bencoding);
|
2009-02-23 02:21:19 +01:00
|
|
|
|
2009-02-13 20:01:02 +01:00
|
|
|
if (!parse_torrent_file(e, ec))
|
2009-02-23 02:21:19 +01:00
|
|
|
throw invalid_torrent_file(ec);
|
2008-05-14 07:29:42 +02:00
|
|
|
}
|
|
|
|
|
2009-10-26 02:29:39 +01:00
|
|
|
torrent_info::torrent_info(std::string const& filename)
|
2009-02-23 02:21:19 +01:00
|
|
|
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
2005-05-12 01:03:12 +02:00
|
|
|
, m_multifile(false)
|
2006-11-14 01:08:16 +01:00
|
|
|
, m_private(false)
|
2009-09-06 19:03:11 +02:00
|
|
|
, m_i2p(false)
|
2008-05-14 07:29:42 +02:00
|
|
|
, m_info_section_size(0)
|
|
|
|
, m_piece_hashes(0)
|
2009-02-23 02:21:19 +01:00
|
|
|
{
|
|
|
|
std::vector<char> buf;
|
|
|
|
int ret = load_file(filename, buf);
|
|
|
|
if (ret < 0) return;
|
2004-10-10 02:42:48 +02:00
|
|
|
|
2009-02-23 02:21:19 +01:00
|
|
|
lazy_entry e;
|
|
|
|
if (lazy_bdecode(&buf[0], &buf[0] + buf.size(), e) != 0)
|
2009-11-29 08:06:38 +01:00
|
|
|
throw invalid_torrent_file(errors::invalid_bencoding);
|
2009-02-23 02:21:19 +01:00
|
|
|
error_code ec;
|
|
|
|
if (!parse_torrent_file(e, ec))
|
|
|
|
throw invalid_torrent_file(ec);
|
|
|
|
}
|
|
|
|
|
2009-10-26 02:29:39 +01:00
|
|
|
#if TORRENT_USE_WSTRING
|
|
|
|
torrent_info::torrent_info(std::wstring const& filename)
|
2008-05-28 10:44:40 +02:00
|
|
|
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
2008-05-12 08:35:24 +02:00
|
|
|
, m_multifile(false)
|
|
|
|
, m_private(false)
|
2009-09-06 19:03:11 +02:00
|
|
|
, m_i2p(false)
|
2009-02-23 02:21:19 +01:00
|
|
|
, m_info_section_size(0)
|
|
|
|
, m_piece_hashes(0)
|
2009-03-13 07:09:39 +01:00
|
|
|
, m_merkle_first_leaf(0)
|
2008-05-12 08:35:24 +02:00
|
|
|
{
|
2008-07-01 01:14:31 +02:00
|
|
|
std::vector<char> buf;
|
2009-02-23 02:21:19 +01:00
|
|
|
std::string utf8;
|
2009-10-26 02:29:39 +01:00
|
|
|
wchar_utf8(filename, utf8);
|
2009-02-23 02:21:19 +01:00
|
|
|
int ret = load_file(utf8, buf);
|
2008-07-01 01:14:31 +02:00
|
|
|
if (ret < 0) return;
|
2008-05-14 07:29:42 +02:00
|
|
|
|
2008-12-01 08:52:59 +01:00
|
|
|
lazy_entry e;
|
2009-02-23 02:21:19 +01:00
|
|
|
if (lazy_bdecode(&buf[0], &buf[0] + buf.size(), e) != 0)
|
2009-11-29 08:06:38 +01:00
|
|
|
throw invalid_torrent_file(errors::invalid_bencoding);
|
2009-02-23 02:21:19 +01:00
|
|
|
|
2009-02-13 20:01:02 +01:00
|
|
|
error_code ec;
|
|
|
|
if (!parse_torrent_file(e, ec))
|
2009-02-23 02:21:19 +01:00
|
|
|
throw invalid_torrent_file(ec);
|
|
|
|
}
|
2009-03-31 10:12:35 +02:00
|
|
|
#endif
|
2008-12-01 08:52:59 +01:00
|
|
|
#endif
|
2009-02-23 02:21:19 +01:00
|
|
|
|
|
|
|
torrent_info::torrent_info(lazy_entry const& torrent_file, error_code& ec)
|
|
|
|
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
|
|
|
, m_multifile(false)
|
|
|
|
, m_private(false)
|
2009-09-06 19:03:11 +02:00
|
|
|
, m_i2p(false)
|
2009-02-23 02:21:19 +01:00
|
|
|
, m_info_section_size(0)
|
|
|
|
, m_piece_hashes(0)
|
|
|
|
{
|
|
|
|
parse_torrent_file(torrent_file, ec);
|
2008-12-01 08:52:59 +01:00
|
|
|
}
|
|
|
|
|
2009-02-23 02:21:19 +01:00
|
|
|
torrent_info::torrent_info(char const* buffer, int size, error_code& ec)
|
2008-12-01 08:52:59 +01:00
|
|
|
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
|
|
|
, m_multifile(false)
|
|
|
|
, m_private(false)
|
2009-09-06 19:03:11 +02:00
|
|
|
, m_i2p(false)
|
2009-02-23 02:21:19 +01:00
|
|
|
, m_info_section_size(0)
|
|
|
|
, m_piece_hashes(0)
|
2009-03-13 07:09:39 +01:00
|
|
|
, m_merkle_first_leaf(0)
|
2009-02-23 02:21:19 +01:00
|
|
|
{
|
|
|
|
lazy_entry e;
|
|
|
|
if (lazy_bdecode(buffer, buffer + size, e) != 0)
|
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::invalid_bencoding;
|
2009-02-23 02:21:19 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
parse_torrent_file(e, ec);
|
|
|
|
}
|
|
|
|
|
2009-10-26 02:29:39 +01:00
|
|
|
torrent_info::torrent_info(std::string const& filename, error_code& ec)
|
2009-02-23 02:21:19 +01:00
|
|
|
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
|
|
|
, m_multifile(false)
|
|
|
|
, m_private(false)
|
2009-09-06 19:03:11 +02:00
|
|
|
, m_i2p(false)
|
2009-02-23 02:21:19 +01:00
|
|
|
, m_info_section_size(0)
|
|
|
|
, m_piece_hashes(0)
|
|
|
|
{
|
|
|
|
std::vector<char> buf;
|
|
|
|
int ret = load_file(filename, buf);
|
|
|
|
if (ret < 0) return;
|
|
|
|
|
|
|
|
lazy_entry e;
|
|
|
|
if (lazy_bdecode(&buf[0], &buf[0] + buf.size(), e) != 0)
|
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::invalid_bencoding;
|
2009-02-23 02:21:19 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
parse_torrent_file(e, ec);
|
|
|
|
}
|
|
|
|
|
2009-10-26 02:29:39 +01:00
|
|
|
#if TORRENT_USE_WSTRING
|
|
|
|
torrent_info::torrent_info(std::wstring const& filename, error_code& ec)
|
2009-02-23 02:21:19 +01:00
|
|
|
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
|
|
|
, m_multifile(false)
|
|
|
|
, m_private(false)
|
2009-09-06 19:03:11 +02:00
|
|
|
, m_i2p(false)
|
2009-02-23 02:21:19 +01:00
|
|
|
, m_info_section_size(0)
|
|
|
|
, m_piece_hashes(0)
|
2008-12-01 08:52:59 +01:00
|
|
|
{
|
|
|
|
std::vector<char> buf;
|
|
|
|
std::string utf8;
|
2009-10-26 02:29:39 +01:00
|
|
|
wchar_utf8(filename, utf8);
|
2008-12-01 08:52:59 +01:00
|
|
|
int ret = load_file(utf8, buf);
|
|
|
|
if (ret < 0) return;
|
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
lazy_entry e;
|
2009-02-23 02:21:19 +01:00
|
|
|
if (lazy_bdecode(&buf[0], &buf[0] + buf.size(), e) != 0)
|
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::invalid_bencoding;
|
2009-02-23 02:21:19 +01:00
|
|
|
return;
|
|
|
|
}
|
2009-02-13 20:01:02 +01:00
|
|
|
parse_torrent_file(e, ec);
|
2008-05-12 08:35:24 +02:00
|
|
|
}
|
2009-03-31 10:12:35 +02:00
|
|
|
#endif
|
2008-05-12 08:35:24 +02:00
|
|
|
|
2009-11-23 09:38:50 +01:00
|
|
|
typedef boost::date_time::second_clock<pt::ptime> second_clock;
|
|
|
|
|
2009-02-23 02:21:19 +01:00
|
|
|
// constructor used for creating new torrents
|
|
|
|
// will not contain any hashes, comments, creation date
|
|
|
|
// 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_info_hash(info_hash)
|
2009-11-23 09:38:50 +01:00
|
|
|
, m_creation_date(second_clock::universal_time())
|
2009-02-23 02:21:19 +01:00
|
|
|
, m_multifile(false)
|
|
|
|
, m_private(false)
|
2009-09-06 19:03:11 +02:00
|
|
|
, m_i2p(false)
|
2009-02-23 02:21:19 +01:00
|
|
|
, m_info_section_size(0)
|
|
|
|
, m_piece_hashes(0)
|
|
|
|
{}
|
|
|
|
|
2004-10-29 15:21:09 +02:00
|
|
|
torrent_info::~torrent_info()
|
|
|
|
{}
|
|
|
|
|
2008-12-24 21:07:34 +01:00
|
|
|
void torrent_info::copy_on_write()
|
|
|
|
{
|
|
|
|
if (m_orig_files) return;
|
|
|
|
m_orig_files.reset(new file_storage(m_files));
|
|
|
|
}
|
|
|
|
|
2007-06-10 22:46:09 +02:00
|
|
|
void torrent_info::swap(torrent_info& ti)
|
|
|
|
{
|
|
|
|
using std::swap;
|
|
|
|
m_urls.swap(ti.m_urls);
|
|
|
|
m_url_seeds.swap(ti.m_url_seeds);
|
|
|
|
m_files.swap(ti.m_files);
|
2008-12-24 21:07:34 +01:00
|
|
|
m_orig_files.swap(ti.m_orig_files);
|
2007-06-10 22:46:09 +02:00
|
|
|
m_nodes.swap(ti.m_nodes);
|
|
|
|
swap(m_info_hash, ti.m_info_hash);
|
|
|
|
swap(m_creation_date, ti.m_creation_date);
|
|
|
|
m_comment.swap(ti.m_comment);
|
|
|
|
m_created_by.swap(ti.m_created_by);
|
|
|
|
swap(m_multifile, ti.m_multifile);
|
|
|
|
swap(m_private, ti.m_private);
|
2009-08-20 05:19:12 +02:00
|
|
|
swap(m_i2p, ti.m_i2p);
|
2008-05-14 07:29:42 +02:00
|
|
|
swap(m_info_section, ti.m_info_section);
|
|
|
|
swap(m_info_section_size, ti.m_info_section_size);
|
|
|
|
swap(m_piece_hashes, ti.m_piece_hashes);
|
2009-11-26 07:54:52 +01:00
|
|
|
m_info_dict.swap(ti.m_info_dict);
|
|
|
|
swap(m_merkle_tree, ti.m_merkle_tree);
|
|
|
|
swap(m_merkle_first_leaf, ti.m_merkle_first_leaf);
|
2004-10-10 02:42:48 +02:00
|
|
|
}
|
2004-03-03 14:47:12 +01:00
|
|
|
|
2009-02-13 20:01:02 +01:00
|
|
|
bool torrent_info::parse_info_section(lazy_entry const& info, error_code& ec)
|
2004-06-14 01:30:42 +02:00
|
|
|
{
|
2008-05-14 07:29:42 +02:00
|
|
|
if (info.type() != lazy_entry::dict_t)
|
2007-12-28 21:11:10 +01:00
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::torrent_info_no_dict;
|
2007-12-28 21:11:10 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
// hash the info-field to calculate info-hash
|
2004-06-14 01:30:42 +02:00
|
|
|
hasher h;
|
2008-05-14 07:29:42 +02:00
|
|
|
std::pair<char const*, int> section = info.data_section();
|
|
|
|
h.update(section.first, section.second);
|
2004-06-14 01:30:42 +02:00
|
|
|
m_info_hash = h.final();
|
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
// copy the info section
|
|
|
|
m_info_section_size = section.second;
|
|
|
|
m_info_section.reset(new char[m_info_section_size]);
|
2009-01-27 09:24:48 +01:00
|
|
|
std::memcpy(m_info_section.get(), section.first, m_info_section_size);
|
2008-05-14 07:29:42 +02:00
|
|
|
TORRENT_ASSERT(section.first[0] == 'd');
|
|
|
|
TORRENT_ASSERT(section.first[m_info_section_size-1] == 'e');
|
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
// extract piece length
|
2008-05-28 10:44:40 +02:00
|
|
|
int piece_length = info.dict_find_int_value("piece length", -1);
|
|
|
|
if (piece_length <= 0)
|
2007-12-28 21:11:10 +01:00
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::torrent_missing_piece_length;
|
2007-12-28 21:11:10 +01:00
|
|
|
return false;
|
|
|
|
}
|
2008-05-28 10:44:40 +02:00
|
|
|
m_files.set_piece_length(piece_length);
|
2004-06-14 01:30:42 +02:00
|
|
|
|
|
|
|
// extract file name (or the directory name if it's a multifile libtorrent)
|
2008-05-28 10:44:40 +02:00
|
|
|
std::string name = info.dict_find_string_value("name.utf-8");
|
|
|
|
if (name.empty()) name = info.dict_find_string_value("name");
|
|
|
|
if (name.empty())
|
2007-12-28 21:11:10 +01:00
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::torrent_missing_name;
|
2008-05-14 07:29:42 +02:00
|
|
|
return false;
|
2007-12-28 21:11:10 +01:00
|
|
|
}
|
2008-05-14 07:29:42 +02:00
|
|
|
|
2009-10-26 02:29:39 +01:00
|
|
|
name = sanitize_path(name);
|
2009-05-28 09:25:09 +02:00
|
|
|
|
|
|
|
if (!valid_path_element(name))
|
2007-12-28 21:11:10 +01:00
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::torrent_invalid_name;
|
2007-12-28 21:11:10 +01:00
|
|
|
return false;
|
|
|
|
}
|
2008-12-31 11:18:19 +01:00
|
|
|
|
|
|
|
// correct utf-8 encoding errors
|
2009-11-13 03:50:07 +01:00
|
|
|
verify_encoding(name, true);
|
2005-05-12 01:03:12 +02:00
|
|
|
|
2004-06-14 01:30:42 +02:00
|
|
|
// extract file list
|
2008-05-14 07:29:42 +02:00
|
|
|
lazy_entry const* i = info.dict_find_list("files");
|
2004-06-14 01:30:42 +02:00
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
// if there's no list of files, there has to be a length
|
|
|
|
// field.
|
|
|
|
file_entry e;
|
2008-05-28 10:44:40 +02:00
|
|
|
e.path = name;
|
2006-06-18 00:04:25 +02:00
|
|
|
e.offset = 0;
|
2008-05-14 07:29:42 +02:00
|
|
|
e.size = info.dict_find_int_value("length", -1);
|
2009-06-23 04:50:41 +02:00
|
|
|
size_type ts = info.dict_find_int_value("mtime", -1);
|
|
|
|
if (ts >= 0)
|
|
|
|
e.mtime = std::time_t(ts);
|
|
|
|
lazy_entry const* attr = info.dict_find_string("attr");
|
|
|
|
if (attr)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < attr->string_length(); ++i)
|
|
|
|
{
|
|
|
|
switch (attr->string_ptr()[i])
|
|
|
|
{
|
2009-07-01 10:35:45 +02:00
|
|
|
case 'l': e.symlink_attribute = true; e.size = 0; break;
|
2009-06-23 04:50:41 +02:00
|
|
|
case 'x': e.executable_attribute = true; break;
|
|
|
|
case 'h': e.hidden_attribute = true; break;
|
|
|
|
case 'p': e.pad_file = true; break;
|
|
|
|
}
|
|
|
|
}
|
2009-07-01 10:35:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
lazy_entry const* s_p = info.dict_find("symlink path");
|
|
|
|
if (s_p != 0 && s_p->type() == lazy_entry::list_t)
|
|
|
|
{
|
|
|
|
for (int i = 0, end(s_p->list_size()); i < end; ++i)
|
|
|
|
{
|
|
|
|
std::string path_element = s_p->list_at(i)->string_value();
|
|
|
|
trim_path_element(path_element);
|
2009-10-26 02:29:39 +01:00
|
|
|
e.symlink_path = combine_path(e.symlink_path, path_element);
|
2009-07-01 10:35:45 +02:00
|
|
|
}
|
|
|
|
}
|
2010-03-27 16:51:30 +01:00
|
|
|
lazy_entry const* fh = info.dict_find_string("sha1");
|
|
|
|
if (fh && fh->string_length() == 20)
|
|
|
|
{
|
|
|
|
e.filehash.reset(new sha1_hash);
|
|
|
|
std::memcpy(&(*e.filehash)[0], fh->string_ptr(), 20);
|
|
|
|
}
|
|
|
|
|
2008-10-03 07:49:41 +02:00
|
|
|
// bitcomet pad file
|
2009-10-26 02:29:39 +01:00
|
|
|
if (e.path.find("_____padding_file_") != std::string::npos)
|
2008-10-03 07:49:41 +02:00
|
|
|
e.pad_file = true;
|
2008-05-14 07:29:42 +02:00
|
|
|
if (e.size < 0)
|
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::torrent_invalid_length;
|
2008-05-14 07:29:42 +02:00
|
|
|
return false;
|
|
|
|
}
|
2008-05-28 10:44:40 +02:00
|
|
|
m_files.add_file(e);
|
2008-05-14 07:29:42 +02:00
|
|
|
m_multifile = false;
|
2004-06-14 01:30:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-05-28 10:44:40 +02:00
|
|
|
if (!extract_files(*i, m_files, name))
|
2007-12-28 21:11:10 +01:00
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::torrent_file_parse_failed;
|
2007-12-28 21:11:10 +01:00
|
|
|
return false;
|
|
|
|
}
|
2005-05-12 01:03:12 +02:00
|
|
|
m_multifile = true;
|
2004-06-14 01:30:42 +02:00
|
|
|
}
|
2008-05-28 10:44:40 +02:00
|
|
|
m_files.set_name(name);
|
2004-06-14 01:30:42 +02:00
|
|
|
|
|
|
|
// extract sha-1 hashes for all pieces
|
|
|
|
// we want this division to round upwards, that's why we have the
|
|
|
|
// extra addition
|
|
|
|
|
2008-05-28 10:44:40 +02:00
|
|
|
m_files.set_num_pieces(int((m_files.total_size() + m_files.piece_length() - 1)
|
|
|
|
/ m_files.piece_length()));
|
2008-05-14 07:29:42 +02:00
|
|
|
|
|
|
|
lazy_entry const* pieces = info.dict_find("pieces");
|
2009-03-13 07:09:39 +01:00
|
|
|
lazy_entry const* root_hash = info.dict_find("root hash");
|
|
|
|
if ((pieces == 0 || pieces->type() != lazy_entry::string_t)
|
|
|
|
&& (root_hash == 0 || root_hash->type() != lazy_entry::string_t))
|
2007-12-28 21:11:10 +01:00
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::torrent_missing_pieces;
|
2007-12-28 21:11:10 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-03-13 07:09:39 +01:00
|
|
|
if (pieces)
|
2007-12-28 21:11:10 +01:00
|
|
|
{
|
2009-03-13 07:09:39 +01:00
|
|
|
if (pieces->string_length() != m_files.num_pieces() * 20)
|
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::torrent_invalid_hashes;
|
2009-03-13 07:09:39 +01:00
|
|
|
return false;
|
|
|
|
}
|
2004-06-14 01:30:42 +02:00
|
|
|
|
2009-03-13 07:09:39 +01:00
|
|
|
m_piece_hashes = m_info_section.get() + (pieces->string_ptr() - section.first);
|
|
|
|
TORRENT_ASSERT(m_piece_hashes >= m_info_section.get());
|
|
|
|
TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(root_hash);
|
|
|
|
if (root_hash->string_length() != 20)
|
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::torrent_invalid_hashes;
|
2009-03-13 07:09:39 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int num_leafs = merkle_num_leafs(m_files.num_pieces());
|
|
|
|
int num_nodes = merkle_num_nodes(num_leafs);
|
|
|
|
m_merkle_first_leaf = num_nodes - num_leafs;
|
|
|
|
m_merkle_tree.resize(num_nodes);
|
|
|
|
std::memset(&m_merkle_tree[0], 0, num_nodes * 20);
|
|
|
|
m_merkle_tree[0].assign(root_hash->string_ptr());
|
|
|
|
}
|
2005-10-16 18:58:41 +02:00
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
m_private = info.dict_find_int_value("private", 0);
|
2007-12-28 21:11:10 +01:00
|
|
|
return true;
|
2004-06-14 01:30:42 +02:00
|
|
|
}
|
|
|
|
|
2009-03-13 07:09:39 +01:00
|
|
|
bool torrent_info::add_merkle_nodes(std::map<int, sha1_hash> const& subtree
|
|
|
|
, int piece)
|
|
|
|
{
|
|
|
|
int n = m_merkle_first_leaf + piece;
|
|
|
|
typedef std::map<int, sha1_hash>::const_iterator iter;
|
|
|
|
iter i = subtree.find(n);
|
|
|
|
if (i == subtree.end()) return false;
|
|
|
|
sha1_hash h = i->second;
|
|
|
|
|
|
|
|
// if the verification passes, these are the
|
|
|
|
// nodes to add to our tree
|
|
|
|
std::map<int, sha1_hash> to_add;
|
|
|
|
|
|
|
|
while (n > 0)
|
|
|
|
{
|
|
|
|
int sibling = merkle_get_sibling(n);
|
|
|
|
int parent = merkle_get_parent(n);
|
|
|
|
iter sibling_hash = subtree.find(sibling);
|
|
|
|
if (sibling_hash == subtree.end())
|
|
|
|
return false;
|
|
|
|
to_add[n] = h;
|
|
|
|
to_add[sibling] = sibling_hash->second;
|
|
|
|
hasher hs;
|
|
|
|
if (sibling < n)
|
|
|
|
{
|
|
|
|
hs.update((char const*)&sibling_hash->second[0], 20);
|
|
|
|
hs.update((char const*)&h[0], 20);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hs.update((char const*)&h[0], 20);
|
|
|
|
hs.update((char const*)&sibling_hash->second[0], 20);
|
|
|
|
}
|
|
|
|
h = hs.final();
|
|
|
|
n = parent;
|
|
|
|
}
|
|
|
|
if (h != m_merkle_tree[0]) return false;
|
|
|
|
|
|
|
|
// the nodes and piece hash matched the root-hash
|
|
|
|
// insert them into our tree
|
|
|
|
|
|
|
|
for (std::map<int, sha1_hash>::iterator i = to_add.begin()
|
|
|
|
, end(to_add.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
m_merkle_tree[i->first] = i->second;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// builds a list of nodes that are required to verify
|
|
|
|
// the given piece
|
|
|
|
std::map<int, sha1_hash> torrent_info::build_merkle_list(int piece) const
|
|
|
|
{
|
|
|
|
std::map<int, sha1_hash> ret;
|
|
|
|
int n = m_merkle_first_leaf + piece;
|
|
|
|
ret[n] = m_merkle_tree[n];
|
|
|
|
ret[0] = m_merkle_tree[0];
|
|
|
|
while (n > 0)
|
|
|
|
{
|
|
|
|
int sibling = merkle_get_sibling(n);
|
|
|
|
int parent = merkle_get_parent(n);
|
|
|
|
ret[sibling] = m_merkle_tree[sibling];
|
|
|
|
// we cannot build the tree path if one
|
|
|
|
// of the nodes in the tree is missing
|
|
|
|
TORRENT_ASSERT(m_merkle_tree[sibling] != sha1_hash(0));
|
|
|
|
n = parent;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-08-20 05:19:12 +02:00
|
|
|
#if TORRENT_USE_I2P
|
|
|
|
bool is_i2p_url(std::string const& url)
|
|
|
|
{
|
|
|
|
using boost::tuples::ignore;
|
|
|
|
std::string hostname;
|
|
|
|
error_code ec;
|
|
|
|
boost::tie(ignore, ignore, hostname, ignore, ignore)
|
|
|
|
= parse_url_components(url, ec);
|
|
|
|
char const* top_domain = strrchr(hostname.c_str(), '.');
|
|
|
|
return top_domain && strcmp(top_domain, ".i2p") == 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-02-13 20:01:02 +01:00
|
|
|
bool torrent_info::parse_torrent_file(lazy_entry const& torrent_file, error_code& ec)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-05-14 07:29:42 +02:00
|
|
|
if (torrent_file.type() != lazy_entry::dict_t)
|
2007-12-28 21:11:10 +01:00
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::torrent_is_no_dict;
|
2007-12-28 21:11:10 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
// extract the url of the tracker
|
2008-05-14 07:29:42 +02:00
|
|
|
lazy_entry const* i = torrent_file.dict_find_list("announce-list");
|
|
|
|
if (i)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-05-14 07:29:42 +02:00
|
|
|
m_urls.reserve(i->list_size());
|
|
|
|
for (int j = 0, end(i->list_size()); j < end; ++j)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-05-14 07:29:42 +02:00
|
|
|
lazy_entry const* tier = i->list_at(j);
|
2008-05-14 21:44:36 +02:00
|
|
|
if (tier->type() != lazy_entry::list_t) continue;
|
2008-05-14 07:29:42 +02:00
|
|
|
for (int k = 0, end(tier->list_size()); k < end; ++k)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-05-14 07:29:42 +02:00
|
|
|
announce_entry e(tier->list_string_value_at(k));
|
2010-02-12 18:11:37 +01:00
|
|
|
e.trim();
|
2008-05-14 07:29:42 +02:00
|
|
|
if (e.url.empty()) continue;
|
|
|
|
e.tier = j;
|
2008-11-27 21:51:59 +01:00
|
|
|
e.fail_limit = 0;
|
2008-11-29 09:38:40 +01:00
|
|
|
e.source = announce_entry::source_torrent;
|
2009-08-20 05:19:12 +02:00
|
|
|
#if TORRENT_USE_I2P
|
|
|
|
if (is_i2p_url(e.url)) m_i2p = true;
|
|
|
|
#endif
|
2003-10-23 01:00:57 +02:00
|
|
|
m_urls.push_back(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-16 02:26:35 +01:00
|
|
|
if (!m_urls.empty())
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-12-16 02:26:35 +01:00
|
|
|
// shuffle each tier
|
|
|
|
std::vector<announce_entry>::iterator start = m_urls.begin();
|
|
|
|
std::vector<announce_entry>::iterator stop;
|
|
|
|
int current_tier = m_urls.front().tier;
|
|
|
|
for (stop = m_urls.begin(); stop != m_urls.end(); ++stop)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-12-16 02:26:35 +01:00
|
|
|
if (stop->tier != current_tier)
|
|
|
|
{
|
|
|
|
std::random_shuffle(start, stop);
|
|
|
|
start = stop;
|
|
|
|
current_tier = stop->tier;
|
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
2008-12-16 02:26:35 +01:00
|
|
|
std::random_shuffle(start, stop);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
}
|
2007-12-28 21:11:10 +01:00
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
|
|
|
|
if (m_urls.empty())
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
2008-05-14 07:29:42 +02:00
|
|
|
announce_entry e(torrent_file.dict_find_string_value("announce"));
|
2008-11-27 21:51:59 +01:00
|
|
|
e.fail_limit = 0;
|
2008-11-29 09:38:40 +01:00
|
|
|
e.source = announce_entry::source_torrent;
|
2009-06-23 03:53:47 +02:00
|
|
|
e.trim();
|
2009-08-20 05:19:12 +02:00
|
|
|
#if TORRENT_USE_I2P
|
|
|
|
if (is_i2p_url(e.url)) m_i2p = true;
|
|
|
|
#endif
|
2008-05-14 07:29:42 +02:00
|
|
|
if (!e.url.empty()) m_urls.push_back(e);
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
lazy_entry const* nodes = torrent_file.dict_find_list("nodes");
|
|
|
|
if (nodes)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
2008-05-14 07:29:42 +02:00
|
|
|
for (int i = 0, end(nodes->list_size()); i < end; ++i)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
2008-05-14 07:29:42 +02:00
|
|
|
lazy_entry const* n = nodes->list_at(i);
|
|
|
|
if (n->type() != lazy_entry::list_t
|
|
|
|
|| n->list_size() < 2
|
|
|
|
|| n->list_at(0)->type() != lazy_entry::string_t
|
|
|
|
|| n->list_at(1)->type() != lazy_entry::int_t)
|
|
|
|
continue;
|
|
|
|
m_nodes.push_back(std::make_pair(
|
|
|
|
n->list_at(0)->string_value()
|
|
|
|
, int(n->list_at(1)->int_value())));
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2004-01-24 18:14:03 +01:00
|
|
|
// extract creation date
|
2008-05-14 07:29:42 +02:00
|
|
|
size_type cd = torrent_file.dict_find_int_value("creation date", -1);
|
|
|
|
if (cd >= 0)
|
2004-01-24 18:14:03 +01:00
|
|
|
{
|
2007-04-05 00:27:36 +02:00
|
|
|
m_creation_date = pt::ptime(gr::date(1970, gr::Jan, 1))
|
2008-05-14 07:29:42 +02:00
|
|
|
+ pt::seconds(long(cd));
|
2004-01-24 18:14:03 +01:00
|
|
|
}
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// if there are any url-seeds, extract them
|
2008-05-14 07:29:42 +02:00
|
|
|
lazy_entry const* url_seeds = torrent_file.dict_find("url-list");
|
|
|
|
if (url_seeds && url_seeds->type() == lazy_entry::string_t)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2009-06-19 20:18:49 +02:00
|
|
|
m_url_seeds.push_back(maybe_url_encode(url_seeds->string_value()));
|
2007-12-28 21:11:10 +01:00
|
|
|
}
|
2008-05-14 07:29:42 +02:00
|
|
|
else if (url_seeds && url_seeds->type() == lazy_entry::list_t)
|
2007-12-28 21:11:10 +01:00
|
|
|
{
|
2008-05-14 07:29:42 +02:00
|
|
|
for (int i = 0, end(url_seeds->list_size()); i < end; ++i)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2008-05-14 07:29:42 +02:00
|
|
|
lazy_entry const* url = url_seeds->list_at(i);
|
|
|
|
if (url->type() != lazy_entry::string_t) continue;
|
2009-06-19 20:18:49 +02:00
|
|
|
m_url_seeds.push_back(maybe_url_encode(url->string_value()));
|
2008-12-30 04:54:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if there are any http-seeds, extract them
|
|
|
|
lazy_entry const* http_seeds = torrent_file.dict_find("httpseeds");
|
|
|
|
if (http_seeds && http_seeds->type() == lazy_entry::string_t)
|
|
|
|
{
|
2009-06-19 20:18:49 +02:00
|
|
|
m_http_seeds.push_back(maybe_url_encode(http_seeds->string_value()));
|
2008-12-30 04:54:07 +01:00
|
|
|
}
|
|
|
|
else if (http_seeds && http_seeds->type() == lazy_entry::list_t)
|
|
|
|
{
|
|
|
|
for (int i = 0, end(http_seeds->list_size()); i < end; ++i)
|
|
|
|
{
|
|
|
|
lazy_entry const* url = http_seeds->list_at(i);
|
|
|
|
if (url->type() != lazy_entry::string_t) continue;
|
2009-06-19 20:18:49 +02:00
|
|
|
m_http_seeds.push_back(maybe_url_encode(url->string_value()));
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
m_comment = torrent_file.dict_find_string_value("comment.utf-8");
|
|
|
|
if (m_comment.empty()) m_comment = torrent_file.dict_find_string_value("comment");
|
2008-12-31 11:18:19 +01:00
|
|
|
verify_encoding(m_comment);
|
2005-08-11 04:01:03 +02:00
|
|
|
|
2008-05-15 19:42:28 +02:00
|
|
|
m_created_by = torrent_file.dict_find_string_value("created by.utf-8");
|
2008-05-15 23:48:11 +02:00
|
|
|
if (m_created_by.empty()) m_created_by = torrent_file.dict_find_string_value("created by");
|
2008-12-31 11:18:19 +01:00
|
|
|
verify_encoding(m_created_by);
|
2005-08-18 00:59:21 +02:00
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
lazy_entry const* info = torrent_file.dict_find_dict("info");
|
|
|
|
if (info == 0)
|
2007-12-28 21:11:10 +01:00
|
|
|
{
|
2009-11-29 08:06:38 +01:00
|
|
|
ec = errors::torrent_missing_info;
|
2007-12-28 21:11:10 +01:00
|
|
|
return false;
|
|
|
|
}
|
2009-02-13 20:01:02 +01:00
|
|
|
return parse_info_section(*info, ec);
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2007-04-05 00:27:36 +02:00
|
|
|
boost::optional<pt::ptime>
|
2004-03-05 13:04:47 +01:00
|
|
|
torrent_info::creation_date() const
|
2003-12-01 06:01:40 +01:00
|
|
|
{
|
2007-04-05 00:27:36 +02:00
|
|
|
if (m_creation_date != pt::ptime(gr::date(pt::not_a_date_time)))
|
2003-12-01 06:01:40 +01:00
|
|
|
{
|
2007-04-05 00:27:36 +02:00
|
|
|
return boost::optional<pt::ptime>(m_creation_date);
|
2004-03-05 13:04:47 +01:00
|
|
|
}
|
2007-04-05 00:27:36 +02:00
|
|
|
return boost::optional<pt::ptime>();
|
2004-03-05 13:04:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void torrent_info::add_tracker(std::string const& url, int tier)
|
|
|
|
{
|
2004-09-12 12:12:16 +02:00
|
|
|
announce_entry e(url);
|
2004-03-05 13:04:47 +01:00
|
|
|
e.tier = tier;
|
2008-11-29 09:38:40 +01:00
|
|
|
e.source = announce_entry::source_client;
|
2004-03-05 13:04:47 +01:00
|
|
|
m_urls.push_back(e);
|
2004-11-01 00:16:08 +01:00
|
|
|
|
|
|
|
using boost::bind;
|
2008-11-29 09:38:40 +01:00
|
|
|
std::sort(m_urls.begin(), m_urls.end(), bind(&announce_entry::tier, _1)
|
|
|
|
< bind(&announce_entry::tier, _2));
|
2004-03-05 13:04:47 +01:00
|
|
|
}
|
|
|
|
|
2009-04-04 11:52:25 +02:00
|
|
|
#if !defined TORRENT_NO_DEPRECATE && TORRENT_USE_IOSTREAM
|
2007-04-10 11:11:32 +02:00
|
|
|
// ------- start deprecation -------
|
|
|
|
|
2003-10-23 01:00:57 +02:00
|
|
|
void torrent_info::print(std::ostream& os) const
|
|
|
|
{
|
|
|
|
os << "trackers:\n";
|
|
|
|
for (std::vector<announce_entry>::const_iterator i = trackers().begin();
|
2006-08-06 18:36:00 +02:00
|
|
|
i != trackers().end(); ++i)
|
2003-10-23 01:00:57 +02:00
|
|
|
{
|
|
|
|
os << i->tier << ": " << i->url << "\n";
|
|
|
|
}
|
2003-11-20 20:58:29 +01:00
|
|
|
if (!m_comment.empty())
|
|
|
|
os << "comment: " << m_comment << "\n";
|
2007-04-10 11:11:32 +02:00
|
|
|
// if (m_creation_date != pt::ptime(gr::date(pt::not_a_date_time)))
|
|
|
|
// os << "creation date: " << to_simple_string(m_creation_date) << "\n";
|
2006-08-06 18:36:00 +02:00
|
|
|
os << "private: " << (m_private?"yes":"no") << "\n";
|
2003-10-23 01:00:57 +02:00
|
|
|
os << "number of pieces: " << num_pieces() << "\n";
|
|
|
|
os << "piece length: " << piece_length() << "\n";
|
|
|
|
os << "files:\n";
|
2008-05-28 10:44:40 +02:00
|
|
|
for (file_storage::iterator i = m_files.begin(); i != m_files.end(); ++i)
|
2009-10-26 02:29:39 +01:00
|
|
|
os << " " << std::setw(11) << i->size << " " << i->path << "\n";
|
2003-10-23 01:00:57 +02:00
|
|
|
}
|
|
|
|
|
2007-04-10 11:11:32 +02:00
|
|
|
// ------- end deprecation -------
|
2008-08-03 17:14:08 +02:00
|
|
|
#endif
|
2007-04-10 11:11:32 +02:00
|
|
|
|
2003-10-26 04:18:17 +01:00
|
|
|
}
|
2007-12-28 21:11:10 +01:00
|
|
|
|