2008-05-14 07:29:42 +02:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright (c) 2008, Arvid Norberg
|
|
|
|
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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "libtorrent/create_torrent.hpp"
|
2008-05-28 10:44:40 +02:00
|
|
|
#include "libtorrent/file_pool.hpp"
|
|
|
|
#include "libtorrent/storage.hpp"
|
2009-06-23 04:50:41 +02:00
|
|
|
#include "libtorrent/escape_string.hpp"
|
2008-05-14 07:29:42 +02:00
|
|
|
|
|
|
|
#include <boost/bind.hpp>
|
2009-10-20 18:44:11 +02:00
|
|
|
#include <boost/next_prior.hpp>
|
2008-05-14 07:29:42 +02:00
|
|
|
|
2009-01-11 23:27:43 +01:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
2009-07-01 10:35:45 +02:00
|
|
|
#define MAX_SYMLINK_PATH 200
|
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
namespace libtorrent
|
|
|
|
{
|
2009-03-14 09:19:17 +01:00
|
|
|
// defined in torrent_info.cpp
|
|
|
|
int merkle_num_leafs(int);
|
|
|
|
int merkle_num_nodes(int);
|
|
|
|
int merkle_get_parent(int);
|
|
|
|
int merkle_get_sibling(int);
|
|
|
|
|
2009-01-11 23:27:43 +01:00
|
|
|
namespace detail
|
|
|
|
{
|
2009-10-26 02:29:39 +01:00
|
|
|
int TORRENT_EXPORT get_file_attributes(std::string const& p)
|
2009-01-11 23:27:43 +01:00
|
|
|
{
|
|
|
|
#ifdef TORRENT_WINDOWS
|
|
|
|
|
2010-02-15 06:49:10 +01:00
|
|
|
#if TORRENT_USE_WSTRING
|
2009-10-26 02:29:39 +01:00
|
|
|
std::wstring path = convert_to_wstring(p);
|
2009-06-22 04:19:11 +02:00
|
|
|
DWORD attr = GetFileAttributesW(path.c_str());
|
2009-01-11 23:27:43 +01:00
|
|
|
#else
|
2009-10-26 02:29:39 +01:00
|
|
|
std::string path = convert_to_native(p);
|
2009-06-22 04:19:11 +02:00
|
|
|
DWORD attr = GetFileAttributesA(path.c_str());
|
2010-02-15 06:49:10 +01:00
|
|
|
#endif // TORRENT_USE_WSTRING
|
2009-01-11 23:27:43 +01:00
|
|
|
if (attr & FILE_ATTRIBUTE_HIDDEN) return file_storage::attribute_hidden;
|
|
|
|
return 0;
|
|
|
|
#else
|
|
|
|
struct stat s;
|
2009-10-26 02:29:39 +01:00
|
|
|
if (lstat(convert_to_native(p).c_str(), &s) < 0) return 0;
|
2009-07-01 10:35:45 +02:00
|
|
|
int file_attr = 0;
|
|
|
|
if (s.st_mode & S_IXUSR)
|
|
|
|
file_attr += file_storage::attribute_executable;
|
|
|
|
if (S_ISLNK(s.st_mode))
|
|
|
|
file_attr += file_storage::attribute_symlink;
|
|
|
|
return file_attr;
|
2009-06-23 04:50:41 +02:00
|
|
|
#endif
|
|
|
|
}
|
2009-10-26 02:29:39 +01:00
|
|
|
|
2009-07-20 04:07:32 +02:00
|
|
|
#ifndef TORRENT_WINDOWS
|
2009-10-26 02:29:39 +01:00
|
|
|
std::string get_symlink_path_impl(char const* path)
|
2009-07-01 10:35:45 +02:00
|
|
|
{
|
|
|
|
char buf[MAX_SYMLINK_PATH];
|
2009-10-26 02:29:39 +01:00
|
|
|
std::string f = convert_to_native(path);
|
|
|
|
int char_read = readlink(f.c_str(),buf,MAX_SYMLINK_PATH);
|
2009-07-01 10:35:45 +02:00
|
|
|
if (char_read < 0) return "";
|
|
|
|
if (char_read < MAX_SYMLINK_PATH) buf[char_read] = 0;
|
|
|
|
else buf[0] = 0;
|
2009-10-26 02:29:39 +01:00
|
|
|
return convert_from_native(buf);
|
2009-07-01 10:35:45 +02:00
|
|
|
}
|
2009-07-20 04:07:32 +02:00
|
|
|
#endif
|
2009-07-01 10:35:45 +02:00
|
|
|
|
2009-10-26 02:29:39 +01:00
|
|
|
std::string TORRENT_EXPORT get_symlink_path(std::string const& p)
|
2009-07-01 10:35:45 +02:00
|
|
|
{
|
2009-10-26 02:29:39 +01:00
|
|
|
#if defined TORRENT_WINDOWS
|
2009-07-20 04:07:32 +02:00
|
|
|
return "";
|
2009-07-01 10:35:45 +02:00
|
|
|
#else
|
2009-10-26 02:29:39 +01:00
|
|
|
std::string path = convert_to_native(p);
|
|
|
|
return get_symlink_path_impl(p.c_str());
|
2009-07-01 10:35:45 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2009-01-11 23:27:43 +01:00
|
|
|
}
|
|
|
|
|
2009-01-19 09:46:45 +01:00
|
|
|
create_torrent::create_torrent(file_storage& fs, int piece_size, int pad_file_limit, int flags)
|
2008-05-28 10:44:40 +02:00
|
|
|
: m_files(fs)
|
2010-08-22 00:10:16 +02:00
|
|
|
, m_creation_date(time(0))
|
2008-05-28 10:44:40 +02:00
|
|
|
, m_multifile(fs.num_files() > 1)
|
2008-05-14 07:29:42 +02:00
|
|
|
, m_private(false)
|
2010-10-16 17:24:45 +02:00
|
|
|
, m_merkle_torrent((flags & merkle) != 0)
|
|
|
|
, m_include_mtime((flags & modification_time) != 0)
|
|
|
|
, m_include_symlinks((flags & symlinks) != 0)
|
|
|
|
, m_calculate_file_hashes((flags & calculate_file_hashes) != 0)
|
2008-05-28 10:44:40 +02:00
|
|
|
{
|
|
|
|
TORRENT_ASSERT(fs.num_files() > 0);
|
2010-01-19 02:58:03 +01:00
|
|
|
|
|
|
|
// return instead of crash in release mode
|
|
|
|
if (fs.num_files() == 0) return;
|
|
|
|
|
2010-11-29 06:44:29 +01:00
|
|
|
if (!m_multifile && has_parent_path(m_files.file_path(*m_files.begin()))) m_multifile = true;
|
2008-05-14 07:29:42 +02:00
|
|
|
|
2009-01-11 11:32:57 +01:00
|
|
|
// a piece_size of 0 means automatic
|
2009-03-13 07:09:39 +01:00
|
|
|
if (piece_size == 0 && !m_merkle_torrent)
|
2009-01-11 11:32:57 +01:00
|
|
|
{
|
|
|
|
const int target_size = 40 * 1024;
|
|
|
|
piece_size = fs.total_size() / (target_size / 20);
|
|
|
|
|
2009-01-11 23:27:43 +01:00
|
|
|
int i = 16*1024;
|
|
|
|
for (; i < 2*1024*1024; i *= 2)
|
2009-01-11 11:32:57 +01:00
|
|
|
{
|
2009-01-11 23:27:43 +01:00
|
|
|
if (piece_size > i) continue;
|
2009-01-11 11:32:57 +01:00
|
|
|
break;
|
|
|
|
}
|
2009-01-11 23:27:43 +01:00
|
|
|
piece_size = i;
|
2009-01-11 11:32:57 +01:00
|
|
|
}
|
2009-03-13 07:09:39 +01:00
|
|
|
else if (piece_size == 0 && m_merkle_torrent)
|
|
|
|
{
|
2009-06-24 23:39:15 +02:00
|
|
|
piece_size = 64*1024;
|
2009-03-13 07:09:39 +01:00
|
|
|
}
|
2009-01-11 11:32:57 +01:00
|
|
|
|
2008-05-28 10:44:40 +02:00
|
|
|
// make sure the size is an even power of 2
|
|
|
|
#ifndef NDEBUG
|
|
|
|
for (int i = 0; i < 32; ++i)
|
|
|
|
{
|
2009-01-11 11:32:57 +01:00
|
|
|
if (piece_size & (1 << i))
|
2008-05-28 10:44:40 +02:00
|
|
|
{
|
2009-01-11 11:32:57 +01:00
|
|
|
TORRENT_ASSERT((piece_size & ~(1 << i)) == 0);
|
2008-05-28 10:44:40 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2009-01-11 11:32:57 +01:00
|
|
|
m_files.set_piece_length(piece_size);
|
2009-01-19 09:46:45 +01:00
|
|
|
if (flags & optimize)
|
|
|
|
m_files.optimize(pad_file_limit);
|
2008-05-28 10:44:40 +02:00
|
|
|
m_files.set_num_pieces(static_cast<int>(
|
|
|
|
(m_files.total_size() + m_files.piece_length() - 1) / m_files.piece_length()));
|
|
|
|
m_piece_hash.resize(m_files.num_pieces());
|
|
|
|
}
|
2008-09-24 19:05:12 +02:00
|
|
|
|
|
|
|
create_torrent::create_torrent(torrent_info const& ti)
|
|
|
|
: m_files(const_cast<file_storage&>(ti.files()))
|
2010-08-22 00:10:16 +02:00
|
|
|
, m_creation_date(time(0))
|
2008-09-24 19:05:12 +02:00
|
|
|
, m_multifile(ti.num_files() > 1)
|
|
|
|
, m_private(ti.priv())
|
2009-03-13 07:09:39 +01:00
|
|
|
, m_merkle_torrent(ti.is_merkle_torrent())
|
2010-03-20 08:30:34 +01:00
|
|
|
, m_include_mtime(false)
|
|
|
|
, m_include_symlinks(false)
|
2010-04-01 02:44:29 +02:00
|
|
|
, m_calculate_file_hashes(false)
|
2008-09-24 19:05:12 +02:00
|
|
|
{
|
|
|
|
TORRENT_ASSERT(ti.is_valid());
|
|
|
|
if (ti.creation_date()) m_creation_date = *ti.creation_date();
|
|
|
|
|
|
|
|
if (!ti.creator().empty()) set_creator(ti.creator().c_str());
|
|
|
|
if (!ti.comment().empty()) set_comment(ti.comment().c_str());
|
|
|
|
|
|
|
|
torrent_info::nodes_t const& nodes = ti.nodes();
|
|
|
|
for (torrent_info::nodes_t::const_iterator i = nodes.begin()
|
|
|
|
, end(nodes.end()); i != end; ++i)
|
|
|
|
add_node(*i);
|
|
|
|
|
|
|
|
std::vector<libtorrent::announce_entry> const& trackers = ti.trackers();
|
|
|
|
for (std::vector<libtorrent::announce_entry>::const_iterator i = trackers.begin()
|
|
|
|
, end(trackers.end()); i != end; ++i)
|
|
|
|
add_tracker(i->url, i->tier);
|
|
|
|
|
2010-10-10 23:06:35 +02:00
|
|
|
std::vector<web_seed_entry> const& web_seeds = ti.web_seeds();
|
|
|
|
for (std::vector<web_seed_entry>::const_iterator i = web_seeds.begin()
|
2008-09-24 19:05:12 +02:00
|
|
|
, end(web_seeds.end()); i != end; ++i)
|
2010-10-10 23:06:35 +02:00
|
|
|
{
|
|
|
|
if (i->type == web_seed_entry::url_seed)
|
|
|
|
add_url_seed(i->url);
|
|
|
|
else if (i->type == web_seed_entry::http_seed)
|
|
|
|
add_http_seed(i->url);
|
|
|
|
}
|
2008-09-24 19:05:12 +02:00
|
|
|
|
|
|
|
m_piece_hash.resize(m_files.num_pieces());
|
|
|
|
for (int i = 0; i < num_pieces(); ++i) set_hash(i, ti.hash_for_piece(i));
|
|
|
|
|
|
|
|
m_info_dict = bdecode(&ti.metadata()[0], &ti.metadata()[0] + ti.metadata_size());
|
|
|
|
m_info_hash = ti.info_hash();
|
|
|
|
}
|
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
entry create_torrent::generate() const
|
|
|
|
{
|
2008-05-28 10:44:40 +02:00
|
|
|
TORRENT_ASSERT(m_files.piece_length() > 0);
|
2008-05-14 07:29:42 +02:00
|
|
|
|
|
|
|
entry dict;
|
|
|
|
|
2009-02-23 02:21:19 +01:00
|
|
|
if (m_files.num_files() == 0)
|
|
|
|
return dict;
|
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
if (!m_urls.empty()) dict["announce"] = m_urls.front().first;
|
|
|
|
|
|
|
|
if (!m_nodes.empty())
|
|
|
|
{
|
|
|
|
entry& nodes = dict["nodes"];
|
|
|
|
entry::list_type& nodes_list = nodes.list();
|
|
|
|
for (nodes_t::const_iterator i = m_nodes.begin()
|
|
|
|
, end(m_nodes.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
entry::list_type node;
|
|
|
|
node.push_back(entry(i->first));
|
|
|
|
node.push_back(entry(i->second));
|
|
|
|
nodes_list.push_back(entry(node));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_urls.size() > 1)
|
|
|
|
{
|
|
|
|
entry trackers(entry::list_t);
|
|
|
|
entry tier(entry::list_t);
|
|
|
|
int current_tier = m_urls.front().second;
|
|
|
|
for (std::vector<announce_entry>::const_iterator i = m_urls.begin();
|
|
|
|
i != m_urls.end(); ++i)
|
|
|
|
{
|
|
|
|
if (i->second != current_tier)
|
|
|
|
{
|
|
|
|
current_tier = i->second;
|
|
|
|
trackers.list().push_back(tier);
|
|
|
|
tier.list().clear();
|
|
|
|
}
|
|
|
|
tier.list().push_back(entry(i->first));
|
|
|
|
}
|
|
|
|
trackers.list().push_back(tier);
|
|
|
|
dict["announce-list"] = trackers;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_comment.empty())
|
|
|
|
dict["comment"] = m_comment;
|
|
|
|
|
2010-08-22 00:10:16 +02:00
|
|
|
dict["creation date"] = m_creation_date;
|
2008-05-14 07:29:42 +02:00
|
|
|
|
|
|
|
if (!m_created_by.empty())
|
|
|
|
dict["created by"] = m_created_by;
|
|
|
|
|
|
|
|
if (!m_url_seeds.empty())
|
|
|
|
{
|
|
|
|
if (m_url_seeds.size() == 1)
|
|
|
|
{
|
|
|
|
dict["url-list"] = m_url_seeds.front();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entry& list = dict["url-list"];
|
|
|
|
for (std::vector<std::string>::const_iterator i
|
|
|
|
= m_url_seeds.begin(); i != m_url_seeds.end(); ++i)
|
|
|
|
{
|
|
|
|
list.list().push_back(entry(*i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-10 23:06:35 +02:00
|
|
|
if (!m_http_seeds.empty())
|
|
|
|
{
|
|
|
|
if (m_http_seeds.size() == 1)
|
|
|
|
{
|
|
|
|
dict["httpseeds"] = m_http_seeds.front();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entry& list = dict["httpseeds"];
|
|
|
|
for (std::vector<std::string>::const_iterator i
|
|
|
|
= m_http_seeds.begin(); i != m_http_seeds.end(); ++i)
|
|
|
|
{
|
|
|
|
list.list().push_back(entry(*i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
entry& info = dict["info"];
|
2008-09-24 19:05:12 +02:00
|
|
|
if (m_info_dict.type() == entry::dictionary_t)
|
|
|
|
{
|
|
|
|
info = m_info_dict;
|
|
|
|
return dict;
|
|
|
|
}
|
|
|
|
|
2008-05-28 10:44:40 +02:00
|
|
|
info["name"] = m_files.name();
|
2008-05-14 07:29:42 +02:00
|
|
|
|
|
|
|
if (m_private) info["private"] = 1;
|
|
|
|
|
|
|
|
if (!m_multifile)
|
|
|
|
{
|
2010-11-29 06:44:29 +01:00
|
|
|
file_entry e = m_files.at(0);
|
|
|
|
if (m_include_mtime) info["mtime"] = e.mtime;
|
|
|
|
info["length"] = e.size;
|
|
|
|
if (e.pad_file
|
|
|
|
|| e.hidden_attribute
|
|
|
|
|| e.executable_attribute
|
|
|
|
|| e.symlink_attribute)
|
2009-06-23 04:50:41 +02:00
|
|
|
{
|
|
|
|
std::string& attr = info["attr"].string();
|
2010-11-29 06:44:29 +01:00
|
|
|
if (e.pad_file) attr += 'p';
|
|
|
|
if (e.hidden_attribute) attr += 'h';
|
|
|
|
if (e.executable_attribute) attr += 'x';
|
|
|
|
if (m_include_symlinks && e.symlink_attribute) attr += 'l';
|
2009-07-01 10:35:45 +02:00
|
|
|
}
|
2010-11-15 06:10:36 +01:00
|
|
|
if (m_include_symlinks
|
2010-11-29 06:44:29 +01:00
|
|
|
&& e.symlink_attribute)
|
2009-07-01 10:35:45 +02:00
|
|
|
{
|
|
|
|
entry& sympath_e = info["symlink path"];
|
|
|
|
|
2010-11-29 06:44:29 +01:00
|
|
|
std::string split = split_path(e.symlink_path);
|
2009-10-26 02:29:39 +01:00
|
|
|
for (char const* e = split.c_str(); e != 0; e = next_path_element(e))
|
|
|
|
sympath_e.list().push_back(entry(e));
|
2009-06-23 04:50:41 +02:00
|
|
|
}
|
2010-03-27 16:51:30 +01:00
|
|
|
if (!m_filehashes.empty())
|
|
|
|
{
|
|
|
|
info["sha1"] = m_filehashes[0].to_string();
|
|
|
|
}
|
2008-05-14 07:29:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!info.find_key("files"))
|
|
|
|
{
|
|
|
|
entry& files = info["files"];
|
|
|
|
|
2008-05-28 10:44:40 +02:00
|
|
|
for (file_storage::iterator i = m_files.begin();
|
2008-05-14 07:29:42 +02:00
|
|
|
i != m_files.end(); ++i)
|
|
|
|
{
|
|
|
|
files.list().push_back(entry());
|
|
|
|
entry& file_e = files.list().back();
|
2010-11-25 00:49:22 +01:00
|
|
|
if (m_include_mtime && m_files.mtime(*i)) file_e["mtime"] = m_files.mtime(*i);
|
2008-05-28 10:44:40 +02:00
|
|
|
file_e["length"] = i->size;
|
2008-05-14 07:29:42 +02:00
|
|
|
entry& path_e = file_e["path"];
|
|
|
|
|
2010-11-25 00:49:22 +01:00
|
|
|
TORRENT_ASSERT(has_parent_path(m_files.file_path(*i)));
|
2008-05-14 07:29:42 +02:00
|
|
|
|
2010-11-25 00:49:22 +01:00
|
|
|
std::string split = split_path(m_files.file_path(*i));
|
2009-10-26 02:29:39 +01:00
|
|
|
TORRENT_ASSERT(split.c_str() == m_files.name());
|
|
|
|
|
|
|
|
for (char const* e = next_path_element(split.c_str());
|
|
|
|
e != 0; e = next_path_element(e))
|
|
|
|
path_e.list().push_back(entry(e));
|
|
|
|
|
|
|
|
if (i->pad_file
|
|
|
|
|| i->hidden_attribute
|
|
|
|
|| i->executable_attribute
|
|
|
|
|| i->symlink_attribute)
|
2009-01-11 23:27:43 +01:00
|
|
|
{
|
|
|
|
std::string& attr = file_e["attr"].string();
|
|
|
|
if (i->pad_file) attr += 'p';
|
|
|
|
if (i->hidden_attribute) attr += 'h';
|
|
|
|
if (i->executable_attribute) attr += 'x';
|
2010-03-20 08:30:34 +01:00
|
|
|
if (m_include_symlinks && i->symlink_attribute) attr += 'l';
|
2009-07-01 10:35:45 +02:00
|
|
|
}
|
2010-11-15 06:10:36 +01:00
|
|
|
if (m_include_symlinks
|
|
|
|
&& i->symlink_attribute
|
|
|
|
&& i->symlink_index != -1)
|
2009-07-01 10:35:45 +02:00
|
|
|
{
|
|
|
|
entry& sympath_e = file_e["symlink path"];
|
|
|
|
|
2010-11-25 00:49:22 +01:00
|
|
|
std::string split = split_path(m_files.symlink(*i));
|
2009-10-26 02:29:39 +01:00
|
|
|
for (char const* e = split.c_str(); e != 0; e = next_path_element(e))
|
|
|
|
sympath_e.list().push_back(entry(e));
|
2009-01-11 23:27:43 +01:00
|
|
|
}
|
2010-03-27 16:51:30 +01:00
|
|
|
int file_index = i - m_files.begin();
|
|
|
|
if (!m_filehashes.empty() && m_filehashes[file_index] != sha1_hash())
|
|
|
|
{
|
|
|
|
file_e["sha1"] = m_filehashes[file_index].to_string();
|
|
|
|
}
|
2008-05-14 07:29:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-28 10:44:40 +02:00
|
|
|
info["piece length"] = m_files.piece_length();
|
2009-03-13 07:09:39 +01:00
|
|
|
if (m_merkle_torrent)
|
2008-05-14 07:29:42 +02:00
|
|
|
{
|
2009-03-13 07:09:39 +01:00
|
|
|
std::vector<sha1_hash> merkle_tree;
|
|
|
|
|
|
|
|
int num_leafs = merkle_num_leafs(m_files.num_pieces());
|
|
|
|
int num_nodes = merkle_num_nodes(num_leafs);
|
|
|
|
int first_leaf = num_nodes - num_leafs;
|
|
|
|
merkle_tree.resize(num_nodes);
|
|
|
|
int num_pieces = m_piece_hash.size();
|
|
|
|
for (int i = 0; i < num_pieces; ++i)
|
|
|
|
merkle_tree[first_leaf + i] = m_piece_hash[i];
|
|
|
|
sha1_hash filler(0);
|
|
|
|
for (int i = num_pieces; i < num_leafs; ++i)
|
|
|
|
merkle_tree[first_leaf + i] = filler;
|
|
|
|
|
|
|
|
// now that we have initialized all leaves, build
|
|
|
|
// each level bottom-up
|
|
|
|
int level_start = first_leaf;
|
|
|
|
int level_size = num_leafs;
|
|
|
|
while (level_start > 0)
|
|
|
|
{
|
|
|
|
int parent = merkle_get_parent(level_start);
|
|
|
|
for (int i = level_start; i < level_start + level_size; i += 2, ++parent)
|
|
|
|
{
|
|
|
|
hasher h;
|
|
|
|
h.update((char const*)&merkle_tree[i][0], 20);
|
|
|
|
h.update((char const*)&merkle_tree[i+1][0], 20);
|
|
|
|
merkle_tree[parent] = h.final();
|
|
|
|
}
|
|
|
|
level_start = merkle_get_parent(level_start);
|
|
|
|
level_size /= 2;
|
|
|
|
}
|
|
|
|
TORRENT_ASSERT(level_size == 1);
|
|
|
|
std::string& p = info["root hash"].string();
|
|
|
|
p.assign((char const*)&merkle_tree[0][0], 20);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::string& p = info["pieces"].string();
|
|
|
|
|
|
|
|
for (std::vector<sha1_hash>::const_iterator i = m_piece_hash.begin();
|
|
|
|
i != m_piece_hash.end(); ++i)
|
|
|
|
{
|
2009-10-20 18:44:11 +02:00
|
|
|
p.append((char*)i->begin(), sha1_hash::size);
|
2009-03-13 07:09:39 +01:00
|
|
|
}
|
2008-05-14 07:29:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<char> buf;
|
|
|
|
bencode(std::back_inserter(buf), info);
|
|
|
|
m_info_hash = hasher(&buf[0], buf.size()).final();
|
|
|
|
|
|
|
|
return dict;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void create_torrent::add_tracker(std::string const& url, int tier)
|
|
|
|
{
|
|
|
|
m_urls.push_back(announce_entry(url, tier));
|
|
|
|
|
|
|
|
std::sort(m_urls.begin(), m_urls.end()
|
2009-11-23 00:55:54 +01:00
|
|
|
, boost::bind(&announce_entry::second, _1) < boost::bind(&announce_entry::second, _2));
|
2008-05-14 07:29:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void create_torrent::set_hash(int index, sha1_hash const& h)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(index >= 0);
|
|
|
|
TORRENT_ASSERT(index < (int)m_piece_hash.size());
|
|
|
|
m_piece_hash[index] = h;
|
|
|
|
}
|
|
|
|
|
2010-03-27 16:51:30 +01:00
|
|
|
void create_torrent::set_file_hash(int index, sha1_hash const& h)
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(index >= 0);
|
|
|
|
TORRENT_ASSERT(index < (int)m_files.num_files());
|
|
|
|
if (m_filehashes.empty()) m_filehashes.resize(m_files.num_files());
|
|
|
|
m_filehashes[index] = h;
|
|
|
|
}
|
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
void create_torrent::add_node(std::pair<std::string, int> const& node)
|
|
|
|
{
|
|
|
|
m_nodes.push_back(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void create_torrent::add_url_seed(std::string const& url)
|
|
|
|
{
|
|
|
|
m_url_seeds.push_back(url);
|
|
|
|
}
|
|
|
|
|
2010-10-10 23:06:35 +02:00
|
|
|
void create_torrent::add_http_seed(std::string const& url)
|
|
|
|
{
|
|
|
|
m_http_seeds.push_back(url);
|
|
|
|
}
|
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
void create_torrent::set_comment(char const* str)
|
|
|
|
{
|
|
|
|
m_comment = str;
|
|
|
|
}
|
|
|
|
|
|
|
|
void create_torrent::set_creator(char const* str)
|
|
|
|
{
|
|
|
|
m_created_by = str;
|
|
|
|
}
|
2008-05-28 10:44:40 +02:00
|
|
|
|
2008-05-14 07:29:42 +02:00
|
|
|
}
|
|
|
|
|