finally finish lt sync

This commit is contained in:
Marcos Pinto 2008-07-20 18:46:41 +00:00
parent 4990d273a4
commit 13f67b609b
27 changed files with 985 additions and 963 deletions

View File

@ -115,7 +115,7 @@ namespace libtorrent {
std::auto_ptr<alert> get(); std::auto_ptr<alert> get();
template <class T> template <class T>
bool should_post() const { return m_alert_mask & T::static_category; } bool should_post() const { return (m_alert_mask & T::static_category) != 0; }
alert const* wait_for_alert(time_duration max_wait); alert const* wait_for_alert(time_duration max_wait);

View File

@ -83,7 +83,8 @@ POSSIBILITY OF SUCH DAMAGE.
#endif #endif
// should wpath or path be used? // should wpath or path be used?
#if defined UNICODE && !defined BOOST_FILESYSTEM_NARROW_ONLY && BOOST_VERSION >= 103400 #if defined UNICODE && !defined BOOST_FILESYSTEM_NARROW_ONLY \
&& BOOST_VERSION >= 103400 && defined WIN32
#define TORRENT_USE_WPATH 1 #define TORRENT_USE_WPATH 1
#else #else
#define TORRENT_USE_WPATH 0 #define TORRENT_USE_WPATH 0

View File

@ -86,6 +86,7 @@ namespace libtorrent
, save_resume_data , save_resume_data
, rename_file , rename_file
, abort_thread , abort_thread
, clear_read_cache
}; };
action_t action; action_t action;
@ -111,6 +112,9 @@ namespace libtorrent
boost::shared_ptr<entry> resume_data; boost::shared_ptr<entry> resume_data;
// the error code from the file operation
error_code error;
// this is called when operation completes // this is called when operation completes
boost::function<void(int, disk_io_job const&)> callback; boost::function<void(int, disk_io_job const&)> callback;
}; };
@ -214,6 +218,8 @@ namespace libtorrent
typedef boost::recursive_mutex mutex_t; typedef boost::recursive_mutex mutex_t;
typedef std::list<cached_piece_entry> cache_t; typedef std::list<cached_piece_entry> cache_t;
bool test_error(disk_io_job& j);
// cache operations // cache operations
cache_t::iterator find_cached_piece( cache_t::iterator find_cached_piece(
cache_t& cache, disk_io_job const& j cache_t& cache, disk_io_job const& j

View File

@ -0,0 +1,81 @@
/*
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.
*/
#ifndef TORRENT_ERROR_CODE_HPP_INCLUDED
#define TORRENT_ERROR_CODE_HPP_INCLUDED
#include <boost/version.hpp>
#if BOOST_VERSION < 103500
#include <asio/error_code.hpp>
#else
#include <boost/system/error_code.hpp>
#endif
namespace libtorrent
{
namespace errors
{
enum error_code_enum
{
no_error = 0,
file_collision
};
}
#if BOOST_VERSION < 103500
typedef asio::error_code error_code;
inline asio::error::error_category get_posix_category() { return asio::error::system_category; }
inline asio::error::error_category get_system_category() { return asio::error::system_category; }
#else
struct libtorrent_error_category : boost::system::error_category
{
virtual const char* name() const;
virtual std::string message(int ev) const;
virtual boost::system::error_condition default_error_condition(int ev) const
{ return boost::system::error_condition(ev, *this); }
};
extern libtorrent_error_category libtorrent_category;
using boost::system::error_code;
inline boost::system::error_category const& get_system_category()
{ return boost::system::get_system_category(); }
inline boost::system::error_category const& get_posix_category()
{ return boost::system::get_posix_category(); }
#endif
}
#endif

View File

@ -48,6 +48,7 @@ POSSIBILITY OF SUCH DAMAGE.
#pragma warning(pop) #pragma warning(pop)
#endif #endif
#include "libtorrent/error_code.hpp"
#include "libtorrent/size_type.hpp" #include "libtorrent/size_type.hpp"
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
@ -76,7 +77,6 @@ namespace libtorrent
public: public:
open_mode(): m_mask(0) {} open_mode(): m_mask(0) {}
open_mode operator|(open_mode m) const open_mode operator|(open_mode m) const
{ return open_mode(m.m_mask | m_mask); } { return open_mode(m.m_mask | m_mask); }
@ -91,6 +91,7 @@ namespace libtorrent
bool operator==(open_mode m) const { return m_mask == m.m_mask; } bool operator==(open_mode m) const { return m_mask == m.m_mask; }
bool operator!=(open_mode m) const { return m_mask != m.m_mask; } bool operator!=(open_mode m) const { return m_mask != m.m_mask; }
operator bool() const { return m_mask != 0; }
private: private:
@ -102,25 +103,30 @@ namespace libtorrent
static const open_mode out; static const open_mode out;
file(); file();
file(fs::path const& p, open_mode m); file(fs::path const& p, open_mode m, error_code& ec);
~file(); ~file();
bool open(fs::path const& p, open_mode m); bool open(fs::path const& p, open_mode m, error_code& ec);
bool is_open() const;
void close(); void close();
bool set_size(size_type size); bool set_size(size_type size, error_code& ec);
size_type write(const char*, size_type num_bytes); size_type write(const char*, size_type num_bytes, error_code& ec);
size_type read(char*, size_type num_bytes); size_type read(char*, size_type num_bytes, error_code& ec);
size_type seek(size_type pos, seek_mode m = begin); size_type seek(size_type pos, seek_mode m, error_code& ec);
size_type tell(); size_type tell(error_code& ec);
std::string const& error() const;
private: private:
struct impl; #ifdef TORRENT_WINDOWS
const std::auto_ptr<impl> m_impl; HANDLE m_file_handle;
#else
int m_fd;
#endif
#ifndef NDEBUG
open_mode m_open_mode;
#endif
}; };

View File

@ -66,7 +66,7 @@ namespace libtorrent
file_pool(int size = 40): m_size(size) {} file_pool(int size = 40): m_size(size) {}
boost::shared_ptr<file> open_file(void* st, fs::path const& p boost::shared_ptr<file> open_file(void* st, fs::path const& p
, file::open_mode m, std::string& error); , file::open_mode m, error_code& ec);
void release(void* st); void release(void* st);
void release(fs::path const& p); void release(fs::path const& p);
void resize(int size); void resize(int size);

View File

@ -124,6 +124,7 @@ namespace libtorrent
size_type dict_find_int_value(char const* name, size_type default_val = 0) const; size_type dict_find_int_value(char const* name, size_type default_val = 0) const;
lazy_entry const* dict_find_dict(char const* name) const; lazy_entry const* dict_find_dict(char const* name) const;
lazy_entry const* dict_find_list(char const* name) const; lazy_entry const* dict_find_list(char const* name) const;
lazy_entry const* dict_find_string(char const* name) const;
std::pair<std::string, lazy_entry const*> dict_at(int i) const std::pair<std::string, lazy_entry const*> dict_at(int i) const
{ {

View File

@ -323,6 +323,10 @@ namespace libtorrent
// the number of bytes transferred within unchoke cycles // the number of bytes transferred within unchoke cycles
void reset_choke_counters(); void reset_choke_counters();
// if this peer connection is useless (neither party is
// interested in the other), disconnect it
void disconnect_if_redundant();
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
boost::shared_ptr<logger> m_logger; boost::shared_ptr<logger> m_logger;
#endif #endif
@ -854,9 +858,13 @@ namespace libtorrent
// is set to 1 // is set to 1
bool m_snubbed:1; bool m_snubbed:1;
// this is set to true once the bitfield is received
bool m_bitfield_received:1;
#ifndef NDEBUG #ifndef NDEBUG
public: public:
bool m_in_constructor:1; bool m_in_constructor:1;
bool m_disconnect_started:1;
#endif #endif
}; };
} }

View File

@ -57,7 +57,8 @@ namespace libtorrent
on_parole = 0x200, on_parole = 0x200,
seed = 0x400, seed = 0x400,
optimistic_unchoke = 0x800, optimistic_unchoke = 0x800,
snubbed = 0x1000 snubbed = 0x1000,
upload_only = 0x2000
#ifndef TORRENT_DISABLE_ENCRYPTION #ifndef TORRENT_DISABLE_ENCRYPTION
, rc4_encrypted = 0x100000, , rc4_encrypted = 0x100000,
plaintext_encrypted = 0x200000 plaintext_encrypted = 0x200000

View File

@ -73,6 +73,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/io.hpp" #include "libtorrent/io.hpp"
#include "libtorrent/time.hpp" #include "libtorrent/time.hpp"
#include "libtorrent/error_code.hpp"
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
@ -94,12 +95,10 @@ namespace libtorrent
typedef asio::ip::udp::socket datagram_socket; typedef asio::ip::udp::socket datagram_socket;
typedef asio::ip::tcp::acceptor socket_acceptor; typedef asio::ip::tcp::acceptor socket_acceptor;
typedef asio::io_service io_service; typedef asio::io_service io_service;
typedef asio::error_code error_code;
namespace asio = ::asio; namespace asio = ::asio;
typedef asio::basic_deadline_timer<libtorrent::ptime> deadline_timer; typedef asio::basic_deadline_timer<libtorrent::ptime> deadline_timer;
#else #else
using boost::system::error_code;
using boost::asio::ip::tcp; using boost::asio::ip::tcp;
using boost::asio::ip::udp; using boost::asio::ip::udp;
using boost::asio::async_write; using boost::asio::async_write;

View File

@ -164,17 +164,17 @@ namespace libtorrent
// non-zero return value indicates an error // non-zero return value indicates an error
virtual bool delete_files() = 0; virtual bool delete_files() = 0;
void set_error(std::string const& file, std::string const& msg) const void set_error(boost::filesystem::path const& file, error_code const& ec) const
{ {
m_error_file = file; m_error_file = file.string();
m_error = msg; m_error = ec;
} }
std::string const& error() const { return m_error; } error_code const& error() const { return m_error; }
std::string const& error_file() const { return m_error_file; } std::string const& error_file() const { return m_error_file; }
void clear_error() { m_error.clear(); m_error_file.clear(); } void clear_error() { m_error = error_code(); m_error_file.clear(); }
mutable std::string m_error; mutable error_code m_error;
mutable std::string m_error_file; mutable std::string m_error_file;
virtual ~storage_interface() {} virtual ~storage_interface() {}
@ -236,6 +236,10 @@ namespace libtorrent
boost::function<void(int, disk_io_job const&)> const& handler boost::function<void(int, disk_io_job const&)> const& handler
= boost::function<void(int, disk_io_job const&)>()); = boost::function<void(int, disk_io_job const&)>());
void async_clear_read_cache(
boost::function<void(int, disk_io_job const&)> const& handler
= boost::function<void(int, disk_io_job const&)>());
void async_delete_files( void async_delete_files(
boost::function<void(int, disk_io_job const&)> const& handler boost::function<void(int, disk_io_job const&)> const& handler
= boost::function<void(int, disk_io_job const&)>()); = boost::function<void(int, disk_io_job const&)>());
@ -267,7 +271,7 @@ namespace libtorrent
void mark_failed(int index); void mark_failed(int index);
std::string const& error() const { return m_storage->error(); } error_code const& error() const { return m_storage->error(); }
std::string const& error_file() const { return m_storage->error_file(); } std::string const& error_file() const { return m_storage->error_file(); }
void clear_error() { m_storage->clear_error(); } void clear_error() { m_storage->clear_error(); }
@ -308,7 +312,8 @@ namespace libtorrent
, int offset , int offset
, int size); , int size);
bool check_one_piece(int& have_piece); // -1=error 0=ok 1=skip
int check_one_piece(int& have_piece);
int identify_data( int identify_data(
const std::vector<char>& piece_data const std::vector<char>& piece_data
, int current_slot); , int current_slot);

View File

@ -235,7 +235,13 @@ namespace libtorrent
void prioritize_pieces(std::vector<int> const& pieces); void prioritize_pieces(std::vector<int> const& pieces);
void piece_priorities(std::vector<int>&) const; void piece_priorities(std::vector<int>&) const;
void set_file_priority(int index, int priority);
int file_priority(int index) const;
void prioritize_files(std::vector<int> const& files); void prioritize_files(std::vector<int> const& files);
void file_priorities(std::vector<int>&) const;
void update_piece_priorities();
torrent_status status() const; torrent_status status() const;
@ -610,6 +616,8 @@ namespace libtorrent
{ return m_connections_initialized; } { return m_connections_initialized; }
bool valid_metadata() const bool valid_metadata() const
{ return m_torrent_file->is_valid(); } { return m_torrent_file->is_valid(); }
bool are_files_checked() const
{ return m_files_checked; }
// parses the info section from the given // parses the info section from the given
// bencoded tree and moves the torrent // bencoded tree and moves the torrent
@ -768,6 +776,8 @@ namespace libtorrent
// this torrent belongs to. // this torrent belongs to.
aux::session_impl& m_ses; aux::session_impl& m_ses;
std::vector<boost::uint8_t> m_file_priority;
boost::scoped_ptr<piece_picker> m_picker; boost::scoped_ptr<piece_picker> m_picker;
// the queue of peer_connections that want more bandwidth // the queue of peer_connections that want more bandwidth

View File

@ -392,8 +392,12 @@ namespace libtorrent
void prioritize_pieces(std::vector<int> const& pieces) const; void prioritize_pieces(std::vector<int> const& pieces) const;
std::vector<int> piece_priorities() const; std::vector<int> piece_priorities() const;
void prioritize_files(std::vector<int> const& files) const; // priority must be within the range [0, 7]
void file_priority(int index, int priority) const;
int file_priority(int index) const;
void prioritize_files(std::vector<int> const& files) const;
std::vector<int> file_priorities() const;
// set the interface to bind outgoing connections // set the interface to bind outgoing connections
// to. // to.

View File

@ -2647,9 +2647,6 @@ namespace libtorrent
TORRENT_ASSERT(m_sent_handshake); TORRENT_ASSERT(m_sent_handshake);
} }
if (!m_in_constructor)
peer_connection::check_invariant();
if (!m_payloads.empty()) if (!m_payloads.empty())
{ {
for (std::deque<range>::const_iterator i = m_payloads.begin(); for (std::deque<range>::const_iterator i = m_payloads.begin();

View File

@ -420,7 +420,7 @@ namespace libtorrent
l.unlock(); l.unlock();
ret += p.storage->read_impl(buf.get(), p.piece, start_block * m_block_size, buffer_size); ret += p.storage->read_impl(buf.get(), p.piece, start_block * m_block_size, buffer_size);
l.lock(); l.lock();
if (!p.storage->error().empty()) { return -1; } if (p.storage->error()) { return -1; }
++m_cache_stats.reads; ++m_cache_stats.reads;
} }
@ -440,7 +440,7 @@ namespace libtorrent
{ {
l.unlock(); l.unlock();
ret += p.storage->read_impl(p.blocks[i], p.piece, piece_offset, block_size); ret += p.storage->read_impl(p.blocks[i], p.piece, piece_offset, block_size);
if (!p.storage->error().empty()) { return -1; } if (!p.storage->error()) { return -1; }
l.lock(); l.lock();
++m_cache_stats.reads; ++m_cache_stats.reads;
} }
@ -735,6 +735,23 @@ namespace libtorrent
#endif #endif
} }
bool disk_io_thread::test_error(disk_io_job& j)
{
error_code const& ec = j.storage->error();
if (ec)
{
j.str = ec.message();
j.error = ec;
j.error_file = j.storage->error_file();
j.storage->clear_error();
#ifndef NDEBUG
std::cout << "ERROR: '" << j.str << "' " << j.error_file << std::endl;
#endif
return true;
}
return false;
}
void disk_io_thread::operator()() void disk_io_thread::operator()()
{ {
for (;;) for (;;)
@ -819,17 +836,10 @@ namespace libtorrent
} }
case disk_io_job::read: case disk_io_job::read:
{ {
std::string const& error_string = j.storage->error(); if (test_error(j))
if (!error_string.empty())
{ {
#ifndef NDEBUG
std::cout << "ERROR: '" << error_string << "' " << j.error_file << std::endl;
#endif
j.str = error_string;
j.error_file = j.storage->error_file();
j.storage->clear_error();
ret = -1; ret = -1;
break; return;
} }
#ifdef TORRENT_DISK_STATS #ifdef TORRENT_DISK_STATS
m_log << log_time() << " read " << j.buffer_size << std::endl; m_log << log_time() << " read " << j.buffer_size << std::endl;
@ -841,7 +851,8 @@ namespace libtorrent
if (j.buffer == 0) if (j.buffer == 0)
{ {
ret = -1; ret = -1;
j.str = "out of memory"; j.error = error_code(ENOMEM, get_posix_category());
j.str = j.error.message();
break; break;
} }
@ -853,9 +864,7 @@ namespace libtorrent
if (ret == -1) if (ret == -1)
{ {
j.buffer = 0; j.buffer = 0;
j.str = j.storage->error(); test_error(j);
j.error_file = j.storage->error_file();
j.storage->clear_error();
break; break;
} }
else if (ret == -2) else if (ret == -2)
@ -864,9 +873,7 @@ namespace libtorrent
, j.buffer_size); , j.buffer_size);
if (ret < 0) if (ret < 0)
{ {
j.str = j.storage->error(); test_error(j);
j.error_file = j.storage->error_file();
j.storage->clear_error();
break; break;
} }
++m_cache_stats.blocks_read; ++m_cache_stats.blocks_read;
@ -876,15 +883,8 @@ namespace libtorrent
} }
case disk_io_job::write: case disk_io_job::write:
{ {
std::string const& error_string = j.storage->error(); if (test_error(j))
if (!error_string.empty())
{ {
#ifndef NDEBUG
std::cout << "ERROR: '" << error_string << "' " << j.error_file << std::endl;
#endif
j.str = error_string;
j.error_file = j.storage->error_file();
j.storage->clear_error();
ret = -1; ret = -1;
break; break;
} }
@ -936,26 +936,18 @@ namespace libtorrent
if (i != m_pieces.end()) if (i != m_pieces.end())
{ {
flush_and_remove(i, l); flush_and_remove(i, l);
std::string const& e = j.storage->error(); if (test_error(j))
if (!e.empty())
{ {
j.str = e;
j.error_file = j.storage->error_file();
ret = -1; ret = -1;
j.storage->clear_error();
j.storage->mark_failed(j.piece); j.storage->mark_failed(j.piece);
break; break;
} }
} }
l.unlock(); l.unlock();
sha1_hash h = j.storage->hash_for_piece_impl(j.piece); sha1_hash h = j.storage->hash_for_piece_impl(j.piece);
std::string const& e = j.storage->error(); if (test_error(j))
if (!e.empty())
{ {
j.str = e;
j.error_file = j.storage->error_file();
ret = -1; ret = -1;
j.storage->clear_error();
j.storage->mark_failed(j.piece); j.storage->mark_failed(j.piece);
break; break;
} }
@ -972,9 +964,7 @@ namespace libtorrent
ret = j.storage->move_storage_impl(j.str) ? 1 : 0; ret = j.storage->move_storage_impl(j.str) ? 1 : 0;
if (ret != 0) if (ret != 0)
{ {
j.str = j.storage->error(); test_error(j);
j.error_file = j.storage->error_file();
j.storage->clear_error();
break; break;
} }
j.str = j.storage->save_path().string(); j.str = j.storage->save_path().string();
@ -1010,12 +1000,40 @@ namespace libtorrent
} }
#endif #endif
ret = j.storage->release_files_impl(); ret = j.storage->release_files_impl();
if (ret != 0) if (ret != 0) test_error(j);
{ break;
j.str = j.storage->error();
j.error_file = j.storage->error_file();
j.storage->clear_error();
} }
case disk_io_job::clear_read_cache:
{
#ifdef TORRENT_DISK_STATS
m_log << log_time() << " clear-cache" << std::endl;
#endif
TORRENT_ASSERT(j.buffer == 0);
mutex_t::scoped_lock l(m_piece_mutex);
INVARIANT_CHECK;
for (cache_t::iterator i = m_read_pieces.begin();
i != m_read_pieces.end();)
{
if (i->storage == j.storage)
{
free_piece(*i, l);
i = m_read_pieces.erase(i);
}
else
{
++i;
}
}
l.unlock();
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
{
mutex_t::scoped_lock l(m_pool_mutex);
m_pool.release_memory();
}
#endif
ret = 0;
break; break;
} }
case disk_io_job::delete_files: case disk_io_job::delete_files:
@ -1051,12 +1069,7 @@ namespace libtorrent
} }
#endif #endif
ret = j.storage->delete_files_impl(); ret = j.storage->delete_files_impl();
if (ret != 0) if (ret != 0) test_error(j);
{
j.str = j.storage->error();
j.error_file = j.storage->error_file();
j.storage->clear_error();
}
break; break;
} }
case disk_io_job::check_fastresume: case disk_io_job::check_fastresume:
@ -1090,6 +1103,13 @@ namespace libtorrent
#endif #endif
if (ret != piece_manager::need_full_check) break; if (ret != piece_manager::need_full_check) break;
} }
if (test_error(j))
{
ret = piece_manager::fatal_disk_error;
break;
}
TORRENT_ASSERT(ret != -2 || !j.str.empty());
// if the check is not done, add it at the end of the job queue // if the check is not done, add it at the end of the job queue
if (ret == piece_manager::need_full_check) if (ret == piece_manager::need_full_check)
{ {
@ -1133,6 +1153,7 @@ namespace libtorrent
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
try { try {
#endif #endif
TORRENT_ASSERT(ret != -2 || !j.str.empty());
if (handler) m_ios.post(bind(handler, ret, j)); if (handler) m_ios.post(bind(handler, ret, j));
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
} catch (std::exception&) } catch (std::exception&)

View File

@ -0,0 +1,60 @@
/*
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 <boost/version.hpp>
#if BOOST_VERSION >= 103500
#include "libtorrent/error_code.hpp"
namespace libtorrent
{
const char* libtorrent_error_category::name() const
{
return "libtorrent error";
}
std::string libtorrent_error_category::message(int ev) const
{
static char const* msgs[] =
{ "no error", "torrent file collides with file from another torrent" };
if (ev < 0 || ev >= sizeof(msgs)/sizeof(msgs[0]))
return "Unknown error";
return msgs[ev];
}
libtorrent_error_category libtorrent_category;
}
#endif

View File

@ -31,27 +31,22 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "libtorrent/pch.hpp" #include "libtorrent/pch.hpp"
#include "libtorrent/config.hpp"
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#ifdef _WIN32 #ifdef TORRENT_WINDOWS
// windows part // windows part
#include "libtorrent/utf8.hpp" #include "libtorrent/utf8.hpp"
#include <io.h> #include <windows.h>
#include <fcntl.h> #include <winioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifndef _MODE_T_
typedef int mode_t;
#endif
#ifdef UNICODE #ifdef UNICODE
#include "libtorrent/storage.hpp" #include "libtorrent/storage.hpp"
#endif #endif
#else #else
// unix part // posix part
#define _FILE_OFFSET_BITS 64 #define _FILE_OFFSET_BITS 64
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
@ -88,18 +83,7 @@ BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);
namespace namespace
{ {
enum { mode_in = 1, mode_out = 2 }; #ifdef TORRENT_WINDOWS
mode_t map_open_mode(int m)
{
if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
TORRENT_ASSERT(false);
return 0;
}
#ifdef WIN32
std::string utf8_native(std::string const& s) std::string utf8_native(std::string const& s)
{ {
try try
@ -121,9 +105,16 @@ namespace
} }
} }
#else #else
std::string utf8_native(std::string const& s)
enum { mode_in = 1, mode_out = 2 };
mode_t map_open_mode(int m)
{ {
return s; if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
TORRENT_ASSERT(false);
return 0;
} }
#endif #endif
@ -133,239 +124,243 @@ namespace libtorrent
{ {
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
#ifdef TORRENT_WINDOWS
const file::open_mode file::in(GENERIC_READ);
const file::open_mode file::out(GENERIC_WRITE);
const file::seek_mode file::begin(FILE_BEGIN);
const file::seek_mode file::end(FILE_END);
#else
const file::open_mode file::in(mode_in); const file::open_mode file::in(mode_in);
const file::open_mode file::out(mode_out); const file::open_mode file::out(mode_out);
const file::seek_mode file::begin(SEEK_SET);
const file::seek_mode file::end(SEEK_END);
#endif
const file::seek_mode file::begin(1); file::file()
const file::seek_mode file::end(2); #ifdef TORRENT_WINDOWS
: m_file_handle(INVALID_HANDLE_VALUE)
struct file::impl #else
{
impl()
: m_fd(-1) : m_fd(-1)
#endif
#ifndef NDEBUG
, m_open_mode(0) , m_open_mode(0)
#endif
{} {}
impl(fs::path const& path, int mode) file::file(fs::path const& path, open_mode mode, error_code& ec)
: m_fd(-1) #ifdef TORRENT_WINDOWS
, m_open_mode(0) : m_file_handle(INVALID_HANDLE_VALUE)
{
open(path, mode);
}
~impl()
{
close();
}
bool open(fs::path const& path, int mode)
{
close();
#if defined _WIN32 && defined UNICODE
std::wstring wpath(safe_convert(path.native_file_string()));
m_fd = ::_wopen(
wpath.c_str()
, map_open_mode(mode)
, S_IREAD | S_IWRITE);
#elif defined _WIN32
m_fd = ::_open(
utf8_native(path.native_file_string()).c_str()
, map_open_mode(mode)
, S_IREAD | S_IWRITE);
#else #else
m_fd = ::open( : m_fd(-1)
utf8_native(path.native_file_string()).c_str()
, map_open_mode(mode)
, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#endif #endif
#ifndef NDEBUG
, m_open_mode(0)
#endif
{
open(path, mode, ec);
}
file::~file()
{
close();
}
bool file::open(fs::path const& path, open_mode mode, error_code& ec)
{
close();
#ifdef TORRENT_WINDOWS
#ifdef UNICODE
std::wstring file_path(safe_convert(path.native_file_string()));
#else
std::string file_path = utf8_native(path.native_file_string());
#endif
m_file_handle = CreateFile(
file_path.c_str()
, mode.m_mask
, FILE_SHARE_READ
, 0
, (mode & out)?OPEN_ALWAYS:OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
if (m_file_handle == INVALID_HANDLE_VALUE)
{
ec = error_code(GetLastError(), get_system_category());
return false;
}
// try to make the file sparse if supported
if (mode & out)
{
DWORD temp;
::DeviceIoControl(m_file_handle, FSCTL_SET_SPARSE, 0, 0
, 0, 0, &temp, 0);
}
#else
// rely on default umask to filter x and w permissions
// for group and others
m_fd = ::open(path.native_file_string().c_str()
, map_open_mode(mode.m_mask), S_IRWXU | S_IRWXG | S_IRWXO);
if (m_fd == -1) if (m_fd == -1)
{ {
std::stringstream msg; ec = error_code(errno, get_posix_category());
msg << "open failed: '" << path.native_file_string() << "'. "
<< std::strerror(errno);
if (!m_error) m_error.reset(new std::string);
*m_error = msg.str();
return false; return false;
} }
#endif
#ifndef NDEBUG
m_open_mode = mode; m_open_mode = mode;
#endif
TORRENT_ASSERT(is_open());
return true; return true;
} }
void close() bool file::is_open() const
{ {
if (m_fd == -1) return; #ifdef TORRENT_WINDOWS
return m_file_handle != INVALID_HANDLE_VALUE;
#ifdef _WIN32
::_close(m_fd);
#else #else
::close(m_fd); return m_fd != -1;
#endif #endif
m_fd = -1;
m_open_mode = 0;
}
size_type read(char* buf, size_type num_bytes)
{
TORRENT_ASSERT(m_open_mode & mode_in);
TORRENT_ASSERT(m_fd != -1);
#ifdef _WIN32
size_type ret = ::_read(m_fd, buf, num_bytes);
#else
size_type ret = ::read(m_fd, buf, num_bytes);
#endif
if (ret == -1)
{
std::stringstream msg;
msg << "read failed: " << std::strerror(errno);
if (!m_error) m_error.reset(new std::string);
*m_error = msg.str();
}
return ret;
}
size_type write(const char* buf, size_type num_bytes)
{
TORRENT_ASSERT(m_open_mode & mode_out);
TORRENT_ASSERT(m_fd != -1);
// TODO: Test this a bit more, what happens with random failures in
// the files?
// if ((rand() % 100) > 80)
// throw file_error("debug");
#ifdef _WIN32
size_type ret = ::_write(m_fd, buf, num_bytes);
#else
size_type ret = ::write(m_fd, buf, num_bytes);
#endif
if (ret == -1)
{
std::stringstream msg;
msg << "write failed: " << std::strerror(errno);
if (!m_error) m_error.reset(new std::string);
*m_error = msg.str();
}
return ret;
}
bool set_size(size_type s)
{
#ifdef _WIN32
#error file.cpp is for posix systems only. use file_win.cpp on windows
#else
if (ftruncate(m_fd, s) < 0)
{
std::stringstream msg;
msg << "ftruncate failed: '" << std::strerror(errno);
if (!m_error) m_error.reset(new std::string);
*m_error = msg.str();
return false;
}
return true;
#endif
}
size_type seek(size_type offset, int m = 1)
{
TORRENT_ASSERT(m_open_mode);
TORRENT_ASSERT(m_fd != -1);
int seekdir = (m == 1)?SEEK_SET:SEEK_END;
#ifdef _WIN32
size_type ret = _lseeki64(m_fd, offset, seekdir);
#else
size_type ret = lseek(m_fd, offset, seekdir);
#endif
// For some strange reason this fails
// on win32. Use windows specific file
// wrapper instead.
if (ret == -1)
{
std::stringstream msg;
msg << "seek failed: '" << std::strerror(errno)
<< "' fd: " << m_fd
<< " offset: " << offset
<< " seekdir: " << seekdir;
if (!m_error) m_error.reset(new std::string);
*m_error = msg.str();
return -1;
}
return ret;
}
size_type tell()
{
TORRENT_ASSERT(m_open_mode);
TORRENT_ASSERT(m_fd != -1);
#ifdef _WIN32
return _telli64(m_fd);
#else
return lseek(m_fd, 0, SEEK_CUR);
#endif
}
std::string const& error() const
{
if (!m_error) m_error.reset(new std::string);
return *m_error;
}
int m_fd;
int m_open_mode;
mutable boost::scoped_ptr<std::string> m_error;
};
// pimpl forwardings
file::file() : m_impl(new impl()) {}
file::file(fs::path const& p, file::open_mode m)
: m_impl(new impl(p, m.m_mask))
{}
file::~file() {}
bool file::open(fs::path const& p, file::open_mode m)
{
return m_impl->open(p, m.m_mask);
} }
void file::close() void file::close()
{ {
m_impl->close(); #ifdef TORRENT_WINDOWS
if (m_file_handle == INVALID_HANDLE_VALUE) return;
CloseHandle(m_file_handle);
m_file_handle = INVALID_HANDLE_VALUE;
#else
if (m_fd == -1) return;
::close(m_fd);
m_fd = -1;
#endif
#ifndef NDEBUG
m_open_mode = 0;
#endif
} }
size_type file::write(const char* buf, size_type num_bytes) size_type file::read(char* buf, size_type num_bytes, error_code& ec)
{ {
return m_impl->write(buf, num_bytes); TORRENT_ASSERT((m_open_mode & in) == in);
} TORRENT_ASSERT(buf);
TORRENT_ASSERT(num_bytes >= 0);
TORRENT_ASSERT(is_open());
size_type file::read(char* buf, size_type num_bytes) #ifdef TORRENT_WINDOWS
TORRENT_ASSERT(DWORD(num_bytes) == num_bytes);
DWORD ret = 0;
if (num_bytes != 0)
{ {
return m_impl->read(buf, num_bytes); if (ReadFile(m_file_handle, buf, (DWORD)num_bytes, &ret, 0) == FALSE)
}
bool file::set_size(size_type s)
{ {
return m_impl->set_size(s); ec = error_code(GetLastError(), get_system_category());
return -1;
}
}
#else
size_type ret = ::read(m_fd, buf, num_bytes);
if (ret == -1) ec = error_code(errno, get_posix_category());
#endif
return ret;
} }
size_type file::seek(size_type pos, file::seek_mode m) size_type file::write(const char* buf, size_type num_bytes, error_code& ec)
{ {
return m_impl->seek(pos, m.m_val); TORRENT_ASSERT((m_open_mode & out) == out);
} TORRENT_ASSERT(buf);
TORRENT_ASSERT(num_bytes >= 0);
TORRENT_ASSERT(is_open());
size_type file::tell() #ifdef TORRENT_WINDOWS
DWORD ret = 0;
if (num_bytes != 0)
{ {
return m_impl->tell(); if (WriteFile(m_file_handle, buf, (DWORD)num_bytes, &ret, 0) == FALSE)
}
std::string const& file::error() const
{ {
return m_impl->error(); ec = error_code(GetLastError(), get_system_category());
return -1;
}
}
#else
size_type ret = ::write(m_fd, buf, num_bytes);
if (ret == -1) ec = error_code(errno, get_posix_category());
#endif
return ret;
} }
bool file::set_size(size_type s, error_code& ec)
{
TORRENT_ASSERT(is_open());
TORRENT_ASSERT(s >= 0);
#ifdef TORRENT_WINDOWS
size_type pos = tell(ec);
if (ec) return false;
seek(s, begin, ec);
if (ec) return false;
if (::SetEndOfFile(m_file_handle) == FALSE)
{
ec = error_code(GetLastError(), get_system_category());
return false;
} }
#else
if (ftruncate(m_fd, s) < 0)
{
ec = error_code(errno, get_posix_category());
return false;
}
#endif
return true;
}
size_type file::seek(size_type offset, seek_mode m, error_code& ec)
{
TORRENT_ASSERT(is_open());
#ifdef TORRENT_WINDOWS
LARGE_INTEGER offs;
offs.QuadPart = offset;
if (SetFilePointerEx(m_file_handle, offs, &offs, m.m_val) == FALSE)
{
ec = error_code(GetLastError(), get_system_category());
return -1;
}
return offs.QuadPart;
#else
size_type ret = lseek(m_fd, offset, m.m_val);
if (ret < 0) ec = error_code(errno, get_posix_category());
return ret;
#endif
}
size_type file::tell(error_code& ec)
{
TORRENT_ASSERT(is_open());
#ifdef TORRENT_WINDOWS
LARGE_INTEGER offs;
offs.QuadPart = 0;
// is there any other way to get offset?
if (SetFilePointerEx(m_file_handle, offs, &offs
, FILE_CURRENT) == FALSE)
{
ec = error_code(GetLastError(), get_system_category());
return -1;
}
return offs.QuadPart;
#else
size_type ret;
ret = lseek(m_fd, 0, SEEK_CUR);
if (ret < 0) ec = error_code(errno, get_posix_category());
return ret;
#endif
}
}

View File

@ -30,9 +30,10 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <boost/version.hpp>
#include "libtorrent/pch.hpp" #include "libtorrent/pch.hpp"
#include "libtorrent/file_pool.hpp" #include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"
#include <iostream> #include <iostream>
@ -42,7 +43,7 @@ namespace libtorrent
using boost::multi_index::get; using boost::multi_index::get;
boost::shared_ptr<file> file_pool::open_file(void* st, fs::path const& p boost::shared_ptr<file> file_pool::open_file(void* st, fs::path const& p
, file::open_mode m, std::string& error) , file::open_mode m, error_code& ec)
{ {
TORRENT_ASSERT(st != 0); TORRENT_ASSERT(st != 0);
TORRENT_ASSERT(p.is_complete()); TORRENT_ASSERT(p.is_complete());
@ -60,8 +61,9 @@ namespace libtorrent
{ {
// this means that another instance of the storage // this means that another instance of the storage
// is using the exact same file. // is using the exact same file.
error = "torrent uses the same file as another torrent " #if BOOST_VERSION >= 103500
"(" + p.string() + ")"; ec = error_code(errors::file_collision, libtorrent_category);
#endif
return boost::shared_ptr<file>(); return boost::shared_ptr<file>();
} }
@ -73,12 +75,12 @@ namespace libtorrent
i->file_ptr.reset(); i->file_ptr.reset();
TORRENT_ASSERT(e.file_ptr.unique()); TORRENT_ASSERT(e.file_ptr.unique());
e.file_ptr->close(); e.file_ptr->close();
if (!e.file_ptr->open(p, m)) if (!e.file_ptr->open(p, m, ec))
{ {
error = e.file_ptr->error();
m_files.erase(i); m_files.erase(i);
return boost::shared_ptr<file>(); return boost::shared_ptr<file>();
} }
TORRENT_ASSERT(e.file_ptr->is_open());
e.mode = m; e.mode = m;
} }
pt.replace(i, e); pt.replace(i, e);
@ -97,21 +99,19 @@ namespace libtorrent
lt.erase(i); lt.erase(i);
} }
lru_file_entry e; lru_file_entry e;
e.file_ptr.reset(new file); e.file_ptr.reset(new (std::nothrow)file);
if (!e.file_ptr) if (!e.file_ptr)
{ {
error = "no memory"; ec = error_code(ENOMEM, get_posix_category());
return e.file_ptr; return e.file_ptr;
} }
if (!e.file_ptr->open(p, m)) if (!e.file_ptr->open(p, m, ec))
{
error = e.file_ptr->error();
return boost::shared_ptr<file>(); return boost::shared_ptr<file>();
}
e.mode = m; e.mode = m;
e.key = st; e.key = st;
e.file_path = p; e.file_path = p;
pt.insert(e); pt.insert(e);
TORRENT_ASSERT(e.file_ptr->is_open());
return e.file_ptr; return e.file_ptr;
} }

View File

@ -1,392 +0,0 @@
/*
Copyright (c) 2003, Magnus Jonsson & 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/file.hpp"
#include "libtorrent/utf8.hpp"
#include "libtorrent/assert.hpp"
#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif
#include <sstream>
#include <windows.h>
#include <winioctl.h>
#include <boost/scoped_ptr.hpp>
namespace
{
// must be used to not leak memory in case something would throw
class auto_localfree
{
public:
auto_localfree(HLOCAL memory)
: m_memory(memory)
{
}
~auto_localfree()
{
if (m_memory)
LocalFree(m_memory);
}
private:
HLOCAL m_memory;
};
std::string utf8_native(std::string const& s)
{
try
{
std::wstring ws;
libtorrent::utf8_wchar(s, ws);
std::size_t size = wcstombs(0, ws.c_str(), 0);
if (size == std::size_t(-1)) return s;
std::string ret;
ret.resize(size);
size = wcstombs(&ret[0], ws.c_str(), size + 1);
if (size == wchar_t(-1)) return s;
ret.resize(size);
return ret;
}
catch(std::exception)
{
return s;
}
}
}
namespace libtorrent
{
struct file::impl : boost::noncopyable
{
enum open_flags
{
read_flag = 1,
write_flag = 2
};
enum seek_mode
{
seek_begin = FILE_BEGIN,
seek_from_here = FILE_CURRENT,
seek_end = FILE_END
};
void set_error(const char* thrower)
{
DWORD err = GetLastError();
#ifdef UNICODE
wchar_t *wbuffer = 0;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM
|FORMAT_MESSAGE_ALLOCATE_BUFFER
, 0, err, 0, (LPWSTR)&wbuffer, 0, 0);
auto_localfree auto_free(wbuffer);
std::string tmp_utf8;
libtorrent::wchar_utf8(wbuffer, tmp_utf8);
char const* buffer = tmp_utf8.c_str();
#else
char* buffer = 0;
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM
|FORMAT_MESSAGE_ALLOCATE_BUFFER
, 0, err, 0, (LPSTR)&buffer, 0, 0);
auto_localfree auto_free(buffer);
#endif
std::stringstream s;
s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL");
if (!m_error) m_error.reset(new std::string);
*m_error = s.str();
}
impl()
{
m_file_handle = INVALID_HANDLE_VALUE;
}
bool open(const char *file_name, open_flags flags)
{
TORRENT_ASSERT(file_name);
TORRENT_ASSERT(flags & (read_flag | write_flag));
DWORD access_mask = 0;
if (flags & read_flag)
access_mask |= GENERIC_READ;
if (flags & write_flag)
access_mask |= GENERIC_WRITE;
TORRENT_ASSERT(access_mask & (GENERIC_READ | GENERIC_WRITE));
#ifdef UNICODE
std::wstring wfile_name(safe_convert(file_name));
HANDLE new_handle = CreateFile(
wfile_name.c_str()
, access_mask
, FILE_SHARE_READ
, 0
, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
#else
HANDLE new_handle = CreateFile(
utf8_native(file_name).c_str()
, access_mask
, FILE_SHARE_READ
, 0
, (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
#endif
if (new_handle == INVALID_HANDLE_VALUE)
{
set_error(file_name);
return false;
}
// try to make the file sparse if supported
if (access_mask & GENERIC_WRITE)
{
DWORD temp;
::DeviceIoControl(new_handle, FSCTL_SET_SPARSE, 0, 0
, 0, 0, &temp, 0);
}
// will only close old file if the open succeeded
close();
m_file_handle = new_handle;
return true;
}
void close()
{
if (m_file_handle != INVALID_HANDLE_VALUE)
{
CloseHandle(m_file_handle);
m_file_handle = INVALID_HANDLE_VALUE;
}
}
~impl()
{
close();
}
size_type write(const char* buffer, size_type num_bytes)
{
TORRENT_ASSERT(buffer);
TORRENT_ASSERT((DWORD)num_bytes == num_bytes);
DWORD bytes_written = 0;
if (num_bytes != 0)
{
if (FALSE == WriteFile(
m_file_handle
, buffer
, (DWORD)num_bytes
, &bytes_written
, 0))
{
set_error("file::write");
return -1;
}
}
return bytes_written;
}
size_type read(char* buffer, size_type num_bytes)
{
TORRENT_ASSERT(buffer);
TORRENT_ASSERT(num_bytes >= 0);
TORRENT_ASSERT((DWORD)num_bytes == num_bytes);
DWORD bytes_read = 0;
if (num_bytes != 0)
{
if (FALSE == ReadFile(
m_file_handle
, buffer
, (DWORD)num_bytes
, &bytes_read
, 0))
{
set_error("file::set_size");
return -1;
}
}
return bytes_read;
}
bool set_size(size_type s)
{
size_type pos = tell();
seek(s, seek_begin);
if (FALSE == ::SetEndOfFile(m_file_handle))
{
set_error("file::set_size");
return false;
}
return true;
}
size_type seek(size_type pos, seek_mode from_where)
{
TORRENT_ASSERT(pos >= 0 || from_where != seek_begin);
TORRENT_ASSERT(pos <= 0 || from_where != seek_end);
LARGE_INTEGER offs;
offs.QuadPart = pos;
if (FALSE == SetFilePointerEx(
m_file_handle
, offs
, &offs
, from_where))
{
set_error("file::seek");
return -1;
}
return offs.QuadPart;
}
size_type tell()
{
LARGE_INTEGER offs;
offs.QuadPart = 0;
// is there any other way to get offset?
if (FALSE == SetFilePointerEx(
m_file_handle
, offs
, &offs
, FILE_CURRENT))
{
set_error("file::tell");
return -1;
}
size_type pos = offs.QuadPart;
TORRENT_ASSERT(pos >= 0);
return pos;
}
/*
size_type size()
{
LARGE_INTEGER s;
if (FALSE == GetFileSizeEx(m_file_handle, &s))
{
throw_exception("file::size");
}
size_type size = s.QuadPart;
TORRENT_ASSERT(size >= 0);
return size;
}
*/
std::string const& error() const
{
if (!m_error) m_error.reset(new std::string);
return *m_error;
}
private:
HANDLE m_file_handle;
mutable boost::scoped_ptr<std::string> m_error;
};
}
namespace libtorrent
{
const file::seek_mode file::begin(file::impl::seek_begin);
const file::seek_mode file::end(file::impl::seek_end);
const file::open_mode file::in(file::impl::read_flag);
const file::open_mode file::out(file::impl::write_flag);
file::file()
: m_impl(new libtorrent::file::impl())
{
}
file::file(boost::filesystem::path const& p, open_mode m)
: m_impl(new libtorrent::file::impl())
{
open(p,m);
}
file::~file()
{
}
bool file::open(boost::filesystem::path const& p, open_mode m)
{
TORRENT_ASSERT(p.is_complete());
return m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask));
}
void file::close()
{
m_impl->close();
}
size_type file::write(const char* buffer, size_type num_bytes)
{
return m_impl->write(buffer, num_bytes);
}
size_type file::read(char* buffer, size_type num_bytes)
{
return m_impl->read(buffer, num_bytes);
}
bool file::set_size(size_type s)
{
return m_impl->set_size(s);
}
size_type file::seek(size_type pos, seek_mode m)
{
return m_impl->seek(pos,impl::seek_mode(m.m_val));
}
size_type file::tell()
{
return m_impl->tell();
}
std::string const& file::error() const
{
return m_impl->error();
}
}

View File

@ -260,6 +260,13 @@ namespace libtorrent
return e->string_value(); return e->string_value();
} }
lazy_entry const* lazy_entry::dict_find_string(char const* name) const
{
lazy_entry const* e = dict_find(name);
if (e == 0 || e->type() != lazy_entry::string_t) return 0;
return e;
}
size_type lazy_entry::dict_find_int_value(char const* name, size_type default_val) const size_type lazy_entry::dict_find_int_value(char const* name, size_type default_val) const
{ {
lazy_entry const* e = dict_find(name); lazy_entry const* e = dict_find(name);
@ -359,7 +366,7 @@ namespace libtorrent
switch (e.type()) switch (e.type())
{ {
case lazy_entry::none_t: return os << "none"; case lazy_entry::none_t: return os << "none";
case lazy_entry::int_t: return os << e.int_value(); case lazy_entry::int_t: return os << std::dec << std::setw(0) << e.int_value();
case lazy_entry::string_t: case lazy_entry::string_t:
{ {
bool printable = true; bool printable = true;
@ -374,7 +381,8 @@ namespace libtorrent
os << "'"; os << "'";
if (printable) return os << e.string_value() << "'"; if (printable) return os << e.string_value() << "'";
for (int i = 0; i < e.string_length(); ++i) for (int i = 0; i < e.string_length(); ++i)
os << std::hex << int((unsigned char)(str[i])); os << std::hex << std::setfill('0') << std::setw(2)
<< int((unsigned char)(str[i]));
return os << "'"; return os << "'";
} }
case lazy_entry::list_t: case lazy_entry::list_t:

View File

@ -129,8 +129,10 @@ namespace libtorrent
, m_request_large_blocks(false) , m_request_large_blocks(false)
, m_upload_only(false) , m_upload_only(false)
, m_snubbed(false) , m_snubbed(false)
, m_bitfield_received(false)
#ifndef NDEBUG #ifndef NDEBUG
, m_in_constructor(true) , m_in_constructor(true)
, m_disconnect_started(false)
#endif #endif
{ {
m_channel_state[upload_channel] = peer_info::bw_idle; m_channel_state[upload_channel] = peer_info::bw_idle;
@ -232,8 +234,10 @@ namespace libtorrent
, m_request_large_blocks(false) , m_request_large_blocks(false)
, m_upload_only(false) , m_upload_only(false)
, m_snubbed(false) , m_snubbed(false)
, m_bitfield_received(false)
#ifndef NDEBUG #ifndef NDEBUG
, m_in_constructor(true) , m_in_constructor(true)
, m_disconnect_started(false)
#endif #endif
{ {
m_channel_state[upload_channel] = peer_info::bw_idle; m_channel_state[upload_channel] = peer_info::bw_idle;
@ -328,8 +332,6 @@ namespace libtorrent
void peer_connection::update_interest() void peer_connection::update_interest()
{ {
INVARIANT_CHECK;
boost::shared_ptr<torrent> t = m_torrent.lock(); boost::shared_ptr<torrent> t = m_torrent.lock();
TORRENT_ASSERT(t); TORRENT_ASSERT(t);
@ -351,10 +353,8 @@ namespace libtorrent
} }
try try
{ {
if (!interested) if (!interested) send_not_interested();
send_not_interested(); else t->get_policy().peer_is_interesting(*this);
else
t->get_policy().peer_is_interesting(*this);
} }
// may throw an asio error if socket has disconnected // may throw an asio error if socket has disconnected
catch (std::exception&) {} catch (std::exception&) {}
@ -455,15 +455,10 @@ namespace libtorrent
#endif #endif
// if this is a web seed. we don't have a peer_info struct // if this is a web seed. we don't have a peer_info struct
if (m_peer_info) m_peer_info->seed = true; if (m_peer_info) m_peer_info->seed = true;
// if we're a seed too, disconnect
if (t->is_finished() && m_ses.settings().close_redundant_connections)
{
disconnect("seed to seed connection redundant");
return;
}
t->peer_has_all(); t->peer_has_all();
if (!t->is_finished()) if (t->is_finished()) send_not_interested();
t->get_policy().peer_is_interesting(*this); else t->get_policy().peer_is_interesting(*this);
return; return;
} }
@ -482,8 +477,12 @@ namespace libtorrent
interesting = true; interesting = true;
} }
} }
if (interesting) if (interesting) t->get_policy().peer_is_interesting(*this);
t->get_policy().peer_is_interesting(*this); else send_not_interested();
}
else
{
update_interest();
} }
} }
@ -492,6 +491,7 @@ namespace libtorrent
// INVARIANT_CHECK; // INVARIANT_CHECK;
TORRENT_ASSERT(!m_in_constructor); TORRENT_ASSERT(!m_in_constructor);
TORRENT_ASSERT(m_disconnecting); TORRENT_ASSERT(m_disconnecting);
TORRENT_ASSERT(m_disconnect_started);
m_disk_recv_buffer_size = 0; m_disk_recv_buffer_size = 0;
@ -535,10 +535,18 @@ namespace libtorrent
m_suggested_pieces.begin(), m_suggested_pieces.end(), index); m_suggested_pieces.begin(), m_suggested_pieces.end(), index);
if (i != m_suggested_pieces.end()) m_suggested_pieces.erase(i); if (i != m_suggested_pieces.end()) m_suggested_pieces.erase(i);
if (has_piece(index))
{
// if we got a piece that this peer has
// it might have been the last interesting
// piece this peer had. We might not be
// interested anymore
update_interest();
if (is_disconnecting()) return;
// optimization, don't send have messages // optimization, don't send have messages
// to peers that already have the piece // to peers that already have the piece
if (!m_ses.settings().send_redundant_have if (!m_ses.settings().send_redundant_have)
&& has_piece(index))
{ {
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() (*m_logger) << time_now_string()
@ -546,6 +554,7 @@ namespace libtorrent
#endif #endif
return; return;
} }
}
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() (*m_logger) << time_now_string()
@ -561,8 +570,6 @@ namespace libtorrent
bool peer_connection::has_piece(int i) const bool peer_connection::has_piece(int i) const
{ {
INVARIANT_CHECK;
boost::shared_ptr<torrent> t = m_torrent.lock(); boost::shared_ptr<torrent> t = m_torrent.lock();
TORRENT_ASSERT(t); TORRENT_ASSERT(t);
TORRENT_ASSERT(t->valid_metadata()); TORRENT_ASSERT(t->valid_metadata());
@ -1055,6 +1062,10 @@ namespace libtorrent
if (is_disconnecting()) return; if (is_disconnecting()) return;
// if we haven't received a bitfield, it was
// probably omitted, which is the same as 'have_none'
if (!m_bitfield_received) incoming_have_none();
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() (*m_logger) << time_now_string()
<< " <== HAVE [ piece: " << index << "]\n"; << " <== HAVE [ piece: " << index << "]\n";
@ -1121,15 +1132,12 @@ namespace libtorrent
} }
} }
if (upload_only()) if (is_seed())
{ {
TORRENT_ASSERT(m_peer_info); m_peer_info->seed = true;
if (is_seed()) m_peer_info->seed = true; m_upload_only = true;
if (t->is_finished() && m_ses.settings().close_redundant_connections) disconnect_if_redundant();
{ if (is_disconnecting()) return;
disconnect("seed to seed connection redundant");
return;
}
} }
} }
} }
@ -1179,6 +1187,8 @@ namespace libtorrent
return; return;
} }
m_bitfield_received = true;
// if we don't have metadata yet // if we don't have metadata yet
// just remember the bitmask // just remember the bitmask
// don't update the piecepicker // don't update the piecepicker
@ -1201,12 +1211,9 @@ namespace libtorrent
#endif #endif
// if this is a web seed. we don't have a peer_info struct // if this is a web seed. we don't have a peer_info struct
if (m_peer_info) m_peer_info->seed = true; if (m_peer_info) m_peer_info->seed = true;
// if we're a seed too, disconnect m_upload_only = true;
if (t->is_finished() && m_ses.settings().close_redundant_connections) disconnect_if_redundant();
{ if (is_disconnecting()) return;
disconnect("seed to seed connection redundant, disconnecting");
return;
}
m_have_piece.set_all(); m_have_piece.set_all();
m_num_pieces = num_pieces; m_num_pieces = num_pieces;
@ -1247,6 +1254,22 @@ namespace libtorrent
else if (upload_only()) disconnect("upload to upload connections"); else if (upload_only()) disconnect("upload to upload connections");
} }
void peer_connection::disconnect_if_redundant()
{
if (!m_ses.settings().close_redundant_connections) return;
boost::shared_ptr<torrent> t = m_torrent.lock();
TORRENT_ASSERT(t);
if (m_upload_only && t->is_finished())
disconnect("seed to seed");
if (m_upload_only
&& !m_interesting
&& m_bitfield_received
&& t->are_files_checked())
disconnect("uninteresting upload-only peer");
}
// ----------------------------- // -----------------------------
// ---------- REQUEST ---------- // ---------- REQUEST ----------
// ----------------------------- // -----------------------------
@ -1258,6 +1281,10 @@ namespace libtorrent
boost::shared_ptr<torrent> t = m_torrent.lock(); boost::shared_ptr<torrent> t = m_torrent.lock();
TORRENT_ASSERT(t); TORRENT_ASSERT(t);
// if we haven't received a bitfield, it was
// probably omitted, which is the same as 'have_none'
if (!m_bitfield_received) incoming_have_none();
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin() for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i) , end(m_extensions.end()); i != end; ++i)
@ -1460,6 +1487,10 @@ namespace libtorrent
} }
#endif #endif
// if we haven't received a bitfield, it was
// probably omitted, which is the same as 'have_none'
if (!m_bitfield_received) incoming_have_none();
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin() for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i) , end(m_extensions.end()); i != end; ++i)
@ -1797,6 +1828,12 @@ namespace libtorrent
m_have_all = true; m_have_all = true;
if (m_peer_info) m_peer_info->seed = true; if (m_peer_info) m_peer_info->seed = true;
m_upload_only = true;
m_bitfield_received = true;
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << " *** THIS IS A SEED ***\n";
#endif
// if we don't have metadata yet // if we don't have metadata yet
// just remember the bitmask // just remember the bitmask
@ -1804,30 +1841,24 @@ namespace libtorrent
// (since it doesn't exist yet) // (since it doesn't exist yet)
if (!t->ready_for_connections()) if (!t->ready_for_connections())
{ {
disconnect_if_redundant();
// TODO: this might need something more // TODO: this might need something more
// so that once we have the metadata // so that once we have the metadata
// we can construct a full bitfield // we can construct a full bitfield
return; return;
} }
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << " *** THIS IS A SEED ***\n";
#endif
// if we're a seed too, disconnect
if (t->is_finished() && m_ses.settings().close_redundant_connections)
{
disconnect("seed to seed connection redundant, disconnecting");
return;
}
TORRENT_ASSERT(!m_have_piece.empty()); TORRENT_ASSERT(!m_have_piece.empty());
m_have_piece.set_all(); m_have_piece.set_all();
m_num_pieces = m_have_piece.size(); m_num_pieces = m_have_piece.size();
t->peer_has_all(); t->peer_has_all();
if (!t->is_finished())
t->get_policy().peer_is_interesting(*this); // if we're finished, we're not interested
if (t->is_finished()) send_not_interested();
else t->get_policy().peer_is_interesting(*this);
disconnect_if_redundant();
} }
// ----------------------------- // -----------------------------
@ -1854,8 +1885,13 @@ namespace libtorrent
#endif #endif
if (is_disconnecting()) return; if (is_disconnecting()) return;
if (m_peer_info) m_peer_info->seed = false; if (m_peer_info) m_peer_info->seed = false;
m_bitfield_received = true;
// we're never interested in a peer that doesn't have anything
send_not_interested();
TORRENT_ASSERT(!m_have_piece.empty() || !t->ready_for_connections()); TORRENT_ASSERT(!m_have_piece.empty() || !t->ready_for_connections());
disconnect_if_redundant();
} }
// ----------------------------- // -----------------------------
@ -2090,11 +2126,9 @@ namespace libtorrent
void peer_connection::send_interested() void peer_connection::send_interested()
{ {
INVARIANT_CHECK;
if (m_interesting) return; if (m_interesting) return;
write_interested();
m_interesting = true; m_interesting = true;
write_interested();
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() << " ==> INTERESTED\n"; (*m_logger) << time_now_string() << " ==> INTERESTED\n";
@ -2103,17 +2137,16 @@ namespace libtorrent
void peer_connection::send_not_interested() void peer_connection::send_not_interested()
{ {
INVARIANT_CHECK;
if (!m_interesting) return; if (!m_interesting) return;
write_not_interested();
m_interesting = false; m_interesting = false;
write_not_interested();
m_became_uninteresting = time_now(); m_became_uninteresting = time_now();
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() << " ==> NOT_INTERESTED\n"; (*m_logger) << time_now_string() << " ==> NOT_INTERESTED\n";
#endif #endif
disconnect_if_redundant();
} }
void peer_connection::send_block_requests() void peer_connection::send_block_requests()
@ -2238,7 +2271,6 @@ namespace libtorrent
void peer_connection::timed_out() void peer_connection::timed_out()
{ {
TORRENT_ASSERT(m_connecting); TORRENT_ASSERT(m_connecting);
TORRENT_ASSERT(m_connection_ticket >= 0);
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
(*m_ses.m_logger) << time_now_string() << " CONNECTION TIMED OUT: " << m_remote.address().to_string() (*m_ses.m_logger) << time_now_string() << " CONNECTION TIMED OUT: " << m_remote.address().to_string()
<< "\n"; << "\n";
@ -2253,6 +2285,10 @@ namespace libtorrent
{ {
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
#ifndef NDEBUG
m_disconnect_started = true;
#endif
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
switch (error) switch (error)
{ {
@ -2461,6 +2497,7 @@ namespace libtorrent
p.flags |= is_seed() ? peer_info::seed : 0; p.flags |= is_seed() ? peer_info::seed : 0;
p.flags |= m_snubbed ? peer_info::snubbed : 0; p.flags |= m_snubbed ? peer_info::snubbed : 0;
p.flags |= m_upload_only ? peer_info::upload_only : 0;
if (peer_info_struct()) if (peer_info_struct())
{ {
policy::peer* pi = peer_info_struct(); policy::peer* pi = peer_info_struct();
@ -2979,8 +3016,6 @@ namespace libtorrent
{ {
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
INVARIANT_CHECK;
if (m_channel_state[upload_channel] != peer_info::bw_idle) return; if (m_channel_state[upload_channel] != peer_info::bw_idle) return;
shared_ptr<torrent> t = m_torrent.lock(); shared_ptr<torrent> t = m_torrent.lock();
@ -3388,8 +3423,6 @@ namespace libtorrent
bool peer_connection::can_write() const bool peer_connection::can_write() const
{ {
INVARIANT_CHECK;
// if we have requests or pending data to be sent or announcements to be made // if we have requests or pending data to be sent or announcements to be made
// we want to send data // we want to send data
return !m_send_buffer.empty() return !m_send_buffer.empty()
@ -3400,8 +3433,6 @@ namespace libtorrent
bool peer_connection::can_read() const bool peer_connection::can_read() const
{ {
INVARIANT_CHECK;
bool ret = (m_bandwidth_limit[download_channel].quota_left() > 0 bool ret = (m_bandwidth_limit[download_channel].quota_left() > 0
|| m_ignore_bandwidth_limits) || m_ignore_bandwidth_limits)
&& !m_connecting && !m_connecting
@ -3585,6 +3616,7 @@ namespace libtorrent
if (m_disconnecting) if (m_disconnecting)
{ {
TORRENT_ASSERT(!t); TORRENT_ASSERT(!t);
TORRENT_ASSERT(m_disconnect_started);
} }
else if (!m_in_constructor) else if (!m_in_constructor)
{ {
@ -3634,6 +3666,23 @@ namespace libtorrent
return; return;
} }
if (m_ses.settings().close_redundant_connections)
{
// make sure upload only peers are disconnected
if (t->is_finished() && m_upload_only)
TORRENT_ASSERT(m_disconnect_started);
if (m_upload_only
&& !m_interesting
&& m_bitfield_received
&& t->are_files_checked())
TORRENT_ASSERT(m_disconnect_started);
}
if (t->is_finished())
TORRENT_ASSERT(!m_interesting);
if (is_seed())
TORRENT_ASSERT(m_upload_only);
if (t->has_picker()) if (t->has_picker())
{ {
std::map<piece_block, int> num_requests; std::map<piece_block, int> num_requests;

View File

@ -1088,6 +1088,8 @@ namespace aux {
// -------------------------------------------------------------- // --------------------------------------------------------------
// scrape paused torrents that are auto managed // scrape paused torrents that are auto managed
// -------------------------------------------------------------- // --------------------------------------------------------------
if (!is_paused())
{
--m_auto_scrape_time_scaler; --m_auto_scrape_time_scaler;
if (m_auto_scrape_time_scaler <= 0) if (m_auto_scrape_time_scaler <= 0)
{ {
@ -1101,6 +1103,7 @@ namespace aux {
least_recently_scraped->second->scrape_tracker(); least_recently_scraped->second->scrape_tracker();
} }
} }
}
// -------------------------------------------------------------- // --------------------------------------------------------------
// connect new peers // connect new peers

View File

@ -253,20 +253,20 @@ namespace
namespace libtorrent namespace libtorrent
{ {
template <class Path> template <class Path>
void recursive_copy(Path const& old_path, Path const& new_path, std::string& error) void recursive_copy(Path const& old_path, Path const& new_path, error_code& ec)
{ {
using boost::filesystem::basic_directory_iterator; using boost::filesystem::basic_directory_iterator;
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
try { try {
#endif #endif
TORRENT_ASSERT(error.empty()); TORRENT_ASSERT(!ec);
if (is_directory(old_path)) if (is_directory(old_path))
{ {
create_directory(new_path); create_directory(new_path);
for (basic_directory_iterator<Path> i(old_path), end; i != end; ++i) for (basic_directory_iterator<Path> i(old_path), end; i != end; ++i)
{ {
recursive_copy(i->path(), new_path / i->leaf(), error); recursive_copy(i->path(), new_path / i->leaf(), ec);
if (!error.empty()) return; if (ec) return;
} }
} }
else else
@ -274,7 +274,7 @@ namespace libtorrent
copy_file(old_path, new_path); copy_file(old_path, new_path);
} }
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
} catch (std::exception& e) { error = e.what(); } } catch (std::exception& e) { ec = error_code(errno, get_posix_category()); }
#endif #endif
} }
@ -436,6 +436,7 @@ namespace libtorrent
boost::scoped_ptr<file_storage> m_mapped_files; boost::scoped_ptr<file_storage> m_mapped_files;
file_storage const& m_files; file_storage const& m_files;
std::vector<boost::uint8_t> m_file_priority;
fs::path m_save_path; fs::path m_save_path;
// the file pool is typically stored in // the file pool is typically stored in
// the session, to make all storage // the session, to make all storage
@ -478,6 +479,7 @@ namespace libtorrent
bool storage::initialize(bool allocate_files) bool storage::initialize(bool allocate_files)
{ {
error_code ec;
// first, create all missing directories // first, create all missing directories
fs::path last_path; fs::path last_path;
for (file_storage::iterator file_iter = files().begin(), for (file_storage::iterator file_iter = files().begin(),
@ -508,42 +510,44 @@ namespace libtorrent
// the directory exists. // the directory exists.
if (file_iter->size == 0) if (file_iter->size == 0)
{ {
#ifndef BOOST_NO_EXCEPTIONS file(m_save_path / file_iter->path, file::out, ec);
try { if (ec)
#endif
file(m_save_path / file_iter->path, file::out);
#ifndef BOOST_NO_EXCEPTIONS
}
catch (std::exception& e)
{ {
set_error((m_save_path / file_iter->path).string(), e.what()); set_error(m_save_path / file_iter->path, ec);
return true; return true;
} }
#endif
continue; continue;
} }
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
try { try {
#endif #endif
if (allocate_files) // don't allocate files with priority 0
int file_index = file_iter - files().begin();
if (allocate_files && (m_file_priority.size() <= file_index
|| m_file_priority[file_index] > 0))
{ {
std::string error; error_code ec;
boost::shared_ptr<file> f = m_pool.open_file(this boost::shared_ptr<file> f = m_pool.open_file(this
, m_save_path / file_iter->path, file::in | file::out , m_save_path / file_iter->path, file::in | file::out, ec);
, error); if (ec) set_error(m_save_path / file_iter->path, ec);
if (f && f->error().empty()) else if (f)
f->set_size(file_iter->size); {
f->set_size(file_iter->size, ec);
if (ec) set_error(m_save_path / file_iter->path, ec);
}
} }
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
} }
catch (std::exception& e) catch (std::exception& e)
{ {
set_error((m_save_path / file_iter->path).string(), e.what()); set_error(m_save_path / file_iter->path
, error_code(errno, get_posix_category()));
return true; return true;
} }
#endif #endif
} }
std::vector<boost::uint8_t>().swap(m_file_priority);
// close files that were opened in write mode // close files that were opened in write mode
m_pool.release(this); m_pool.release(this);
return false; return false;
@ -568,6 +572,15 @@ namespace libtorrent
{ {
#endif #endif
rename(old_path, new_path); rename(old_path, new_path);
/*
error_code ec;
rename(old_path, new_path, ec);
if (ec)
{
set_error(old_path, ec);
return;
}
*/
if (!m_mapped_files) if (!m_mapped_files)
{ m_mapped_files.reset(new file_storage(m_files)); } { m_mapped_files.reset(new file_storage(m_files)); }
m_mapped_files->rename_file(index, new_filename); m_mapped_files->rename_file(index, new_filename);
@ -575,7 +588,7 @@ namespace libtorrent
} }
catch (std::exception& e) catch (std::exception& e)
{ {
set_error(old_name.string(), e.what()); set_error(old_name, error_code(errno, get_posix_category()));
return true; return true;
} }
#endif #endif
@ -595,8 +608,7 @@ namespace libtorrent
m_pool.release(this); m_pool.release(this);
buffer().swap(m_scratch_buffer); buffer().swap(m_scratch_buffer);
int result = 0; int error = 0;
std::string error;
std::string error_file; std::string error_file;
// delete the files from disk // delete the files from disk
@ -619,16 +631,14 @@ namespace libtorrent
{ fs::remove(safe_convert(p)); } { fs::remove(safe_convert(p)); }
catch (std::exception& e) catch (std::exception& e)
{ {
error = e.what(); error = errno;
error_file = p; error_file = p;
result = 1;
} }
#else #else
if (std::remove(p.c_str()) != 0 && errno != ENOENT) if (std::remove(p.c_str()) != 0 && errno != ENOENT)
{ {
error = std::strerror(errno); error = errno;
error_file = p; error_file = p;
result = errno;
} }
#endif #endif
} }
@ -644,26 +654,25 @@ namespace libtorrent
{ fs::remove(safe_convert(*i)); } { fs::remove(safe_convert(*i)); }
catch (std::exception& e) catch (std::exception& e)
{ {
error = e.what(); error = errno;
error_file = *i; error_file = *i;
result = 1;
} }
#else #else
if (std::remove(i->c_str()) != 0 && errno != ENOENT) if (std::remove(i->c_str()) != 0 && errno != ENOENT)
{ {
error = std::strerror(errno); error = errno;
error_file = *i; error_file = *i;
result = errno;
} }
#endif #endif
} }
if (!error.empty()) if (error)
{ {
m_error.swap(error); m_error = error_code(error, get_posix_category());
m_error_file.swap(error_file); m_error_file.swap(error_file);
return true;
} }
return result != 0; return false;
} }
bool storage::write_resume_data(entry& rd) const bool storage::write_resume_data(entry& rd) const
@ -682,15 +691,38 @@ namespace libtorrent
p.push_back(entry(i->second)); p.push_back(entry(i->second));
fl.push_back(entry(p)); fl.push_back(entry(p));
} }
if (m_mapped_files)
{
entry::list_type& fl = rd["mapped_files"].list();
for (file_storage::iterator i = m_mapped_files->begin()
, end(m_mapped_files->end()); i != end; ++i)
{
fl.push_back(i->path.string());
}
}
return false; return false;
} }
bool storage::verify_resume_data(lazy_entry const& rd, std::string& error) bool storage::verify_resume_data(lazy_entry const& rd, std::string& error)
{ {
if (rd.type() != lazy_entry::dict_t) lazy_entry const* file_priority = rd.dict_find_list("file_priority");
if (file_priority && file_priority->list_size()
== files().num_files())
{ {
error = "invalid fastresume file (not a dictionary)"; m_file_priority.resize(file_priority->list_size());
return true; for (int i = 0; i < file_priority->list_size(); ++i)
m_file_priority[i] = file_priority->list_int_value_at(i, 1);
}
lazy_entry const* mapped_files = rd.dict_find_list("mapped_files");
if (mapped_files && mapped_files->list_size() == m_files.num_files())
{
if (!m_mapped_files)
{ m_mapped_files.reset(new file_storage(m_files)); }
for (int i = 0; i < m_files.num_files(); ++i)
m_mapped_files->rename_file(i, mapped_files->list_string_value_at(i));
} }
std::vector<std::pair<size_type, std::time_t> > file_sizes; std::vector<std::pair<size_type, std::time_t> > file_sizes;
@ -719,18 +751,14 @@ namespace libtorrent
return false; return false;
} }
lazy_entry const* slots = rd.dict_find_list("slots");
if (slots == 0)
{
error = "missing or invalid 'slots' entry in resume data";
return false;
}
bool seed = false; bool seed = false;
lazy_entry const* slots = rd.dict_find_list("slots");
if (slots)
{
if (int(slots->list_size()) == m_files.num_pieces()) if (int(slots->list_size()) == m_files.num_pieces())
{ {
bool seed = true; seed = true;
for (int i = 0; i < slots->list_size(); ++i) for (int i = 0; i < slots->list_size(); ++i)
{ {
lazy_entry const* e = slots->list_at(i); lazy_entry const* e = slots->list_at(i);
@ -739,9 +767,29 @@ namespace libtorrent
break; break;
} }
} }
}
else if (lazy_entry const* pieces = rd.dict_find_string("pieces"))
{
if (int(pieces->string_length()) == m_files.num_pieces())
{
seed = true;
char const* p = pieces->string_ptr();
for (int i = 0; i < pieces->string_length(); ++i)
{
if ((p[i] & 1) == 1) continue;
seed = false;
break;
}
}
}
else
{
error = "missing 'slots' and 'pieces' entry in resume data";
return false;
}
bool full_allocation_mode = false; bool full_allocation_mode = false;
if (rd.dict_find_string_value("allocation") == "full") if (rd.dict_find_string_value("allocation") != "compact")
full_allocation_mode = true; full_allocation_mode = true;
if (seed) if (seed)
@ -832,11 +880,11 @@ namespace libtorrent
} }
catch (std::exception& e) catch (std::exception& e)
{ {
std::string err; error_code ec;
recursive_copy(old_path, new_path, err); recursive_copy(old_path, new_path, ec);
if (!err.empty()) if (ec)
{ {
set_error((m_save_path / files().name()).string(), e.what()); set_error(m_save_path / files().name(), ec);
return true; return true;
} }
m_save_path = save_path; m_save_path = save_path;
@ -964,30 +1012,24 @@ namespace libtorrent
} }
int buf_pos = 0; int buf_pos = 0;
std::string error; error_code ec;
boost::shared_ptr<file> in(m_pool.open_file( boost::shared_ptr<file> in(m_pool.open_file(
this, m_save_path / file_iter->path, file::in this, m_save_path / file_iter->path, file::in, ec));
, error)); if (!in || ec)
if (!in)
{ {
set_error((m_save_path / file_iter->path).string(), error); set_error(m_save_path / file_iter->path, ec);
return -1;
}
if (!in->error().empty())
{
set_error((m_save_path / file_iter->path).string(), in->error());
return -1; return -1;
} }
TORRENT_ASSERT(file_offset < file_iter->size); TORRENT_ASSERT(file_offset < file_iter->size);
TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base); TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base);
size_type new_pos = in->seek(file_offset + file_iter->file_base); size_type new_pos = in->seek(file_offset + file_iter->file_base, file::begin, ec);
if (new_pos != file_offset + file_iter->file_base) if (new_pos != file_offset + file_iter->file_base || ec)
{ {
// the file was not big enough // the file was not big enough
if (!fill_zero) if (!fill_zero)
{ {
set_error((m_save_path / file_iter->path).string(), "seek failed"); set_error(m_save_path / file_iter->path, ec);
return -1; return -1;
} }
std::memset(buf + buf_pos, 0, size - buf_pos); std::memset(buf + buf_pos, 0, size - buf_pos);
@ -995,8 +1037,8 @@ namespace libtorrent
} }
#ifndef NDEBUG #ifndef NDEBUG
size_type in_tell = in->tell(); size_type in_tell = in->tell(ec);
TORRENT_ASSERT(in_tell == file_offset + file_iter->file_base); TORRENT_ASSERT(in_tell == file_offset + file_iter->file_base && !ec);
#endif #endif
int left_to_read = size; int left_to_read = size;
@ -1029,15 +1071,15 @@ namespace libtorrent
== file_iter->path); == file_iter->path);
#endif #endif
int actual_read = int(in->read(buf + buf_pos, read_bytes)); int actual_read = int(in->read(buf + buf_pos, read_bytes, ec));
if (read_bytes != actual_read) if (read_bytes != actual_read || ec)
{ {
// the file was not big enough // the file was not big enough
if (actual_read > 0) buf_pos += actual_read; if (actual_read > 0) buf_pos += actual_read;
if (!fill_zero) if (!fill_zero)
{ {
set_error((m_save_path / file_iter->path).string(), "read failed"); set_error(m_save_path / file_iter->path, ec);
return -1; return -1;
} }
std::memset(buf + buf_pos, 0, size - buf_pos); std::memset(buf + buf_pos, 0, size - buf_pos);
@ -1061,25 +1103,19 @@ namespace libtorrent
fs::path path = m_save_path / file_iter->path; fs::path path = m_save_path / file_iter->path;
file_offset = 0; file_offset = 0;
std::string error; error_code ec;
in = m_pool.open_file( in = m_pool.open_file( this, path, file::in, ec);
this, path, file::in, error); if (!in || ec)
if (!in)
{ {
set_error(path.string(), error); set_error(path, ec);
return -1; return -1;
} }
if (!in->error().empty()) size_type pos = in->seek(file_iter->file_base, file::begin, ec);
{ if (pos != file_iter->file_base || ec)
set_error((m_save_path / file_iter->path).string(), in->error());
return -1;
}
size_type pos = in->seek(file_iter->file_base);
if (pos != file_iter->file_base)
{ {
if (!fill_zero) if (!fill_zero)
{ {
set_error((m_save_path / file_iter->path).string(), "seek failed"); set_error(m_save_path / file_iter->path, ec);
return -1; return -1;
} }
std::memset(buf + buf_pos, 0, size - buf_pos); std::memset(buf + buf_pos, 0, size - buf_pos);
@ -1125,28 +1161,23 @@ namespace libtorrent
} }
fs::path p(m_save_path / file_iter->path); fs::path p(m_save_path / file_iter->path);
std::string error; error_code ec;
boost::shared_ptr<file> out = m_pool.open_file( boost::shared_ptr<file> out = m_pool.open_file(
this, p, file::out | file::in, error); this, p, file::out | file::in, ec);
if (!out) if (!out || ec)
{ {
set_error(p.string(), error); set_error(p, ec);
return -1;
}
if (!out->error().empty())
{
set_error(p.string(), out->error());
return -1; return -1;
} }
TORRENT_ASSERT(file_offset < file_iter->size); TORRENT_ASSERT(file_offset < file_iter->size);
TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base); TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base);
size_type pos = out->seek(file_offset + file_iter->file_base); size_type pos = out->seek(file_offset + file_iter->file_base, file::begin, ec);
if (pos != file_offset + file_iter->file_base) if (pos != file_offset + file_iter->file_base || ec)
{ {
set_error((m_save_path / file_iter->path).string(), "seek failed"); set_error(p, ec);
return -1; return -1;
} }
@ -1180,11 +1211,12 @@ namespace libtorrent
TORRENT_ASSERT(buf_pos >= 0); TORRENT_ASSERT(buf_pos >= 0);
TORRENT_ASSERT(write_bytes >= 0); TORRENT_ASSERT(write_bytes >= 0);
size_type written = out->write(buf + buf_pos, write_bytes); error_code ec;
size_type written = out->write(buf + buf_pos, write_bytes, ec);
if (written != write_bytes) if (written != write_bytes || ec)
{ {
set_error((m_save_path / file_iter->path).string(), "write failed"); set_error(m_save_path / file_iter->path, ec);
return -1; return -1;
} }
@ -1205,26 +1237,21 @@ namespace libtorrent
TORRENT_ASSERT(file_iter != files().end()); TORRENT_ASSERT(file_iter != files().end());
fs::path p = m_save_path / file_iter->path; fs::path p = m_save_path / file_iter->path;
file_offset = 0; file_offset = 0;
std::string error; error_code ec;
out = m_pool.open_file( out = m_pool.open_file(
this, p, file::out | file::in, error); this, p, file::out | file::in, ec);
if (!out) if (!out || ec)
{ {
set_error(p.string(), error); set_error(p, ec);
return -1;
}
if (!out->error().empty())
{
set_error(p.string(), out->error());
return -1; return -1;
} }
size_type pos = out->seek(file_iter->file_base); size_type pos = out->seek(file_iter->file_base, file::begin, ec);
if (pos != file_iter->file_base) if (pos != file_iter->file_base || ec)
{ {
set_error((m_save_path / file_iter->path).string(), "seek failed"); set_error(p, ec);
return -1; return -1;
} }
} }
@ -1276,6 +1303,15 @@ namespace libtorrent
m_io_thread.add_job(j, handler); m_io_thread.add_job(j, handler);
} }
void piece_manager::async_clear_read_cache(
boost::function<void(int, disk_io_job const&)> const& handler)
{
disk_io_job j;
j.storage = this;
j.action = disk_io_job::clear_read_cache;
m_io_thread.add_job(j, handler);
}
void piece_manager::async_release_files( void piece_manager::async_release_files(
boost::function<void(int, disk_io_job const&)> const& handler) boost::function<void(int, disk_io_job const&)> const& handler)
{ {
@ -1723,6 +1759,7 @@ namespace libtorrent
error = f.string(); error = f.string();
error += ": "; error += ": ";
error += e.what(); error += e.what();
TORRENT_ASSERT(!error.empty());
return fatal_disk_error; return fatal_disk_error;
} }
#endif #endif
@ -1738,6 +1775,7 @@ namespace libtorrent
m_unallocated_slots.clear(); m_unallocated_slots.clear();
m_free_slots.clear(); m_free_slots.clear();
} }
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces());
return need_full_check; return need_full_check;
} }
} }
@ -1762,8 +1800,8 @@ namespace libtorrent
{ {
if (m_storage->initialize(m_storage_mode == storage_mode_allocate)) if (m_storage->initialize(m_storage_mode == storage_mode_allocate))
{ {
error = m_storage->error(); error = m_storage->error().message();
m_storage->clear_error(); TORRENT_ASSERT(!error.empty());
return fatal_disk_error; return fatal_disk_error;
} }
m_state = state_finished; m_state = state_finished;
@ -1817,6 +1855,9 @@ namespace libtorrent
if (rd.dict_find_string_value("allocation") != "compact") if (rd.dict_find_string_value("allocation") != "compact")
storage_mode = storage_mode_sparse; storage_mode = storage_mode_sparse;
if (!m_storage->verify_resume_data(rd, error))
return check_no_fastresume(error);
// assume no piece is out of place (i.e. in a slot // assume no piece is out of place (i.e. in a slot
// other than the one it should be in) // other than the one it should be in)
bool out_of_place = false; bool out_of_place = false;
@ -1902,9 +1943,6 @@ namespace libtorrent
} }
} }
if (!m_storage->verify_resume_data(rd, error))
return check_no_fastresume(error);
// This will corrupt the storage // This will corrupt the storage
// use while debugging to find // use while debugging to find
// states that cannot be scanned // states that cannot be scanned
@ -1927,6 +1965,7 @@ namespace libtorrent
m_state = state_expand_pieces; m_state = state_expand_pieces;
m_current_slot = 0; m_current_slot = 0;
error = "pieces needs to be reordered"; error = "pieces needs to be reordered";
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces());
return need_full_check; return need_full_check;
} }
} }
@ -2021,8 +2060,8 @@ namespace libtorrent
if (m_storage->read(&m_scratch_buffer2[0], piece, 0, piece_size) if (m_storage->read(&m_scratch_buffer2[0], piece, 0, piece_size)
!= piece_size) != piece_size)
{ {
error = m_storage->error(); error = m_storage->error().message();
m_storage->clear_error(); TORRENT_ASSERT(!error.empty());
return fatal_disk_error; return fatal_disk_error;
} }
m_scratch_piece = other_piece; m_scratch_piece = other_piece;
@ -2034,8 +2073,8 @@ namespace libtorrent
int piece_size = m_files.piece_size(piece); int piece_size = m_files.piece_size(piece);
if (m_storage->write(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size) if (m_storage->write(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size)
{ {
error = m_storage->error(); error = m_storage->error().message();
m_storage->clear_error(); TORRENT_ASSERT(!error.empty());
return fatal_disk_error; return fatal_disk_error;
} }
m_piece_to_slot[piece] = piece; m_piece_to_slot[piece] = piece;
@ -2044,6 +2083,7 @@ namespace libtorrent
if (other_piece >= 0) if (other_piece >= 0)
m_scratch_buffer.swap(m_scratch_buffer2); m_scratch_buffer.swap(m_scratch_buffer2);
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces());
return need_full_check; return need_full_check;
} }
@ -2075,8 +2115,8 @@ namespace libtorrent
int piece_size = m_files.piece_size(other_piece); int piece_size = m_files.piece_size(other_piece);
if (m_storage->read(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size) if (m_storage->read(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size)
{ {
error = m_storage->error(); error = m_storage->error().message();
m_storage->clear_error(); TORRENT_ASSERT(!error.empty());
return fatal_disk_error; return fatal_disk_error;
} }
m_scratch_piece = other_piece; m_scratch_piece = other_piece;
@ -2090,14 +2130,22 @@ namespace libtorrent
m_slot_to_piece[m_current_slot] = unassigned; m_slot_to_piece[m_current_slot] = unassigned;
m_slot_to_piece[piece] = piece; m_slot_to_piece[piece] = piece;
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces());
return need_full_check; return need_full_check;
} }
TORRENT_ASSERT(m_state == state_full_check); TORRENT_ASSERT(m_state == state_full_check);
bool skip = check_one_piece(have_piece); int skip = check_one_piece(have_piece);
TORRENT_ASSERT(m_current_slot <= m_files.num_pieces()); TORRENT_ASSERT(m_current_slot <= m_files.num_pieces());
if (skip == -1)
{
error = m_storage->error().message();
TORRENT_ASSERT(!error.empty());
return fatal_disk_error;
}
if (skip) if (skip)
{ {
clear_error(); clear_error();
@ -2162,6 +2210,7 @@ namespace libtorrent
m_state = state_expand_pieces; m_state = state_expand_pieces;
m_current_slot = 0; m_current_slot = 0;
current_slot = m_current_slot; current_slot = m_current_slot;
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces());
return need_full_check; return need_full_check;
} }
} }
@ -2171,10 +2220,13 @@ namespace libtorrent
} }
return check_init_storage(error); return check_init_storage(error);
} }
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces());
return need_full_check; return need_full_check;
} }
bool piece_manager::check_one_piece(int& have_piece) // -1=error 0=ok 1=skip
int piece_manager::check_one_piece(int& have_piece)
{ {
// ------------------------ // ------------------------
// DO THE FULL CHECK // DO THE FULL CHECK
@ -2196,9 +2248,20 @@ namespace libtorrent
int num_read = m_storage->read(&m_piece_data[0] int num_read = m_storage->read(&m_piece_data[0]
, m_current_slot, 0, piece_size); , m_current_slot, 0, piece_size);
if (num_read < 0)
{
if (m_storage->error()
&& m_storage->error() != error_code(ENOENT, get_posix_category()))
{
std::cerr << m_storage->error().message() << std::endl;
return -1;
}
return 1;
}
// if the file is incomplete, skip the rest of it // if the file is incomplete, skip the rest of it
if (num_read != piece_size) if (num_read != piece_size)
return true; return 1;
int piece_index = identify_data(m_piece_data, m_current_slot); int piece_index = identify_data(m_piece_data, m_current_slot);
@ -2271,7 +2334,7 @@ namespace libtorrent
else else
ret |= m_storage->move_slot(m_current_slot, other_slot); ret |= m_storage->move_slot(m_current_slot, other_slot);
if (ret) return true; if (ret) return 1;
TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot); || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
@ -2304,7 +2367,7 @@ namespace libtorrent
ret |= m_storage->move_slot(other_slot, m_current_slot); ret |= m_storage->move_slot(other_slot, m_current_slot);
} }
if (ret) return true; if (ret) return 1;
TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot); || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
@ -2388,7 +2451,7 @@ namespace libtorrent
ret |= m_storage->move_slot(slot2, m_current_slot); ret |= m_storage->move_slot(slot2, m_current_slot);
} }
if (ret) return true; if (ret) return 1;
TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot); || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
@ -2411,7 +2474,7 @@ namespace libtorrent
TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot); || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot);
} }
return false; return 0;
} }
void piece_manager::switch_to_full_mode() void piece_manager::switch_to_full_mode()

View File

@ -424,6 +424,9 @@ namespace libtorrent
TORRENT_ASSERT(m_torrent_file->num_files() > 0); TORRENT_ASSERT(m_torrent_file->num_files() > 0);
TORRENT_ASSERT(m_torrent_file->total_size() >= 0); TORRENT_ASSERT(m_torrent_file->total_size() >= 0);
m_file_priority.clear();
m_file_priority.resize(m_torrent_file->num_files(), 1);
m_block_size = (std::min)(m_block_size, m_torrent_file->piece_length()); m_block_size = (std::min)(m_block_size, m_torrent_file->piece_length());
if (m_torrent_file->num_pieces() if (m_torrent_file->num_pieces()
@ -1344,8 +1347,12 @@ namespace libtorrent
std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin())); std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin()));
m_picker->we_have(index); m_picker->we_have(index);
for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i) for (peer_iterator i = m_connections.begin(); i != m_connections.end();)
(*i)->announce_piece(index); {
peer_connection* p = *i;
++i;
p->announce_piece(index);
}
for (std::set<void*>::iterator i = peers.begin() for (std::set<void*>::iterator i = peers.begin()
, end(peers.end()); i != end; ++i) , end(peers.end()); i != end; ++i)
@ -1767,17 +1774,49 @@ namespace libtorrent
// in the torrent // in the torrent
TORRENT_ASSERT(int(files.size()) == m_torrent_file->num_files()); TORRENT_ASSERT(int(files.size()) == m_torrent_file->num_files());
size_type position = 0;
if (m_torrent_file->num_pieces() == 0) return; if (m_torrent_file->num_pieces() == 0) return;
std::copy(files.begin(), files.end(), m_file_priority.begin());
update_piece_priorities();
}
void torrent::set_file_priority(int index, int prio)
{
INVARIANT_CHECK;
TORRENT_ASSERT(index < m_torrent_file->num_files());
TORRENT_ASSERT(index >= 0);
if (m_file_priority[index] == prio) return;
m_file_priority[index] = prio;
update_piece_priorities();
}
int torrent::file_priority(int index) const
{
TORRENT_ASSERT(index < m_torrent_file->num_files());
TORRENT_ASSERT(index >= 0);
return m_file_priority[index];
}
void torrent::file_priorities(std::vector<int>& files) const
{
INVARIANT_CHECK;
files.resize(m_file_priority.size());
std::copy(m_file_priority.begin(), m_file_priority.end(), files.begin());
}
void torrent::update_piece_priorities()
{
INVARIANT_CHECK;
if (m_torrent_file->num_pieces() == 0) return;
bool was_finished = is_finished(); bool was_finished = is_finished();
size_type position = 0;
int piece_length = m_torrent_file->piece_length(); int piece_length = m_torrent_file->piece_length();
// initialize the piece priorities to 0, then only allow // initialize the piece priorities to 0, then only allow
// setting higher priorities // setting higher priorities
std::vector<int> pieces(m_torrent_file->num_pieces(), 0); std::vector<int> pieces(m_torrent_file->num_pieces(), 0);
for (int i = 0; i < int(files.size()); ++i) for (int i = 0; i < int(m_file_priority.size()); ++i)
{ {
size_type start = position; size_type start = position;
size_type size = m_torrent_file->files().at(i).size; size_type size = m_torrent_file->files().at(i).size;
@ -1788,12 +1827,12 @@ namespace libtorrent
// already set (to avoid problems with overlapping pieces) // already set (to avoid problems with overlapping pieces)
int start_piece = int(start / piece_length); int start_piece = int(start / piece_length);
int last_piece = int((position - 1) / piece_length); int last_piece = int((position - 1) / piece_length);
TORRENT_ASSERT(last_piece <= int(pieces.size())); TORRENT_ASSERT(last_piece < int(pieces.size()));
// if one piece spans several files, we might // if one piece spans several files, we might
// come here several times with the same start_piece, end_piece // come here several times with the same start_piece, end_piece
std::for_each(pieces.begin() + start_piece std::for_each(pieces.begin() + start_piece
, pieces.begin() + last_piece + 1 , pieces.begin() + last_piece + 1
, bind(&set_if_greater, _1, files[i])); , bind(&set_if_greater, _1, m_file_priority[i]));
} }
prioritize_pieces(pieces); prioritize_pieces(pieces);
update_peer_interest(was_finished); update_peer_interest(was_finished);
@ -1989,7 +2028,6 @@ namespace libtorrent
{ {
if (m_picker.get()) if (m_picker.get())
{ {
TORRENT_ASSERT(!is_seed());
m_picker->dec_refcount_all(); m_picker->dec_refcount_all();
} }
} }
@ -2434,6 +2472,30 @@ namespace libtorrent
m_seeding_time = seconds(rd.dict_find_int_value("seeding_time")); m_seeding_time = seconds(rd.dict_find_int_value("seeding_time"));
m_complete = rd.dict_find_int_value("num_seeds", -1); m_complete = rd.dict_find_int_value("num_seeds", -1);
m_incomplete = rd.dict_find_int_value("num_downloaders", -1); m_incomplete = rd.dict_find_int_value("num_downloaders", -1);
set_upload_limit(rd.dict_find_int_value("upload_rate_limit", -1));
set_download_limit(rd.dict_find_int_value("download_rate_limit", -1));
set_max_connections(rd.dict_find_int_value("max_connections", -1));
set_max_uploads(rd.dict_find_int_value("max_uploads", -1));
lazy_entry const* file_priority = rd.dict_find_list("file_priority");
if (file_priority && file_priority->list_size()
== m_torrent_file->num_files())
{
for (int i = 0; i < file_priority->list_size(); ++i)
m_file_priority[i] = file_priority->list_int_value_at(i, 1);
update_piece_priorities();
}
lazy_entry const* piece_priority = rd.dict_find_string("piece_priority");
if (piece_priority && piece_priority->string_length()
== m_torrent_file->num_pieces())
{
char const* p = piece_priority->string_ptr();
for (int i = 0; i < piece_priority->string_length(); ++i)
m_picker->set_piece_priority(i, p[i]);
}
if (rd.dict_find_int_value("auto_managed")) auto_managed(true);
if (rd.dict_find_int_value("paused")) pause();
} }
void torrent::write_resume_data(entry& ret) const void torrent::write_resume_data(entry& ret) const
@ -2512,8 +2574,7 @@ namespace libtorrent
pieces.resize(m_torrent_file->num_pieces()); pieces.resize(m_torrent_file->num_pieces());
if (is_seed()) if (is_seed())
{ {
for (int i = 0, end(pieces.size()); i < end; ++i) std::memset(&pieces[0], 1, pieces.size());
pieces[i] = 1;
} }
else else
{ {
@ -2559,6 +2620,33 @@ namespace libtorrent
peer["port"] = i->second.port; peer["port"] = i->second.port;
peer_list.push_back(peer); peer_list.push_back(peer);
} }
ret["upload_rate_limit"] = upload_limit();
ret["download_rate_limit"] = download_limit();
ret["max_connections"] = max_connections();
ret["max_uploads"] = max_uploads();
ret["paused"] = m_paused;
ret["auto_managed"] = m_auto_managed;
// write piece priorities
entry::string_type& piece_priority = ret["piece_priority"].string();
piece_priority.resize(m_torrent_file->num_pieces());
if (is_seed())
{
std::memset(&piece_priority[0], 1, pieces.size());
}
else
{
for (int i = 0, end(piece_priority.size()); i < end; ++i)
piece_priority[i] = m_picker->piece_priority(i);
}
// write file priorities
entry::list_type& file_priority = ret["file_priority"].list();
file_priority.clear();
for (int i = 0, end(m_file_priority.size()); i < end; ++i)
file_priority.push_back(m_file_priority[i]);
} }
void torrent::get_full_peer_list(std::vector<peer_list_entry>& v) const void torrent::get_full_peer_list(std::vector<peer_list_entry>& v) const
@ -3108,8 +3196,6 @@ namespace libtorrent
// called when torrent is complete (all pieces downloaded) // called when torrent is complete (all pieces downloaded)
void torrent::completed() void torrent::completed()
{ {
INVARIANT_CHECK;
m_picker.reset(); m_picker.reset();
set_state(torrent_status::seeding); set_state(torrent_status::seeding);
@ -3224,24 +3310,13 @@ namespace libtorrent
m_connections_initialized = true; m_connections_initialized = true;
// all peer connections have to initialize themselves now that the metadata // all peer connections have to initialize themselves now that the metadata
// is available // is available
for (torrent::peer_iterator i = m_connections.begin() for (torrent::peer_iterator i = m_connections.begin();
, end(m_connections.end()); i != end;) i != m_connections.end();)
{ {
boost::intrusive_ptr<peer_connection> pc = *i; peer_connection* pc = *i;
++i; ++i;
#ifndef BOOST_NO_EXCEPTIONS
try
{
#endif
pc->on_metadata(); pc->on_metadata();
pc->init(); pc->init();
#ifndef BOOST_NO_EXCEPTIONS
}
catch (std::exception& e)
{
pc->disconnect(e.what());
}
#endif
} }
} }
@ -3763,6 +3838,7 @@ namespace libtorrent
TORRENT_ASSERT(m_storage); TORRENT_ASSERT(m_storage);
m_storage->async_release_files( m_storage->async_release_files(
bind(&torrent::on_torrent_paused, shared_from_this(), _1, _2)); bind(&torrent::on_torrent_paused, shared_from_this(), _1, _2));
m_storage->async_clear_read_cache();
} }
else else
{ {
@ -4270,7 +4346,7 @@ namespace libtorrent
st.next_announce = boost::posix_time::seconds( st.next_announce = boost::posix_time::seconds(
total_seconds(next_announce() - now)); total_seconds(next_announce() - now));
if (st.next_announce.is_negative()) if (st.next_announce.is_negative() || is_paused())
st.next_announce = boost::posix_time::seconds(0); st.next_announce = boost::posix_time::seconds(0);
st.announce_interval = boost::posix_time::seconds(m_duration); st.announce_interval = boost::posix_time::seconds(m_duration);

View File

@ -400,12 +400,32 @@ namespace libtorrent
return ret; return ret;
} }
void torrent_handle::file_priority(int index, int priority) const
{
INVARIANT_CHECK;
TORRENT_FORWARD(set_file_priority(index, priority));
}
int torrent_handle::file_priority(int index) const
{
INVARIANT_CHECK;
TORRENT_FORWARD_RETURN(file_priority(index), 0);
}
void torrent_handle::prioritize_files(std::vector<int> const& files) const void torrent_handle::prioritize_files(std::vector<int> const& files) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(prioritize_files(files)); TORRENT_FORWARD(prioritize_files(files));
} }
std::vector<int> torrent_handle::file_priorities() const
{
INVARIANT_CHECK;
std::vector<int> ret;
TORRENT_FORWARD_RETURN2(file_priorities(ret), ret);
return ret;
}
// ============ start deprecation =============== // ============ start deprecation ===============
void torrent_handle::filter_piece(int index, bool filter) const void torrent_handle::filter_piece(int index, bool filter) const

View File

@ -211,14 +211,19 @@ namespace libtorrent
int load_file(fs::path const& filename, std::vector<char>& v) int load_file(fs::path const& filename, std::vector<char>& v)
{ {
file f; file f;
if (!f.open(filename, file::in)) return -1; error_code ec;
f.seek(0, file::end); if (!f.open(filename, file::in, ec)) return -1;
size_type s = f.tell(); f.seek(0, file::end, ec);
if (ec) return -1;
size_type s = f.tell(ec);
if (ec) return -1;
if (s > 5000000) return -2; if (s > 5000000) return -2;
v.resize(s); v.resize(s);
f.seek(0); f.seek(0, file::begin, ec);
size_type read = f.read(&v[0], s); if (ec) return -1;
size_type read = f.read(&v[0], s, ec);
if (read != s) return -3; if (read != s) return -3;
if (ec) return -3;
return 0; return 0;
} }

View File

@ -175,11 +175,6 @@ _sources = glob.glob("./libtorrent/src/*.cpp") + \
# Remove some files from the source that aren't needed # Remove some files from the source that aren't needed
_source_removals = ["mapped_storage.cpp"] _source_removals = ["mapped_storage.cpp"]
if windows_check():
_source_removals.append("file.cpp")
else:
_source_removals.append("file_win.cpp")
for source in _sources: for source in _sources:
for rem in _source_removals: for rem in _source_removals:
if rem in source: if rem in source:
@ -327,7 +322,7 @@ setup(
]}, ]},
packages = find_packages(exclude=["plugins"]), packages = find_packages(exclude=["plugins"]),
url = "http://deluge-torrent.org", url = "http://deluge-torrent.org",
version = "0.9.02", version = "0.9.03",
) )
try: try: