mirror of
https://github.com/arvidn/libtorrent.git
synced 2026-07-29 07:14:08 -04:00
191 lines
4.5 KiB
C++
191 lines
4.5 KiB
C++
/*
|
|
|
|
Copyright (c) 2016, Alden Torres
|
|
Copyright (c) 2016, Andrei Kurushin
|
|
Copyright (c) 2016-2020, 2022, Arvid Norberg
|
|
All rights reserved.
|
|
|
|
You may use, distribute and modify this code under the terms of the BSD license,
|
|
see LICENSE file.
|
|
*/
|
|
|
|
#include <deque>
|
|
|
|
#include "make_torrent.hpp"
|
|
#include "libtorrent/hasher.hpp"
|
|
#include "libtorrent/entry.hpp"
|
|
#include "libtorrent/bencode.hpp"
|
|
#include "libtorrent/load_torrent.hpp"
|
|
#include "libtorrent/aux_/session_settings.hpp"
|
|
#include "libtorrent/aux_/posix_storage.hpp"
|
|
|
|
using namespace lt;
|
|
|
|
lt::add_torrent_params make_test_torrent(torrent_args const& args)
|
|
{
|
|
entry e;
|
|
|
|
entry::dictionary_type& info = e["info"].dict();
|
|
int total_size = 0;
|
|
|
|
if (args.m_priv)
|
|
{
|
|
info["priv"] = 1;
|
|
}
|
|
|
|
// torrent offset ranges where the pad files are
|
|
// used when generating hashes
|
|
std::deque<std::pair<int,int>> pad_files;
|
|
|
|
int const piece_length = 32768;
|
|
info["piece length"] = piece_length;
|
|
|
|
if (args.m_files.size() == 1)
|
|
{
|
|
std::string const& ent = args.m_files[0];
|
|
std::string name = "test_file-1";
|
|
if (ent.find("name=") != std::string::npos)
|
|
{
|
|
std::string::size_type pos = ent.find("name=") + 5;
|
|
name = ent.substr(pos, ent.find(',', pos));
|
|
}
|
|
info["name"] = name;
|
|
int file_size = atoi(args.m_files[0].c_str());
|
|
info["length"] = file_size;
|
|
total_size = file_size;
|
|
}
|
|
else
|
|
{
|
|
info["name"] = args.m_name;
|
|
|
|
entry::list_type& files = info["files"].list();
|
|
for (int i = 0; i < int(args.m_files.size()); ++i)
|
|
{
|
|
auto const idx = static_cast<std::size_t>(i);
|
|
int file_size = atoi(args.m_files[idx].c_str());
|
|
|
|
files.push_back(entry());
|
|
entry::dictionary_type& file_entry = files.back().dict();
|
|
std::string const& ent = args.m_files[idx];
|
|
if (ent.find("padfile") != std::string::npos)
|
|
{
|
|
file_entry["attr"].string() += "p";
|
|
pad_files.push_back(std::make_pair(total_size, total_size + file_size));
|
|
}
|
|
if (ent.find("executable") != std::string::npos)
|
|
file_entry["attr"].string() += "x";
|
|
|
|
char filename[100];
|
|
std::snprintf(filename, sizeof(filename), "test_file-%d", i);
|
|
|
|
std::string name = filename;
|
|
if (ent.find("name=") != std::string::npos)
|
|
{
|
|
std::string::size_type pos = ent.find("name=") + 5;
|
|
name = ent.substr(pos, ent.find(',', pos));
|
|
}
|
|
file_entry["path"].list().push_back(name);
|
|
file_entry["length"] = file_size;
|
|
total_size += file_size;
|
|
}
|
|
}
|
|
|
|
if (!args.m_url_seed.empty())
|
|
{
|
|
e["url-list"] = args.m_url_seed;
|
|
}
|
|
|
|
if (!args.m_http_seed.empty())
|
|
{
|
|
e["httpseeds"] = args.m_http_seed;
|
|
}
|
|
|
|
if (!args.m_collection.empty())
|
|
{
|
|
auto& l = info["collections"].list();
|
|
l.push_back(args.m_collection);
|
|
}
|
|
|
|
std::string piece_hashes;
|
|
|
|
int num_pieces = (total_size + piece_length - 1) / piece_length;
|
|
int torrent_offset = 0;
|
|
for (int i = 0; i < num_pieces; ++i)
|
|
{
|
|
hasher h;
|
|
int const piece_size = (i < num_pieces - 1)
|
|
? piece_length
|
|
: total_size - (num_pieces - 1) * piece_length;
|
|
|
|
char const data = char(i & 0xff);
|
|
char const zero = 0;
|
|
for (int o = 0; o < piece_size; ++o, ++torrent_offset)
|
|
{
|
|
while (!pad_files.empty() && torrent_offset >= pad_files.front().second)
|
|
pad_files.pop_front();
|
|
|
|
if (!pad_files.empty() && torrent_offset >= pad_files.front().first)
|
|
{
|
|
h.update(zero);
|
|
}
|
|
else
|
|
{
|
|
h.update(data);
|
|
}
|
|
}
|
|
piece_hashes += h.final().to_string();
|
|
}
|
|
|
|
info["pieces"] = piece_hashes;
|
|
|
|
std::vector<char> const tmp = bencode(e);
|
|
|
|
return lt::load_torrent_buffer(tmp);
|
|
}
|
|
|
|
void generate_files(lt::torrent_info const& ti, std::string const& path
|
|
, bool alternate_data)
|
|
{
|
|
aux::vector<download_priority_t, file_index_t> priorities;
|
|
renamed_files rf;
|
|
storage_params params{
|
|
ti.layout(),
|
|
rf,
|
|
path,
|
|
{},
|
|
storage_mode_t::storage_mode_sparse,
|
|
priorities,
|
|
sha1_hash{},
|
|
true, // v1-hashes
|
|
true // v2-hashes
|
|
};
|
|
|
|
// default settings
|
|
aux::session_settings sett;
|
|
aux::posix_storage st(params);
|
|
|
|
file_storage const& fs = ti.layout();
|
|
std::vector<char> buffer;
|
|
for (auto const i : fs.piece_range())
|
|
{
|
|
int const piece_size = ti.piece_size(i);
|
|
buffer.resize(static_cast<std::size_t>(ti.piece_length()));
|
|
|
|
char const data = static_cast<char>((alternate_data
|
|
? 255 - static_cast<int>(i) : static_cast<int>(i)) & 0xff);
|
|
for (int o = 0; o < piece_size; ++o)
|
|
{
|
|
buffer[static_cast<std::size_t>(o)] = data;
|
|
}
|
|
|
|
span<char> const b = { &buffer[0], piece_size };
|
|
storage_error ec;
|
|
int ret = st.write(sett, b, i, 0, ec);
|
|
if (ret != piece_size || ec)
|
|
{
|
|
std::printf("ERROR writing files: (%d expected %d) %s\n"
|
|
, ret, piece_size, ec.ec.message().c_str());
|
|
}
|
|
}
|
|
}
|