merge RC_1_1 into master

This commit is contained in:
arvidn 2017-08-10 16:44:57 +02:00
commit 865ff09a84
11 changed files with 138 additions and 74 deletions

View File

@ -76,6 +76,9 @@
* resume data no longer has timestamps of files * resume data no longer has timestamps of files
* require C++11 to build libtorrent * require C++11 to build libtorrent
* fix issue with very long tracker- and web seed URLs
* don't attempt to create empty files on startup, if they already exist
* fix force-recheck issue (new files would not be picked up)
* fix inconsistency in file_priorities and override_resume_data behavior * fix inconsistency in file_priorities and override_resume_data behavior
1.1.4 release 1.1.4 release

View File

@ -1024,7 +1024,7 @@ namespace libtorrent {
// renames the file with the given index to the new name // renames the file with the given index to the new name
// the name may include a directory path // the name may include a directory path
// returns false on failure // posts alert to indicate success or failure
void rename_file(file_index_t index, std::string name); void rename_file(file_index_t index, std::string name);
// unless this returns true, new connections must wait // unless this returns true, new connections must wait

View File

@ -163,13 +163,7 @@ void http_connection::get(std::string const& url, time_duration timeout, int pri
bool ssl = false; bool ssl = false;
if (protocol == "https") ssl = true; if (protocol == "https") ssl = true;
char request[4096]; std::stringstream request;
char* end = request + sizeof(request);
char* ptr = request;
#define APPEND_FMT(fmt) ptr += std::snprintf(ptr, std::size_t(end - ptr), fmt)
#define APPEND_FMT1(fmt, arg) ptr += std::snprintf(ptr, std::size_t(end - ptr), fmt, arg)
#define APPEND_FMT2(fmt, arg1, arg2) ptr += std::snprintf(ptr, std::size_t(end - ptr), fmt, arg1, arg2)
// exclude ssl here, because SSL assumes CONNECT support in the // exclude ssl here, because SSL assumes CONNECT support in the
// proxy and is handled at the lower layer // proxy and is handled at the lower layer
@ -179,40 +173,39 @@ void http_connection::get(std::string const& url, time_duration timeout, int pri
{ {
// if we're using an http proxy and not an ssl // if we're using an http proxy and not an ssl
// connection, just do a regular http proxy request // connection, just do a regular http proxy request
APPEND_FMT1("GET %s HTTP/1.1\r\n", url.c_str()); request << "GET " << url << " HTTP/1.1\r\n";
if (ps->type == settings_pack::http_pw) if (ps->type == settings_pack::http_pw)
APPEND_FMT1("Proxy-Authorization: Basic %s\r\n", base64encode( request << "Proxy-Authorization: Basic " << base64encode(
ps->username + ":" + ps->password).c_str()); ps->username + ":" + ps->password) << "\r\n";
hostname = ps->hostname; hostname = ps->hostname;
port = ps->port; port = ps->port;
APPEND_FMT1("Host: %s", hostname.c_str()); request << "Host: " << hostname;
if (port != default_port) APPEND_FMT1(":%d\r\n", port); if (port != default_port) request << ":" << port << "\r\n";
else APPEND_FMT("\r\n"); else request << "\r\n";
} }
else else
{ {
APPEND_FMT2("GET %s HTTP/1.1\r\n" request << "GET " << path << " HTTP/1.1\r\nHost: " << hostname;
"Host: %s", path.c_str(), hostname.c_str()); if (port != default_port) request << ":" << port << "\r\n";
if (port != default_port) APPEND_FMT1(":%d\r\n", port); else request << "\r\n";
else APPEND_FMT("\r\n");
} }
// APPEND_FMT("Accept: */*\r\n"); // request << "Accept: */*\r\n";
if (!m_user_agent.empty()) if (!m_user_agent.empty())
APPEND_FMT1("User-Agent: %s\r\n", m_user_agent.c_str()); request << "User-Agent: " << m_user_agent << "\r\n";
if (m_bottled) if (m_bottled)
APPEND_FMT("Accept-Encoding: gzip\r\n"); request << "Accept-Encoding: gzip\r\n";
if (!auth.empty()) if (!auth.empty())
APPEND_FMT1("Authorization: Basic %s\r\n", base64encode(auth).c_str()); request << "Authorization: Basic " << base64encode(auth) << "\r\n";
APPEND_FMT("Connection: close\r\n\r\n"); request << "Connection: close\r\n\r\n";
m_sendbuffer.assign(request); m_sendbuffer.assign(request.str());
m_url = url; m_url = url;
start(hostname, port, timeout, prio start(hostname, port, timeout, prio
, ps, ssl, handle_redirects, bind_addr, m_resolve_flags , ps, ssl, handle_redirects, bind_addr, m_resolve_flags

View File

@ -242,7 +242,7 @@ namespace libtorrent {
// it's supposed to be, truncate it // it's supposed to be, truncate it
// if the file is empty, just create it either way. // if the file is empty, just create it either way.
if ((!err && size > files().file_size(file_index)) if ((!err && size > files().file_size(file_index))
|| files().file_size(file_index) == 0) || (files().file_size(file_index) == 0 && err == boost::system::errc::no_such_file_or_directory))
{ {
std::string file_path = files().file_path(file_index, m_save_path); std::string file_path = files().file_path(file_index, m_save_path);
std::string dir = parent_path(file_path); std::string dir = parent_path(file_path);

View File

@ -2227,6 +2227,10 @@ namespace libtorrent {
TORRENT_ASSERT(m_outstanding_check_files == false); TORRENT_ASSERT(m_outstanding_check_files == false);
m_add_torrent_params.reset(); m_add_torrent_params.reset();
// this will clear the stat cache, to make us actually query the
// filesystem for files again
m_ses.disk_thread().async_release_files(m_storage, []{});
aux::vector<std::string, file_index_t> links; aux::vector<std::string, file_index_t> links;
m_ses.disk_thread().async_check_files(m_storage, nullptr m_ses.disk_thread().async_check_files(m_storage, nullptr
, links, std::bind(&torrent::on_force_recheck , links, std::bind(&torrent::on_force_recheck
@ -2657,6 +2661,7 @@ namespace libtorrent {
void torrent::announce_with_tracker(std::uint8_t e) void torrent::announce_with_tracker(std::uint8_t e)
{ {
TORRENT_ASSERT(is_single_thread()); TORRENT_ASSERT(is_single_thread());
TORRENT_ASSERT(e == tracker_request::stopped || state() != torrent_status::checking_files);
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_trackers.empty()) if (m_trackers.empty())
@ -8831,6 +8836,7 @@ namespace libtorrent {
void torrent::start_announcing() void torrent::start_announcing()
{ {
TORRENT_ASSERT(is_single_thread()); TORRENT_ASSERT(is_single_thread());
TORRENT_ASSERT(state() != torrent_status::checking_files);
if (is_paused()) if (is_paused())
{ {
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING

View File

@ -640,7 +640,8 @@ std::shared_ptr<lt::torrent_info> make_torrent(const int file_sizes[]
return std::make_shared<torrent_info>(buf, from_span); return std::make_shared<torrent_info>(buf, from_span);
} }
void create_random_files(std::string const& path, const int file_sizes[], int num_files) void create_random_files(std::string const& path, const int file_sizes[], int num_files
, file_storage* fs)
{ {
error_code ec; error_code ec;
aux::vector<char> random_data(300000); aux::vector<char> random_data(300000);
@ -657,6 +658,7 @@ void create_random_files(std::string const& path, const int file_sizes[], int nu
full_path = combine_path(full_path, filename); full_path = combine_path(full_path, filename);
int to_write = file_sizes[i]; int to_write = file_sizes[i];
if (fs) fs->add_file(full_path, to_write);
file f(full_path, open_mode::write_only, ec); file f(full_path, open_mode::write_only, ec);
if (ec) std::printf("failed to create file \"%s\": (%d) %s\n" if (ec) std::printf("failed to create file \"%s\": (%d) %s\n"
, full_path.c_str(), ec.value(), ec.message().c_str()); , full_path.c_str(), ec.value(), ec.message().c_str());

View File

@ -37,9 +37,14 @@ POSSIBILITY OF SUCH DAMAGE.
#include "test.hpp" #include "test.hpp"
#include "libtorrent/session.hpp" #include "libtorrent/session.hpp"
#include "libtorrent/units.hpp" #include "libtorrent/units.hpp"
#include "libtorrent/span.hpp"
#include "libtorrent/alert.hpp" namespace libtorrent
#include "libtorrent/add_torrent_params.hpp" {
class alert;
struct add_torrent_params;
class file_storage;
class session;
}
EXPORT int print_failures(); EXPORT int print_failures();
EXPORT unsigned char random_byte(); EXPORT unsigned char random_byte();
@ -89,7 +94,7 @@ EXPORT lt::file_storage make_file_storage(const int file_sizes[], int num_files
EXPORT std::shared_ptr<lt::torrent_info> make_torrent(const int file_sizes[] EXPORT std::shared_ptr<lt::torrent_info> make_torrent(const int file_sizes[]
, int num_files, int piece_size); , int num_files, int piece_size);
EXPORT void create_random_files(std::string const& path, const int file_sizes[] EXPORT void create_random_files(std::string const& path, const int file_sizes[]
, int num_files); , int num_files, libtorrent::file_storage* fs = nullptr);
EXPORT std::shared_ptr<lt::torrent_info> create_torrent(std::ostream* file = 0 EXPORT std::shared_ptr<lt::torrent_info> create_torrent(std::ostream* file = 0
, char const* name = "temporary", int piece_size = 16 * 1024, int num_pieces = 13 , char const* name = "temporary", int piece_size = 16 * 1024, int num_pieces = 13

View File

@ -30,18 +30,20 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <sys/stat.h> // for chmod
#include "libtorrent/session.hpp" #include "libtorrent/session.hpp"
#include "test.hpp" #include "test.hpp"
#include "setup_transfer.hpp" #include "setup_transfer.hpp"
#include "libtorrent/create_torrent.hpp" #include "libtorrent/create_torrent.hpp"
#include <sys/stat.h> // for chmod #include "libtorrent/alert_types.hpp"
#include "libtorrent/torrent_info.hpp" #include "libtorrent/torrent_info.hpp"
#include "libtorrent/torrent_status.hpp" #include "libtorrent/torrent_status.hpp"
#include "libtorrent/hex.hpp" // to_hex #include "libtorrent/hex.hpp" // to_hex
#include "libtorrent/aux_/path.hpp" #include "libtorrent/aux_/path.hpp"
static const int file_sizes[] = static const int file_sizes[] =
{ 5, 16 - 5, 16000, 17, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1 { 0, 5, 16 - 5, 16000, 17, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1
,1,1,1,1,1,1,13,65000,34,75,2,30,400,500,23000,900,43000,400,4300,6, 4}; ,1,1,1,1,1,1,13,65000,34,75,2,30,400,500,23000,900,43000,400,4300,6, 4};
const int num_files = sizeof(file_sizes)/sizeof(file_sizes[0]); const int num_files = sizeof(file_sizes)/sizeof(file_sizes[0]);
@ -56,59 +58,39 @@ enum
corrupt_files = 2, corrupt_files = 2,
incomplete_files = 4, incomplete_files = 4,
// make the files not be there when starting up, move the files in place and
// force-recheck. Make sure the stat cache is cleared and let us pick up the
// new files
force_recheck = 8,
}; };
void test_checking(int flags = read_only_files) void test_checking(int flags = read_only_files)
{ {
using namespace lt; using namespace lt;
std::printf("\n==== TEST CHECKING %s%s%s=====\n\n" std::printf("\n==== TEST CHECKING %s%s%s%s=====\n\n"
, (flags & read_only_files) ? "read-only-files ":"" , (flags & read_only_files) ? "read-only-files ":""
, (flags & corrupt_files) ? "corrupt ":"" , (flags & corrupt_files) ? "corrupt ":""
, (flags & incomplete_files) ? "incomplete ":""); , (flags & incomplete_files) ? "incomplete ":""
, (flags & force_recheck) ? "force_recheck ":"");
// make the files writable again
for (int i = 0; i < num_files; ++i)
{
char name[1024];
std::snprintf(name, sizeof(name), "test%d", i);
char dirname[200];
std::snprintf(dirname, sizeof(dirname), "test_dir%d", i / 5);
std::string path = combine_path(combine_path("tmp1_checking", "test_torrent_dir"), dirname);
path = combine_path(path, name);
#ifdef TORRENT_WINDOWS
SetFileAttributesA(path.c_str(), FILE_ATTRIBUTE_NORMAL);
#else
chmod(path.c_str(), S_IRUSR | S_IWUSR);
#endif
}
// in case the previous run was terminated
error_code ec; error_code ec;
remove_all("tmp1_checking", ec); create_directory("test_torrent_dir", ec);
if (ec) std::printf("ERROR: removing tmp1_checking: (%d) %s\n" if (ec) fprintf(stdout, "ERROR: creating directory test_torrent_dir: (%d) %s\n"
, ec.value(), ec.message().c_str());
create_directory("tmp1_checking", ec);
if (ec) std::printf("ERROR: creating directory tmp1_checking: (%d) %s\n"
, ec.value(), ec.message().c_str());
create_directory(combine_path("tmp1_checking", "test_torrent_dir"), ec);
if (ec) std::printf("ERROR: creating directory test_torrent_dir: (%d) %s\n"
, ec.value(), ec.message().c_str()); , ec.value(), ec.message().c_str());
file_storage fs; file_storage fs;
std::srand(10); std::srand(10);
int piece_size = 0x4000; int piece_size = 0x4000;
create_random_files(combine_path("tmp1_checking", "test_torrent_dir") create_random_files("test_torrent_dir", file_sizes, num_files, &fs);
, file_sizes, num_files);
add_files(fs, combine_path("tmp1_checking", "test_torrent_dir"));
lt::create_torrent t(fs, piece_size, 0x4000 lt::create_torrent t(fs, piece_size, 0x4000
, lt::create_torrent::optimize_alignment); , lt::create_torrent::optimize_alignment);
// calculate the hash for all pieces // calculate the hash for all pieces
set_piece_hashes(t, "tmp1_checking", ec); set_piece_hashes(t, ".", ec);
if (ec) std::printf("ERROR: set_piece_hashes: (%d) %s\n" if (ec) std::printf("ERROR: set_piece_hashes: (%d) %s\n"
, ec.value(), ec.message().c_str()); , ec.value(), ec.message().c_str());
@ -116,7 +98,7 @@ void test_checking(int flags = read_only_files)
bencode(std::back_inserter(buf), t.generate()); bencode(std::back_inserter(buf), t.generate());
auto ti = std::make_shared<torrent_info>(buf, ec, from_span); auto ti = std::make_shared<torrent_info>(buf, ec, from_span);
std::printf("generated torrent: %s tmp1_checking/test_torrent_dir\n" std::printf("generated torrent: %s test_torrent_dir\n"
, aux::to_hex(ti->info_hash()).c_str()); , aux::to_hex(ti->info_hash()).c_str());
// truncate every file in half // truncate every file in half
@ -128,7 +110,7 @@ void test_checking(int flags = read_only_files)
std::snprintf(name, sizeof(name), "test%d", i); std::snprintf(name, sizeof(name), "test%d", i);
char dirname[200]; char dirname[200];
std::snprintf(dirname, sizeof(dirname), "test_dir%d", i / 5); std::snprintf(dirname, sizeof(dirname), "test_dir%d", i / 5);
std::string path = combine_path(combine_path("tmp1_checking", "test_torrent_dir"), dirname); std::string path = combine_path("test_torrent_dir", dirname);
path = combine_path(path, name); path = combine_path(path, name);
error_code ec; error_code ec;
@ -148,9 +130,9 @@ void test_checking(int flags = read_only_files)
// increase the size of some files. When they're read only that forces // increase the size of some files. When they're read only that forces
// the checker to open them in write-mode to truncate them // the checker to open them in write-mode to truncate them
static const int file_sizes2[] = static const int file_sizes2[] =
{ 5, 16 - 5, 16001, 30, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1 { 0, 5, 16 - 5, 16001, 30, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1
,1,1,1,1,1,1,13,65000,34,75,2,30,400,500,23000,900,43000,400,4300,6, 4}; ,1,1,1,1,1,1,13,65000,34,75,2,30,400,500,23000,900,43000,400,4300,6, 4};
create_random_files(combine_path("tmp1_checking", "test_torrent_dir"), file_sizes2, num_files); create_random_files("test_torrent_dir", file_sizes2, num_files);
} }
// make the files read only // make the files read only
@ -164,7 +146,7 @@ void test_checking(int flags = read_only_files)
char dirname[200]; char dirname[200];
std::snprintf(dirname, sizeof(dirname), "test_dir%d", i / 5); std::snprintf(dirname, sizeof(dirname), "test_dir%d", i / 5);
std::string path = combine_path(combine_path("tmp1_checking", "test_torrent_dir"), dirname); std::string path = combine_path("test_torrent_dir", dirname);
path = combine_path(path, name); path = combine_path(path, name);
std::printf(" %s\n", path.c_str()); std::printf(" %s\n", path.c_str());
@ -176,6 +158,16 @@ void test_checking(int flags = read_only_files)
} }
} }
if (flags & force_recheck)
{
remove_all("test_torrent_dir_tmp", ec);
if (ec) std::printf("ERROR: removing \"test_torrent_dir_tmp\": (%d) %s\n"
, ec.value(), ec.message().c_str());
rename("test_torrent_dir", "test_torrent_dir_tmp", ec);
if (ec) std::printf("ERROR: renaming dir \"test_torrent_dir\": (%d) %s\n"
, ec.value(), ec.message().c_str());
}
auto const mask = alert::all_categories auto const mask = alert::all_categories
& ~(alert::progress_notification & ~(alert::progress_notification
| alert::performance_warning | alert::performance_warning
@ -192,11 +184,30 @@ void test_checking(int flags = read_only_files)
lt::session ses1(pack); lt::session ses1(pack);
add_torrent_params p; add_torrent_params p;
p.save_path = "tmp1_checking"; p.save_path = ".";
p.ti = ti; p.ti = ti;
torrent_handle tor1 = ses1.add_torrent(p, ec); torrent_handle tor1 = ses1.add_torrent(p, ec);
TEST_CHECK(!ec); TEST_CHECK(!ec);
if (flags & force_recheck)
{
// first make sure the session tries to check for the file and can't find
// them
libtorrent::alert const* a = wait_for_alert(
ses1, torrent_checked_alert::alert_type, "checking");
TEST_CHECK(a);
// now, move back the files and force-recheck. make sure we pick up the
// files this time
remove_all("test_torrent_dir", ec);
if (ec) fprintf(stdout, "ERROR: removing \"test_torrent_dir\": (%d) %s\n"
, ec.value(), ec.message().c_str());
rename("test_torrent_dir_tmp", "test_torrent_dir", ec);
if (ec) fprintf(stdout, "ERROR: renaming dir \"test_torrent_dir_tmp\": (%d) %s\n"
, ec.value(), ec.message().c_str());
tor1.force_recheck();
}
torrent_status st; torrent_status st;
for (int i = 0; i < 20; ++i) for (int i = 0; i < 20; ++i)
{ {
@ -217,6 +228,7 @@ void test_checking(int flags = read_only_files)
if (st.errc) break; if (st.errc) break;
std::this_thread::sleep_for(lt::milliseconds(500)); std::this_thread::sleep_for(lt::milliseconds(500));
} }
if (flags & incomplete_files) if (flags & incomplete_files)
{ {
TEST_CHECK(!st.is_seeding); TEST_CHECK(!st.is_seeding);
@ -273,7 +285,7 @@ void test_checking(int flags = read_only_files)
char dirname[200]; char dirname[200];
std::snprintf(dirname, sizeof(dirname), "test_dir%d", i / 5); std::snprintf(dirname, sizeof(dirname), "test_dir%d", i / 5);
std::string path = combine_path(combine_path("tmp1_checking", "test_torrent_dir"), dirname); std::string path = combine_path("test_torrent_dir", dirname);
path = combine_path(path, name); path = combine_path(path, name);
#ifdef TORRENT_WINDOWS #ifdef TORRENT_WINDOWS
SetFileAttributesA(path.c_str(), FILE_ATTRIBUTE_NORMAL); SetFileAttributesA(path.c_str(), FILE_ATTRIBUTE_NORMAL);
@ -283,8 +295,8 @@ void test_checking(int flags = read_only_files)
} }
} }
remove_all("tmp1_checking", ec); remove_all("test_torrent_dir", ec);
if (ec) std::printf("ERROR: removing tmp1_checking: (%d) %s\n" if (ec) std::printf("ERROR: removing test_torrent_dir: (%d) %s\n"
, ec.value(), ec.message().c_str()); , ec.value(), ec.message().c_str());
} }
@ -313,3 +325,8 @@ TORRENT_TEST(corrupt)
test_checking(corrupt_files); test_checking(corrupt_files);
} }
TORRENT_TEST(force_recheck)
{
test_checking(force_recheck);
}

View File

@ -76,6 +76,36 @@ void setup_test_storage(file_storage& st)
TEST_EQUAL(st.num_pieces(), (100000 + 0x3fff) / 0x4000); TEST_EQUAL(st.num_pieces(), (100000 + 0x3fff) / 0x4000);
} }
TORRENT_TEST(coalesce_path)
{
file_storage st;
st.add_file(combine_path("test", "a"), 10000);
TEST_EQUAL(st.paths().size(), 1);
TEST_EQUAL(st.paths()[0], "");
st.add_file(combine_path("test", "b"), 20000);
TEST_EQUAL(st.paths().size(), 1);
TEST_EQUAL(st.paths()[0], "");
st.add_file(combine_path("test", combine_path("c", "a")), 30000);
TEST_EQUAL(st.paths().size(), 2);
TEST_EQUAL(st.paths()[0], "");
TEST_EQUAL(st.paths()[1], "c");
// make sure that two files with the same path shares the path entry
st.add_file(combine_path("test", combine_path("c", "b")), 40000);
TEST_EQUAL(st.paths().size(), 2);
TEST_EQUAL(st.paths()[0], "");
TEST_EQUAL(st.paths()[1], "c");
// cause pad files to be created, to make sure the pad files also share the
// same path entries
st.optimize(0, 1024, true);
TEST_EQUAL(st.paths().size(), 3);
TEST_EQUAL(st.paths()[0], "");
TEST_EQUAL(st.paths()[1], "c");
TEST_EQUAL(st.paths()[2], ".pad");
}
TORRENT_TEST(rename_file) TORRENT_TEST(rename_file)
{ {
// test rename_file // test rename_file

View File

@ -201,6 +201,14 @@ void run_suite(std::string const& protocol
run_test(url_base + "password_protected", 3216, 200, 1, error_code(), ps run_test(url_base + "password_protected", 3216, 200, 1, error_code(), ps
, "testuser:testpass"); , "testuser:testpass");
// try a very long path
std::string path;
for (int i = 0; i < 6000; ++i)
{
path += static_cast<char>(i % 26) + 'a';
}
run_test(url_base + path, 0, 404, 1, err(), ps);
// only run the tests to handle NX_DOMAIN if we have a proper internet // only run the tests to handle NX_DOMAIN if we have a proper internet
// connection that doesn't inject false DNS responses (like Comcast does) // connection that doesn't inject false DNS responses (like Comcast does)
hostent* h = gethostbyname("non-existent-domain.se"); hostent* h = gethostbyname("non-existent-domain.se");

View File

@ -514,7 +514,7 @@ TORRENT_TEST(erase_peers)
{ {
std::printf("unexpected rejection of peer: %s | %d in list. " std::printf("unexpected rejection of peer: %s | %d in list. "
"added peer %p, erased %d peers\n" "added peer %p, erased %d peers\n"
, print_endpoint(ep).c_str(), p.num_peers(), peer , print_endpoint(ep).c_str(), p.num_peers(), static_cast<void*>(peer)
, int(st.erased.size())); , int(st.erased.size()));
} }
} }