finally finish lt sync
This commit is contained in:
parent
4990d273a4
commit
13f67b609b
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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&)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
7
setup.py
7
setup.py
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue