mirror of
https://git.deluge-torrent.org/deluge
synced 2025-04-21 03:54:50 +00:00
lt sync 2370
This commit is contained in:
parent
8e11197ac9
commit
772f80e622
44 changed files with 1497 additions and 897 deletions
|
@ -3,6 +3,7 @@
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <libtorrent/peer_info.hpp>
|
||||
#include <libtorrent/bitfield.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/iterator.hpp>
|
||||
|
||||
|
@ -35,7 +36,7 @@ list get_pieces(peer_info const& pi)
|
|||
{
|
||||
list ret;
|
||||
|
||||
for (std::vector<bool>::const_iterator i = pi.pieces.begin()
|
||||
for (bitfield::const_iterator i = pi.pieces.begin()
|
||||
, end(pi.pieces.end()); i != end; ++i)
|
||||
{
|
||||
ret.append(*i);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <libtorrent/entry.hpp>
|
||||
#include <libtorrent/peer_request.hpp>
|
||||
#include <libtorrent/disk_buffer_holder.hpp>
|
||||
#include <libtorrent/bitfield.hpp>
|
||||
#include <boost/python.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
|
@ -119,17 +120,26 @@ namespace
|
|||
return this->peer_plugin::on_have(index);
|
||||
}
|
||||
|
||||
bool on_bitfield(std::vector<bool> const& bitfield)
|
||||
bool on_bitfield(list _bf)
|
||||
{
|
||||
//Convert list to a bitfield
|
||||
bitfield bf(len(_bf));
|
||||
for (int i = 0; i < len(_bf); ++i)
|
||||
{
|
||||
if (_bf[i])
|
||||
bf.set_bit(i);
|
||||
else
|
||||
bf.clear_bit(i);
|
||||
}
|
||||
if (override f = this->get_override("on_bitfield"))
|
||||
return f(bitfield);
|
||||
return f(bf);
|
||||
else
|
||||
return peer_plugin::on_bitfield(bitfield);
|
||||
return peer_plugin::on_bitfield(bf);
|
||||
}
|
||||
|
||||
bool default_on_bitfield(std::vector<bool> const& bitfield)
|
||||
bool default_on_bitfield(const bitfield &bf)
|
||||
{
|
||||
return this->peer_plugin::on_bitfield(bitfield);
|
||||
return this->peer_plugin::on_bitfield(bf);
|
||||
}
|
||||
|
||||
bool on_request(peer_request const& req)
|
||||
|
|
|
@ -41,14 +41,14 @@ namespace
|
|||
return result;
|
||||
}
|
||||
|
||||
std::vector<file_entry>::const_iterator begin_files(torrent_info& i, bool storage)
|
||||
file_storage::iterator begin_files(torrent_info& i)
|
||||
{
|
||||
return i.begin_files(storage);
|
||||
return i.begin_files();
|
||||
}
|
||||
|
||||
std::vector<file_entry>::const_iterator end_files(torrent_info& i, bool storage)
|
||||
file_storage::iterator end_files(torrent_info& i)
|
||||
{
|
||||
return i.end_files(storage);
|
||||
return i.end_files();
|
||||
}
|
||||
|
||||
//list files(torrent_info const& ti, bool storage) {
|
||||
|
@ -57,7 +57,7 @@ namespace
|
|||
|
||||
typedef std::vector<file_entry> list_type;
|
||||
|
||||
for (list_type::const_iterator i = ti.begin_files(storage); i != ti.end_files(storage); ++i)
|
||||
for (list_type::const_iterator i = ti.begin_files(); i != ti.end_files(); ++i)
|
||||
result.append(*i);
|
||||
|
||||
return result;
|
||||
|
@ -70,10 +70,12 @@ void bind_torrent_info()
|
|||
{
|
||||
return_value_policy<copy_const_reference> copy;
|
||||
|
||||
class_<torrent_info, boost::intrusive_ptr<torrent_info> >("torrent_info")
|
||||
class_<torrent_info, boost::intrusive_ptr<torrent_info> >("torrent_info", no_init)
|
||||
.def(init<entry const&>())
|
||||
.def(init<sha1_hash const&>())
|
||||
|
||||
.def(init<char const*, int>())
|
||||
.def(init<char const*>())
|
||||
|
||||
.def("add_tracker", &torrent_info::add_tracker, (arg("url"), arg("tier")=0))
|
||||
.def("add_url_seed", &torrent_info::add_url_seed)
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <libtorrent/torrent_handle.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include <libtorrent/bitfield.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace libtorrent;
|
||||
|
@ -12,7 +13,7 @@ object pieces(torrent_status const& s)
|
|||
{
|
||||
list result;
|
||||
|
||||
for (std::vector<bool>::const_iterator i(s.pieces->begin()), e(s.pieces->end()); i != e; ++i)
|
||||
for (bitfield::const_iterator i(s.pieces->begin()), e(s.pieces->end()); i != e; ++i)
|
||||
result.append(*i);
|
||||
|
||||
return result;
|
||||
|
|
|
@ -53,6 +53,21 @@ namespace libtorrent
|
|||
torrent_handle handle;
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT file_renamed_alert: torrent_alert
|
||||
{
|
||||
file_renamed_alert(torrent_handle const& h
|
||||
, std::string const& name_
|
||||
, std::string const& msg)
|
||||
: torrent_alert(h, alert::warning, msg)
|
||||
, name(name_)
|
||||
{}
|
||||
|
||||
virtual std::auto_ptr<alert> clone() const
|
||||
{ return std::auto_ptr<alert>(new file_renamed_alert(*this)); }
|
||||
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT tracker_alert: torrent_alert
|
||||
{
|
||||
tracker_alert(torrent_handle const& h
|
||||
|
|
|
@ -514,10 +514,6 @@ namespace libtorrent
|
|||
// port we'll bind the next outgoing socket to
|
||||
int m_next_port;
|
||||
|
||||
// the sequence number to assign to the
|
||||
// next torrent that's added
|
||||
int m_torrent_sequence;
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
boost::intrusive_ptr<dht::dht_tracker> m_dht;
|
||||
dht_settings m_dht_settings;
|
||||
|
|
241
libtorrent/include/libtorrent/bitfield.hpp
Normal file
241
libtorrent/include/libtorrent/bitfield.hpp
Normal file
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
|
||||
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_BITFIELD_HPP_INCLUDED
|
||||
#define TORRENT_BITFIELD_HPP_INCLUDED
|
||||
|
||||
#include "libtorrent/assert.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
struct TORRENT_EXPORT bitfield
|
||||
{
|
||||
bitfield(): m_bytes(0), m_size(0), m_own(false) {}
|
||||
bitfield(int bits): m_bytes(0), m_size(0)
|
||||
{ resize(bits); }
|
||||
bitfield(int bits, bool val): m_bytes(0), m_size(0)
|
||||
{ resize(bits, val); }
|
||||
bitfield(char const* bytes, int bits): m_bytes(0), m_size(0)
|
||||
{ assign(bytes, bits); }
|
||||
bitfield(bitfield const& rhs): m_bytes(0), m_size(0), m_own(false)
|
||||
{ assign(rhs.bytes(), rhs.size()); }
|
||||
|
||||
void borrow_bytes(char* bytes, int bits)
|
||||
{
|
||||
dealloc();
|
||||
m_bytes = (unsigned char*)bytes;
|
||||
m_size = bits;
|
||||
m_own = false;
|
||||
}
|
||||
~bitfield() { dealloc(); }
|
||||
|
||||
void assign(char const* bytes, int bits)
|
||||
{ resize(bits); memcpy(m_bytes, bytes, (bits + 7) / 8); }
|
||||
|
||||
bool operator[](int index) const
|
||||
{ return get_bit(index); }
|
||||
|
||||
bool get_bit(int index) const
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0);
|
||||
TORRENT_ASSERT(index < m_size);
|
||||
return m_bytes[index / 8] & (0x80 >> (index & 7));
|
||||
}
|
||||
|
||||
void clear_bit(int index)
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0);
|
||||
TORRENT_ASSERT(index < m_size);
|
||||
m_bytes[index / 8] &= ~(0x80 >> (index & 7));
|
||||
}
|
||||
|
||||
void set_bit(int index)
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0);
|
||||
TORRENT_ASSERT(index < m_size);
|
||||
m_bytes[index / 8] |= (0x80 >> (index & 7));
|
||||
}
|
||||
|
||||
std::size_t size() const { return m_size; }
|
||||
bool empty() const { return m_size == 0; }
|
||||
|
||||
char const* bytes() const { return (char*)m_bytes; }
|
||||
|
||||
bitfield& operator=(bitfield const& rhs)
|
||||
{
|
||||
assign(rhs.bytes(), rhs.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
int count() const
|
||||
{
|
||||
// 0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111,
|
||||
// 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111
|
||||
const static char num_bits[] =
|
||||
{
|
||||
0, 1, 1, 2, 1, 2, 2, 3,
|
||||
1, 2, 2, 3, 2, 3, 3, 4
|
||||
};
|
||||
|
||||
int ret = 0;
|
||||
const int num_bytes = m_size / 8;
|
||||
for (int i = 0; i < num_bytes; ++i)
|
||||
{
|
||||
ret += num_bits[m_bytes[i] & 0xf] + num_bits[m_bytes[i] >> 4];
|
||||
}
|
||||
|
||||
int rest = m_size - num_bytes * 8;
|
||||
for (int i = 0; i < rest; ++i)
|
||||
{
|
||||
ret += (m_bytes[num_bytes] >> (7-i)) & 1;
|
||||
}
|
||||
TORRENT_ASSERT(ret <= m_size);
|
||||
TORRENT_ASSERT(ret >= 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct const_iterator
|
||||
{
|
||||
friend struct bitfield;
|
||||
|
||||
typedef bool value_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef bool const* pointer;
|
||||
typedef bool& reference;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
bool operator*() { return *byte & bit; }
|
||||
const_iterator& operator++() { inc(); return *this; }
|
||||
const_iterator operator++(int)
|
||||
{ const_iterator ret(*this); inc(); return ret; }
|
||||
const_iterator& operator--() { dec(); return *this; }
|
||||
const_iterator operator--(int)
|
||||
{ const_iterator ret(*this); dec(); return ret; }
|
||||
|
||||
const_iterator(): byte(0), bit(0x80) {}
|
||||
bool operator==(const_iterator const& rhs) const
|
||||
{ return byte == rhs.byte && bit == rhs.bit; }
|
||||
|
||||
bool operator!=(const_iterator const& rhs) const
|
||||
{ return byte != rhs.byte || bit != rhs.bit; }
|
||||
|
||||
private:
|
||||
void inc()
|
||||
{
|
||||
TORRENT_ASSERT(byte);
|
||||
if (bit == 0x01)
|
||||
{
|
||||
bit = 0x80;
|
||||
++byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
bit >>= 1;
|
||||
}
|
||||
}
|
||||
void dec()
|
||||
{
|
||||
TORRENT_ASSERT(byte);
|
||||
if (bit == 0x80)
|
||||
{
|
||||
bit = 0x01;
|
||||
--byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
bit <<= 1;
|
||||
}
|
||||
}
|
||||
const_iterator(unsigned char const* ptr, int offset)
|
||||
: byte(ptr), bit(0x80 >> offset) {}
|
||||
unsigned char const* byte;
|
||||
int bit;
|
||||
};
|
||||
|
||||
const_iterator begin() const { return const_iterator(m_bytes, 0); }
|
||||
const_iterator end() const { return const_iterator(m_bytes + m_size / 8, m_size & 7); }
|
||||
|
||||
void resize(int bits, bool val)
|
||||
{
|
||||
resize(bits);
|
||||
if (val) set_all(); else clear_all();
|
||||
}
|
||||
|
||||
void set_all()
|
||||
{
|
||||
memset(m_bytes, 0xff, (m_size + 7) / 8);
|
||||
}
|
||||
|
||||
void clear_all()
|
||||
{
|
||||
memset(m_bytes, 0x00, (m_size + 7) / 8);
|
||||
}
|
||||
|
||||
void resize(int bits)
|
||||
{
|
||||
const int bytes = (bits + 7) / 8;
|
||||
if (m_bytes)
|
||||
{
|
||||
if (m_own)
|
||||
{
|
||||
m_bytes = (unsigned char*)realloc(m_bytes, bytes);
|
||||
m_own = true;
|
||||
}
|
||||
else if (bits > m_size)
|
||||
{
|
||||
unsigned char* tmp = (unsigned char*)malloc(bytes);
|
||||
memcpy(tmp, m_bytes, (std::min)((m_size + 7)/ 8, bytes));
|
||||
m_bytes = tmp;
|
||||
m_own = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bytes = (unsigned char*)malloc(bytes);
|
||||
m_own = true;
|
||||
}
|
||||
m_size = bits;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void dealloc() { if (m_own) free(m_bytes); m_bytes = 0; }
|
||||
unsigned char* m_bytes;
|
||||
int m_size; // in bits
|
||||
bool m_own;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TORRENT_BITFIELD_HPP_INCLUDED
|
||||
|
|
@ -209,7 +209,7 @@ namespace libtorrent
|
|||
void write_not_interested();
|
||||
void write_request(peer_request const& r);
|
||||
void write_cancel(peer_request const& r);
|
||||
void write_bitfield(std::vector<bool> const& bitfield);
|
||||
void write_bitfield(bitfield const& bits);
|
||||
void write_have(int index);
|
||||
void write_piece(peer_request const& r, disk_buffer_holder& buffer);
|
||||
void write_handshake();
|
||||
|
|
|
@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#define TORRENT_CHAINED_BUFFER_HPP_INCLUDED
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/version.hpp>
|
||||
#if BOOST_VERSION < 103500
|
||||
#include <asio/buffer.hpp>
|
||||
#else
|
||||
|
|
|
@ -35,6 +35,12 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/peer_id.hpp"
|
||||
#include "libtorrent/file_storage.hpp"
|
||||
#include "libtorrent/file_pool.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/storage.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
@ -44,8 +50,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#endif
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
|
@ -56,26 +64,29 @@ namespace libtorrent
|
|||
namespace fs = boost::filesystem;
|
||||
namespace pt = boost::posix_time;
|
||||
|
||||
struct create_torrent
|
||||
struct TORRENT_EXPORT create_torrent
|
||||
{
|
||||
create_torrent();
|
||||
create_torrent(file_storage& fs, int piece_size);
|
||||
create_torrent(file_storage& fs);
|
||||
entry generate() const;
|
||||
|
||||
file_storage const& files() const { return m_files; }
|
||||
|
||||
void set_comment(char const* str);
|
||||
void set_creator(char const* str);
|
||||
void set_piece_size(int size);
|
||||
void set_hash(int index, sha1_hash const& h);
|
||||
void add_file(fs::path file, size_type size);
|
||||
void add_url_seed(std::string const& url);
|
||||
void add_node(std::pair<std::string, int> const& node);
|
||||
void add_tracker(std::string const& url, int tier = 0);
|
||||
|
||||
int num_pieces() const { return m_num_pieces; }
|
||||
int piece_length() const { return m_piece_length; }
|
||||
int piece_size(int i) const;
|
||||
int num_pieces() const { return m_files.num_pieces(); }
|
||||
int piece_length() const { return m_files.piece_length(); }
|
||||
int piece_size(int i) const { return m_files.piece_size(i); }
|
||||
|
||||
private:
|
||||
|
||||
file_storage& m_files;
|
||||
|
||||
// the urls to the trackers
|
||||
typedef std::pair<std::string, int> announce_entry;
|
||||
std::vector<announce_entry> m_urls;
|
||||
|
@ -84,32 +95,15 @@ namespace libtorrent
|
|||
|
||||
std::vector<sha1_hash> m_piece_hash;
|
||||
|
||||
// the length of one piece
|
||||
// if this is 0, the torrent_info is
|
||||
// in an uninitialized state
|
||||
int m_piece_length;
|
||||
|
||||
typedef std::pair<fs::path, size_type> file_entry;
|
||||
// the list of files that this torrent consists of
|
||||
std::vector<file_entry> m_files;
|
||||
|
||||
// dht nodes to add to the routing table/bootstrap from
|
||||
typedef std::vector<std::pair<std::string, int> > nodes_t;
|
||||
nodes_t m_nodes;
|
||||
|
||||
// the sum of all filesizes
|
||||
size_type m_total_size;
|
||||
|
||||
// the number of pieces in the torrent
|
||||
int m_num_pieces;
|
||||
|
||||
// the hash that identifies this torrent
|
||||
// is mutable because it's calculated
|
||||
// lazily
|
||||
mutable sha1_hash m_info_hash;
|
||||
|
||||
std::string m_name;
|
||||
|
||||
// if a creation date is found in the torrent file
|
||||
// this will be set to that, otherwise it'll be
|
||||
// 1970, Jan 1
|
||||
|
@ -134,6 +128,72 @@ namespace libtorrent
|
|||
// be announced on the dht
|
||||
bool m_private;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline bool default_pred(boost::filesystem::path const&) { return true; }
|
||||
|
||||
inline void nop(int i) {}
|
||||
|
||||
template <class Pred>
|
||||
void add_files_impl(file_storage& fs, boost::filesystem::path const& p
|
||||
, boost::filesystem::path const& l, Pred pred)
|
||||
{
|
||||
using boost::filesystem::path;
|
||||
using boost::filesystem::directory_iterator;
|
||||
std::string const& leaf = l.leaf();
|
||||
if (leaf == ".." || leaf == ".") return;
|
||||
if (!pred(l)) return;
|
||||
path f(p / l);
|
||||
if (is_directory(f))
|
||||
{
|
||||
for (directory_iterator i(f), end; i != end; ++i)
|
||||
add_files_impl(fs, p, l / i->leaf(), pred);
|
||||
}
|
||||
else
|
||||
{
|
||||
fs.add_file(l, file_size(f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Pred>
|
||||
void add_files(file_storage& fs, boost::filesystem::path const& file, Pred p)
|
||||
{
|
||||
detail::add_files_impl(fs, complete(file).branch_path(), file.leaf(), p);
|
||||
}
|
||||
|
||||
inline void add_files(file_storage& fs, boost::filesystem::path const& file)
|
||||
{
|
||||
detail::add_files_impl(fs, complete(file).branch_path(), file.leaf(), detail::default_pred);
|
||||
}
|
||||
|
||||
template <class Fun>
|
||||
void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p, Fun f)
|
||||
{
|
||||
file_pool fp;
|
||||
boost::scoped_ptr<storage_interface> st(
|
||||
default_storage_constructor(const_cast<file_storage&>(t.files()), p, fp));
|
||||
|
||||
// calculate the hash for all pieces
|
||||
int num = t.num_pieces();
|
||||
std::vector<char> buf(t.piece_length());
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
// read hits the disk and will block. Progress should
|
||||
// be updated in between reads
|
||||
st->read(&buf[0], i, 0, t.piece_size(i));
|
||||
hasher h(&buf[0], t.piece_size(i));
|
||||
t.set_hash(i, h.final());
|
||||
f(i);
|
||||
}
|
||||
}
|
||||
|
||||
inline void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p)
|
||||
{
|
||||
set_piece_hashes(t, p, detail::nop);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -82,6 +82,7 @@ namespace libtorrent
|
|||
, check_fastresume
|
||||
, check_files
|
||||
, save_resume_data
|
||||
, rename_file
|
||||
};
|
||||
|
||||
action_t action;
|
||||
|
@ -91,7 +92,7 @@ namespace libtorrent
|
|||
boost::intrusive_ptr<piece_manager> storage;
|
||||
// arguments used for read and write
|
||||
int piece, offset;
|
||||
// used for move_storage. On errors, this is set
|
||||
// used for move_storage and rename_file. On errors, this is set
|
||||
// to the error message
|
||||
std::string str;
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ namespace libtorrent
|
|||
class peer_connection;
|
||||
class entry;
|
||||
struct disk_buffer_holder;
|
||||
struct bitfield;
|
||||
|
||||
struct TORRENT_EXPORT torrent_plugin
|
||||
{
|
||||
|
@ -129,7 +130,7 @@ namespace libtorrent
|
|||
virtual bool on_have(int index)
|
||||
{ return false; }
|
||||
|
||||
virtual bool on_bitfield(std::vector<bool> const& bitfield)
|
||||
virtual bool on_bitfield(bitfield const& bitfield)
|
||||
{ return false; }
|
||||
|
||||
virtual bool on_have_all()
|
||||
|
|
|
@ -68,6 +68,7 @@ namespace libtorrent
|
|||
boost::shared_ptr<file> open_file(void* st, fs::path const& p
|
||||
, file::open_mode m, std::string& error);
|
||||
void release(void* st);
|
||||
void release(fs::path const& p);
|
||||
void resize(int size);
|
||||
|
||||
private:
|
||||
|
|
146
libtorrent/include/libtorrent/file_storage.hpp
Normal file
146
libtorrent/include/libtorrent/file_storage.hpp
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2003-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_FILE_STORAGE_HPP_INCLUDED
|
||||
#define TORRENT_FILE_STORAGE_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 1)
|
||||
#endif
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "libtorrent/size_type.hpp"
|
||||
#include "libtorrent/assert.hpp"
|
||||
#include "libtorrent/peer_request.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
struct TORRENT_EXPORT file_entry
|
||||
{
|
||||
file_entry(): offset(0), size(0), file_base(0) {}
|
||||
|
||||
fs::path path;
|
||||
size_type offset; // the offset of this file inside the torrent
|
||||
size_type size; // the size of this file
|
||||
// the offset in the file where the storage starts.
|
||||
// This is always 0 unless parts of the torrent is
|
||||
// compressed into a single file, such as a so-called part file.
|
||||
size_type file_base;
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT file_slice
|
||||
{
|
||||
int file_index;
|
||||
size_type offset;
|
||||
size_type size;
|
||||
};
|
||||
|
||||
class TORRENT_EXPORT file_storage
|
||||
{
|
||||
friend class torrent_info;
|
||||
public:
|
||||
file_storage();
|
||||
~file_storage() {}
|
||||
|
||||
bool is_valid() const { return m_piece_length > 0; }
|
||||
|
||||
void add_file(file_entry const& e);
|
||||
void add_file(fs::path const& p, size_type size);
|
||||
void rename_file(int index, std::string const& new_filename);
|
||||
|
||||
std::vector<file_slice> map_block(int piece, size_type offset
|
||||
, int size) const;
|
||||
peer_request map_file(int file, size_type offset, int size) const;
|
||||
|
||||
typedef std::vector<file_entry>::const_iterator iterator;
|
||||
typedef std::vector<file_entry>::const_reverse_iterator reverse_iterator;
|
||||
|
||||
iterator begin() const { return m_files.begin(); }
|
||||
iterator end() const { return m_files.end(); }
|
||||
reverse_iterator rbegin() const { return m_files.rbegin(); }
|
||||
reverse_iterator rend() const { return m_files.rend(); }
|
||||
int num_files() const
|
||||
{ return int(m_files.size()); }
|
||||
|
||||
file_entry const& at(int index) const
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0 && index < int(m_files.size()));
|
||||
return m_files[index];
|
||||
}
|
||||
|
||||
size_type total_size() const { TORRENT_ASSERT(m_piece_length > 0); return m_total_size; }
|
||||
void set_num_pieces(int n) { m_num_pieces = n; }
|
||||
int num_pieces() const { TORRENT_ASSERT(m_piece_length > 0); return m_num_pieces; }
|
||||
void set_piece_length(int l) { m_piece_length = l; }
|
||||
int piece_length() const { TORRENT_ASSERT(m_piece_length > 0); return m_piece_length; }
|
||||
int piece_size(int index) const;
|
||||
|
||||
void set_name(std::string const& n) { m_name = n; }
|
||||
const std::string& name() const { TORRENT_ASSERT(m_piece_length > 0); return m_name; }
|
||||
|
||||
void swap(file_storage& ti)
|
||||
{
|
||||
using std::swap;
|
||||
swap(ti.m_piece_length, m_piece_length);
|
||||
swap(ti.m_files, m_files);
|
||||
swap(ti.m_total_size, m_total_size);
|
||||
swap(ti.m_num_pieces, m_num_pieces);
|
||||
swap(ti.m_name, m_name);
|
||||
}
|
||||
|
||||
private:
|
||||
int m_piece_length;
|
||||
|
||||
// the list of files that this torrent consists of
|
||||
std::vector<file_entry> m_files;
|
||||
|
||||
// the sum of all filesizes
|
||||
size_type m_total_size;
|
||||
|
||||
// the number of pieces in the torrent
|
||||
int m_num_pieces;
|
||||
std::string m_name;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // TORRENT_FILE_STORAGE_HPP_INCLUDED
|
||||
|
|
@ -76,6 +76,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/assert.hpp"
|
||||
#include "libtorrent/chained_buffer.hpp"
|
||||
#include "libtorrent/disk_buffer_holder.hpp"
|
||||
#include "libtorrent/bitfield.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -242,7 +243,7 @@ namespace libtorrent
|
|||
boost::shared_ptr<socket_type> get_socket() const { return m_socket; }
|
||||
tcp::endpoint const& remote() const { return m_remote; }
|
||||
|
||||
std::vector<bool> const& get_bitfield() const;
|
||||
bitfield const& get_bitfield() const;
|
||||
std::vector<int> const& allowed_fast();
|
||||
std::vector<int> const& suggested_pieces() const { return m_suggested_pieces; }
|
||||
|
||||
|
@ -328,7 +329,7 @@ namespace libtorrent
|
|||
void incoming_interested();
|
||||
void incoming_not_interested();
|
||||
void incoming_have(int piece_index);
|
||||
void incoming_bitfield(std::vector<bool> const& bitfield);
|
||||
void incoming_bitfield(bitfield const& bits);
|
||||
void incoming_request(peer_request const& r);
|
||||
void incoming_piece(peer_request const& p, disk_buffer_holder& data);
|
||||
void incoming_piece(peer_request const& p, char const* data);
|
||||
|
@ -629,7 +630,7 @@ namespace libtorrent
|
|||
peer_id m_peer_id;
|
||||
|
||||
// the pieces the other end have
|
||||
std::vector<bool> m_have_piece;
|
||||
bitfield m_have_piece;
|
||||
|
||||
// the queue of requests we have got
|
||||
// from this peer
|
||||
|
|
|
@ -33,12 +33,11 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef TORRENT_PEER_INFO_HPP_INCLUDED
|
||||
#define TORRENT_PEER_INFO_HPP_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "libtorrent/socket.hpp"
|
||||
#include "libtorrent/peer_id.hpp"
|
||||
#include "libtorrent/size_type.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/bitfield.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -96,7 +95,7 @@ namespace libtorrent
|
|||
size_type total_download;
|
||||
size_type total_upload;
|
||||
peer_id pid;
|
||||
std::vector<bool> pieces;
|
||||
bitfield pieces;
|
||||
int upload_limit;
|
||||
int download_limit;
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ namespace libtorrent
|
|||
|
||||
class torrent;
|
||||
class peer_connection;
|
||||
class bitfield;
|
||||
|
||||
struct TORRENT_EXPORT piece_block
|
||||
{
|
||||
|
@ -138,7 +139,7 @@ namespace libtorrent
|
|||
|
||||
// the vector tells which pieces we already have
|
||||
// and which we don't have.
|
||||
void init(std::vector<bool> const& pieces);
|
||||
void init(bitfield const& pieces);
|
||||
|
||||
// increases the peer count for the given piece
|
||||
// (is used when a HAVE message is received)
|
||||
|
@ -147,10 +148,10 @@ namespace libtorrent
|
|||
|
||||
// increases the peer count for the given piece
|
||||
// (is used when a BITFIELD message is received)
|
||||
void inc_refcount(std::vector<bool> const& bitmask);
|
||||
void inc_refcount(bitfield const& bitmask);
|
||||
// decreases the peer count for the given piece
|
||||
// (used when a peer disconnects)
|
||||
void dec_refcount(std::vector<bool> const& bitmask);
|
||||
void dec_refcount(bitfield const& bitmask);
|
||||
|
||||
// these will increase and decrease the peer count
|
||||
// of all pieces. They are used when seeds join
|
||||
|
@ -193,7 +194,7 @@ namespace libtorrent
|
|||
// THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION!
|
||||
// The last argument is the policy::peer pointer for the peer that
|
||||
// we'll download from.
|
||||
void pick_pieces(std::vector<bool> const& pieces
|
||||
void pick_pieces(bitfield const& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, int num_pieces, int prefer_whole_pieces
|
||||
, void* peer, piece_state_t speed
|
||||
|
@ -207,14 +208,14 @@ namespace libtorrent
|
|||
// blocks to be picked. Blocks are not picked from pieces
|
||||
// that are being downloaded
|
||||
int add_blocks(std::vector<int> const& piece_list
|
||||
, const std::vector<bool>& pieces
|
||||
, bitfield const& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, int num_blocks, int prefer_whole_pieces
|
||||
, void* peer, std::vector<int> const& ignore) const;
|
||||
|
||||
// picks blocks only from downloading pieces
|
||||
int add_blocks_downloading(
|
||||
std::vector<bool> const& pieces
|
||||
bitfield const& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, int num_blocks, int prefer_whole_pieces
|
||||
|
@ -280,7 +281,7 @@ namespace libtorrent
|
|||
void verify_priority(int start, int end, int prio) const;
|
||||
void check_invariant(const torrent* t = 0) const;
|
||||
void verify_pick(std::vector<piece_block> const& picked
|
||||
, std::vector<bool> const& bitfield) const;
|
||||
, bitfield const& bits) const;
|
||||
void print_pieces() const;
|
||||
#endif
|
||||
|
||||
|
@ -302,9 +303,9 @@ namespace libtorrent
|
|||
|
||||
friend struct piece_pos;
|
||||
|
||||
bool can_pick(int piece, std::vector<bool> const& bitmask) const;
|
||||
bool can_pick(int piece, bitfield const& bitmask) const;
|
||||
std::pair<int, int> expand_piece(int piece, int whole_pieces
|
||||
, std::vector<bool> const& have) const;
|
||||
, bitfield const& have) const;
|
||||
|
||||
struct piece_pos
|
||||
{
|
||||
|
|
|
@ -129,7 +129,7 @@ namespace libtorrent
|
|||
, resume_data(0)
|
||||
, storage_mode(storage_mode_sparse)
|
||||
, paused(true)
|
||||
, auto_managed(true)
|
||||
, auto_managed(false)
|
||||
, duplicate_is_error(false)
|
||||
, storage(sc)
|
||||
, userdata(0)
|
||||
|
|
|
@ -135,6 +135,7 @@ namespace libtorrent
|
|||
, close_redundant_connections(true)
|
||||
, auto_scrape_interval(1800)
|
||||
, auto_scrape_min_interval(300)
|
||||
, max_peerlist_size(8000)
|
||||
{}
|
||||
|
||||
// this is the user agent that will be sent to the tracker
|
||||
|
@ -402,6 +403,11 @@ namespace libtorrent
|
|||
// the minimum number of seconds between any
|
||||
// automatic scrape (regardless of torrent)
|
||||
int auto_scrape_min_interval;
|
||||
|
||||
// the max number of peers in the peer list
|
||||
// per torrent. This is the peers we know
|
||||
// about, not necessarily connected to.
|
||||
int max_peerlist_size;
|
||||
};
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
|
|
|
@ -45,6 +45,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#define Protocol Protocol_
|
||||
#endif
|
||||
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#if BOOST_VERSION < 103500
|
||||
#include <asio/ip/tcp.hpp>
|
||||
#include <asio/ip/udp.hpp>
|
||||
|
|
|
@ -87,11 +87,11 @@ namespace libtorrent
|
|||
#endif
|
||||
|
||||
TORRENT_EXPORT std::vector<std::pair<size_type, std::time_t> > get_filesizes(
|
||||
torrent_info const& t
|
||||
file_storage const& t
|
||||
, fs::path p);
|
||||
|
||||
TORRENT_EXPORT bool match_filesizes(
|
||||
torrent_info const& t
|
||||
file_storage const& t
|
||||
, fs::path p
|
||||
, std::vector<std::pair<size_type, std::time_t> > const& sizes
|
||||
, bool compact_mode
|
||||
|
@ -157,6 +157,9 @@ namespace libtorrent
|
|||
// non-zero return value indicates an error
|
||||
virtual bool release_files() = 0;
|
||||
|
||||
// this will rename the file specified by index.
|
||||
virtual bool rename_file(int index, std::string const& new_filename) = 0;
|
||||
|
||||
// this will close all open files and delete them
|
||||
// non-zero return value indicates an error
|
||||
virtual bool delete_files() = 0;
|
||||
|
@ -178,16 +181,12 @@ namespace libtorrent
|
|||
};
|
||||
|
||||
typedef storage_interface* (&storage_constructor_type)(
|
||||
boost::intrusive_ptr<torrent_info const>, fs::path const&
|
||||
, file_pool&);
|
||||
file_storage const&, fs::path const&, file_pool&);
|
||||
|
||||
TORRENT_EXPORT storage_interface* default_storage_constructor(
|
||||
boost::intrusive_ptr<torrent_info const> ti
|
||||
, fs::path const& path, file_pool& fp);
|
||||
|
||||
file_storage const&, fs::path const&, file_pool&);
|
||||
TORRENT_EXPORT storage_interface* mapped_storage_constructor(
|
||||
boost::intrusive_ptr<torrent_info const> ti
|
||||
, fs::path const& path, file_pool& fp);
|
||||
file_storage const&, fs::path const&, file_pool&);
|
||||
|
||||
struct disk_io_thread;
|
||||
|
||||
|
@ -201,7 +200,7 @@ namespace libtorrent
|
|||
|
||||
piece_manager(
|
||||
boost::shared_ptr<void> const& torrent
|
||||
, boost::intrusive_ptr<torrent_info const> ti
|
||||
, boost::intrusive_ptr<torrent_info const> info
|
||||
, fs::path const& path
|
||||
, file_pool& fp
|
||||
, disk_io_thread& io
|
||||
|
@ -210,8 +209,7 @@ namespace libtorrent
|
|||
|
||||
~piece_manager();
|
||||
|
||||
torrent_info const* info() const { return m_info.get(); }
|
||||
|
||||
boost::intrusive_ptr<torrent_info const> info() const { return m_info; }
|
||||
void write_resume_data(entry& rd) const;
|
||||
|
||||
void async_check_fastresume(entry const* resume_data
|
||||
|
@ -219,6 +217,9 @@ namespace libtorrent
|
|||
|
||||
void async_check_files(boost::function<void(int, disk_io_job const&)> const& handler);
|
||||
|
||||
void async_rename_file(int index, std::string const& name
|
||||
, boost::function<void(int, disk_io_job const&)> const& handler);
|
||||
|
||||
void async_read(
|
||||
peer_request const& r
|
||||
, boost::function<void(int, disk_io_job const&)> const& handler
|
||||
|
@ -316,6 +317,8 @@ namespace libtorrent
|
|||
|
||||
int release_files_impl() { return m_storage->release_files(); }
|
||||
int delete_files_impl() { return m_storage->delete_files(); }
|
||||
int rename_file_impl(int index, std::string const& new_filename)
|
||||
{ return m_storage->rename_file(index, new_filename); }
|
||||
|
||||
bool move_storage_impl(fs::path const& save_path);
|
||||
|
||||
|
@ -326,12 +329,13 @@ namespace libtorrent
|
|||
void debug_log() const;
|
||||
#endif
|
||||
#endif
|
||||
boost::intrusive_ptr<torrent_info const> m_info;
|
||||
file_storage const& m_files;
|
||||
|
||||
boost::scoped_ptr<storage_interface> m_storage;
|
||||
|
||||
storage_mode_t m_storage_mode;
|
||||
|
||||
boost::intrusive_ptr<torrent_info const> m_info;
|
||||
|
||||
// slots that haven't had any file storage allocated
|
||||
std::vector<int> m_unallocated_slots;
|
||||
// slots that have file storage, but isn't assigned to a piece
|
||||
|
|
|
@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#define TORRENT_TIME_HPP_INCLUDED
|
||||
|
||||
#include <ctime>
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
|
|
|
@ -70,6 +70,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/storage.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/assert.hpp"
|
||||
#include "libtorrent/bitfield.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -79,6 +80,7 @@ namespace libtorrent
|
|||
|
||||
class piece_manager;
|
||||
struct torrent_plugin;
|
||||
struct bitfield;
|
||||
|
||||
namespace aux
|
||||
{
|
||||
|
@ -167,6 +169,9 @@ namespace libtorrent
|
|||
|
||||
void set_sequential_download(bool sd);
|
||||
|
||||
void set_queue_position(int p);
|
||||
int queue_position() const { return m_sequence_number; }
|
||||
|
||||
void second_tick(stat& accumulator, float tick_interval);
|
||||
|
||||
// debug purpose only
|
||||
|
@ -181,6 +186,7 @@ namespace libtorrent
|
|||
|
||||
void ip_filter_updated() { m_policy.ip_filter_updated(); }
|
||||
|
||||
bool has_error() const { return !m_error.empty(); }
|
||||
void pause();
|
||||
void resume();
|
||||
bool is_paused() const { return m_paused; }
|
||||
|
@ -375,7 +381,7 @@ namespace libtorrent
|
|||
return m_have_pieces[index];
|
||||
}
|
||||
|
||||
const std::vector<bool>& pieces() const
|
||||
bitfield const& pieces() const
|
||||
{ return m_have_pieces; }
|
||||
|
||||
int num_pieces() const { return m_num_pieces; }
|
||||
|
@ -398,12 +404,12 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
// when we get a bitfield message, this is called for that piece
|
||||
void peer_has(std::vector<bool> const& bitfield)
|
||||
void peer_has(bitfield const& bits)
|
||||
{
|
||||
if (m_picker.get())
|
||||
{
|
||||
TORRENT_ASSERT(!is_seed());
|
||||
m_picker->inc_refcount(bitfield);
|
||||
m_picker->inc_refcount(bits);
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
else
|
||||
|
@ -562,8 +568,14 @@ namespace libtorrent
|
|||
int max_uploads() const { return m_max_uploads; }
|
||||
void set_max_connections(int limit);
|
||||
int max_connections() const { return m_max_connections; }
|
||||
|
||||
void move_storage(fs::path const& save_path);
|
||||
|
||||
// renames the file with the given index to the new name
|
||||
// the name may include a directory path
|
||||
// returns false on failure
|
||||
bool rename_file(int index, std::string const& name);
|
||||
|
||||
// unless this returns true, new connections must wait
|
||||
// with their initialization.
|
||||
bool ready_for_connections() const
|
||||
|
@ -587,6 +599,7 @@ namespace libtorrent
|
|||
void on_torrent_paused(int ret, disk_io_job const& j);
|
||||
void on_storage_moved(int ret, disk_io_job const& j);
|
||||
void on_save_resume_data(int ret, disk_io_job const& j);
|
||||
void on_file_renamed(int ret, disk_io_job const& j);
|
||||
|
||||
void on_piece_verified(int ret, disk_io_job const& j
|
||||
, boost::function<void(int)> f);
|
||||
|
@ -728,7 +741,7 @@ namespace libtorrent
|
|||
// this is an index into m_trackers
|
||||
|
||||
// the bitmask that says which pieces we have
|
||||
std::vector<bool> m_have_pieces;
|
||||
bitfield m_have_pieces;
|
||||
|
||||
// the number of bytes that has been
|
||||
// downloaded that failed the hash-test
|
||||
|
@ -750,6 +763,10 @@ namespace libtorrent
|
|||
// the state of this torrent (queued, checking, downloading)
|
||||
torrent_status::state_t m_state;
|
||||
|
||||
// if there's an error on this torrent, this is the
|
||||
// error message
|
||||
std::string m_error;
|
||||
|
||||
entry m_resume_data;
|
||||
|
||||
// if the torrent is started without metadata, it may
|
||||
|
|
|
@ -137,6 +137,8 @@ namespace libtorrent
|
|||
state_t state;
|
||||
bool paused;
|
||||
float progress;
|
||||
std::string error;
|
||||
|
||||
boost::posix_time::time_duration next_announce;
|
||||
boost::posix_time::time_duration announce_interval;
|
||||
|
||||
|
@ -198,7 +200,7 @@ namespace libtorrent
|
|||
// we potentially could connect to
|
||||
int connect_candidates;
|
||||
|
||||
const std::vector<bool>* pieces;
|
||||
bitfield const* pieces;
|
||||
|
||||
// this is the number of pieces the client has
|
||||
// downloaded. it is equal to:
|
||||
|
@ -344,6 +346,12 @@ namespace libtorrent
|
|||
bool is_auto_managed() const;
|
||||
void auto_managed(bool m) const;
|
||||
|
||||
int queue_position() const;
|
||||
void queue_position_up() const;
|
||||
void queue_position_down() const;
|
||||
void queue_position_top() const;
|
||||
void queue_position_bottom() const;
|
||||
|
||||
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
|
||||
void resolve_countries(bool r);
|
||||
bool resolve_countries() const;
|
||||
|
@ -440,6 +448,7 @@ namespace libtorrent
|
|||
|
||||
// post condition: save_path() == save_path if true is returned
|
||||
void move_storage(fs::path const& save_path) const;
|
||||
void rename_file(int index, fs::path const& new_name) const;
|
||||
|
||||
sha1_hash info_hash() const;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2003, Arvid Norberg
|
||||
Copyright (c) 2003-2008, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -30,9 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_TORRENT_INFO_HPP_INCLUDE
|
||||
#define TORRENT_TORRENT_INFO_HPP_INCLUDE
|
||||
|
||||
#ifndef TORRENT_TORRENT_INFO_HPP_INCLUDED
|
||||
#define TORRENT_TORRENT_INFO_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -44,7 +43,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/shared_array.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -56,44 +54,17 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/socket.hpp"
|
||||
#include "libtorrent/peer_id.hpp"
|
||||
#include "libtorrent/size_type.hpp"
|
||||
#include "libtorrent/peer_request.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
#include "libtorrent/intrusive_ptr_base.hpp"
|
||||
#include "libtorrent/assert.hpp"
|
||||
#include "libtorrent/file_storage.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
namespace pt = boost::posix_time;
|
||||
namespace gr = boost::gregorian;
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
struct TORRENT_EXPORT file_entry
|
||||
{
|
||||
file_entry(): offset(0), size(0), file_base(0) {}
|
||||
|
||||
fs::path path;
|
||||
size_type offset; // the offset of this file inside the torrent
|
||||
size_type size; // the size of this file
|
||||
// the offset in the file where the storage starts.
|
||||
// This is always 0 unless parts of the torrent is
|
||||
// compressed into a single file, such as a so-called part file.
|
||||
size_type file_base;
|
||||
// if the path was incorrectly encoded, this is
|
||||
// the original corrupt encoded string. It is
|
||||
// preserved in order to be able to reproduce
|
||||
// the correct info-hash
|
||||
boost::shared_ptr<const fs::path> orig_path;
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT file_slice
|
||||
{
|
||||
int file_index;
|
||||
size_type offset;
|
||||
size_type size;
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT announce_entry
|
||||
{
|
||||
announce_entry(std::string const& u): url(u), tier(0) {}
|
||||
|
@ -101,124 +72,73 @@ namespace libtorrent
|
|||
int tier;
|
||||
};
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
struct TORRENT_EXPORT invalid_torrent_file: std::exception
|
||||
{
|
||||
virtual const char* what() const throw() { return "invalid torrent file"; }
|
||||
};
|
||||
#endif
|
||||
|
||||
class TORRENT_EXPORT torrent_info : public intrusive_ptr_base<torrent_info>
|
||||
{
|
||||
public:
|
||||
|
||||
torrent_info();
|
||||
torrent_info(sha1_hash const& info_hash);
|
||||
torrent_info(lazy_entry const& torrent_file);
|
||||
torrent_info(char const* buffer, int size);
|
||||
torrent_info(char const* filename);
|
||||
~torrent_info();
|
||||
|
||||
file_storage const& files() const { return m_files; }
|
||||
|
||||
void add_tracker(std::string const& url, int tier = 0);
|
||||
std::vector<announce_entry> const& trackers() const { return m_urls; }
|
||||
|
||||
bool remap_files(std::vector<file_entry> const& map);
|
||||
|
||||
std::vector<file_slice> map_block(int piece, size_type offset
|
||||
, int size, bool storage = false) const;
|
||||
peer_request map_file(int file, size_type offset, int size
|
||||
, bool storage = false) const;
|
||||
|
||||
std::vector<std::string> const& url_seeds() const
|
||||
{ return m_url_seeds; }
|
||||
void add_url_seed(std::string const& url)
|
||||
{ m_url_seeds.push_back(url); }
|
||||
|
||||
typedef std::vector<file_entry>::const_iterator file_iterator;
|
||||
typedef std::vector<file_entry>::const_reverse_iterator reverse_file_iterator;
|
||||
|
||||
// list the files in the torrent file
|
||||
file_iterator begin_files(bool storage = false) const
|
||||
{
|
||||
if (!storage || m_remapped_files.empty())
|
||||
return m_files.begin();
|
||||
else
|
||||
return m_remapped_files.begin();
|
||||
}
|
||||
|
||||
file_iterator end_files(bool storage = false) const
|
||||
{
|
||||
if (!storage || m_remapped_files.empty())
|
||||
return m_files.end();
|
||||
else
|
||||
return m_remapped_files.end();
|
||||
}
|
||||
|
||||
reverse_file_iterator rbegin_files(bool storage = false) const
|
||||
{
|
||||
if (!storage || m_remapped_files.empty())
|
||||
return m_files.rbegin();
|
||||
else
|
||||
return m_remapped_files.rbegin();
|
||||
}
|
||||
|
||||
reverse_file_iterator rend_files(bool storage = false) const
|
||||
{
|
||||
if (!storage || m_remapped_files.empty())
|
||||
return m_files.rend();
|
||||
else
|
||||
return m_remapped_files.rend();
|
||||
}
|
||||
|
||||
int num_files(bool storage = false) const
|
||||
{
|
||||
TORRENT_ASSERT(m_piece_length > 0);
|
||||
if (!storage || m_remapped_files.empty())
|
||||
return int(m_files.size());
|
||||
else
|
||||
return int(m_remapped_files.size());
|
||||
}
|
||||
|
||||
file_entry const& file_at(int index, bool storage = false) const
|
||||
{
|
||||
if (!storage || m_remapped_files.empty())
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0 && index < (int)m_files.size());
|
||||
return m_files[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0 && index < (int)m_remapped_files.size());
|
||||
return m_remapped_files[index];
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<announce_entry> const& trackers() const { return m_urls; }
|
||||
|
||||
size_type total_size() const { TORRENT_ASSERT(m_piece_length > 0); return m_total_size; }
|
||||
int piece_length() const { TORRENT_ASSERT(m_piece_length > 0); return m_piece_length; }
|
||||
int num_pieces() const { TORRENT_ASSERT(m_piece_length > 0); return m_num_pieces; }
|
||||
size_type total_size() const { return m_files.total_size(); }
|
||||
int piece_length() const { return m_files.piece_length(); }
|
||||
int num_pieces() const { return m_files.num_pieces(); }
|
||||
const sha1_hash& info_hash() const { return m_info_hash; }
|
||||
const std::string& name() const { TORRENT_ASSERT(m_piece_length > 0); return m_name; }
|
||||
const std::string& name() const { return m_files.name(); }
|
||||
|
||||
typedef file_storage::iterator file_iterator;
|
||||
typedef file_storage::reverse_iterator reverse_file_iterator;
|
||||
|
||||
file_iterator begin_files() const { return m_files.begin(); }
|
||||
file_iterator end_files() const { return m_files.end(); }
|
||||
reverse_file_iterator rbegin_files() const { return m_files.rbegin(); }
|
||||
reverse_file_iterator rend_files() const { return m_files.rend(); }
|
||||
int num_files() const { return m_files.num_files(); }
|
||||
file_entry const& file_at(int index) const { return m_files.at(index); }
|
||||
|
||||
std::vector<file_slice> map_block(int piece, size_type offset, int size) const
|
||||
{ return m_files.map_block(piece, offset, size); }
|
||||
peer_request map_file(int file, size_type offset, int size) const
|
||||
{ return m_files.map_file(file, offset, size); }
|
||||
|
||||
// ------- start deprecation -------
|
||||
// these functions will be removed in a future version
|
||||
torrent_info(entry const& torrent_file) TORRENT_DEPRECATED;
|
||||
void print(std::ostream& os) const TORRENT_DEPRECATED;
|
||||
// ------- end deprecation -------
|
||||
|
||||
bool is_valid() const { return m_piece_length > 0; }
|
||||
bool is_valid() const { return m_files.is_valid(); }
|
||||
|
||||
bool priv() const { return m_private; }
|
||||
|
||||
int piece_size(int index) const;
|
||||
int piece_size(int index) const { return m_files.piece_size(index); }
|
||||
|
||||
sha1_hash hash_for_piece(int index) const
|
||||
{
|
||||
return sha1_hash(hash_for_piece_ptr(index));
|
||||
}
|
||||
{ return sha1_hash(hash_for_piece_ptr(index)); }
|
||||
|
||||
char const* hash_for_piece_ptr(int index) const
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0);
|
||||
TORRENT_ASSERT(index < m_num_pieces);
|
||||
TORRENT_ASSERT(index < m_files.num_pieces());
|
||||
TORRENT_ASSERT(m_piece_hashes);
|
||||
TORRENT_ASSERT(m_piece_hashes >= m_info_section.get());
|
||||
TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size);
|
||||
|
@ -262,41 +182,18 @@ namespace libtorrent
|
|||
|
||||
bool parse_torrent_file(lazy_entry const& libtorrent, std::string& error);
|
||||
|
||||
file_storage m_files;
|
||||
|
||||
// the urls to the trackers
|
||||
std::vector<announce_entry> m_urls;
|
||||
|
||||
std::vector<std::string> m_url_seeds;
|
||||
|
||||
// the length of one piece
|
||||
// if this is 0, the torrent_info is
|
||||
// in an uninitialized state
|
||||
int m_piece_length;
|
||||
|
||||
// the list of files that this torrent consists of
|
||||
std::vector<file_entry> m_files;
|
||||
|
||||
// this vector is typically empty. If it is not
|
||||
// empty, it means the user has re-mapped the
|
||||
// files in this torrent to different names
|
||||
// on disk. This is only used when reading and
|
||||
// writing the disk.
|
||||
std::vector<file_entry> m_remapped_files;
|
||||
|
||||
nodes_t m_nodes;
|
||||
|
||||
// the sum of all filesizes
|
||||
size_type m_total_size;
|
||||
|
||||
// the number of pieces in the torrent
|
||||
int m_num_pieces;
|
||||
|
||||
// the hash that identifies this torrent
|
||||
// is mutable because it's calculated
|
||||
// lazily
|
||||
sha1_hash m_info_hash;
|
||||
|
||||
std::string m_name;
|
||||
|
||||
// if a creation date is found in the torrent file
|
||||
// this will be set to that, otherwise it'll be
|
||||
// 1970, Jan 1
|
||||
|
|
|
@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#if BOOST_VERSION < 103500
|
||||
#include <asio/ip/host_name.hpp>
|
||||
#include <asio/ip/multicast.hpp>
|
||||
|
|
|
@ -937,21 +937,11 @@ namespace libtorrent
|
|||
|
||||
buffer::const_interval recv_buffer = receive_buffer();
|
||||
|
||||
std::vector<bool> bitfield;
|
||||
bitfield bits;
|
||||
bits.borrow_bytes((char*)recv_buffer.begin + 1
|
||||
, t->valid_metadata()?get_bitfield().size():(packet_size()-1)*8);
|
||||
|
||||
if (!t->valid_metadata())
|
||||
bitfield.resize((packet_size() - 1) * 8);
|
||||
else
|
||||
bitfield.resize(get_bitfield().size());
|
||||
|
||||
// if we don't have metadata yet
|
||||
// just remember the bitmask
|
||||
// don't update the piecepicker
|
||||
// (since it doesn't exist yet)
|
||||
for (int i = 0; i < (int)bitfield.size(); ++i)
|
||||
bitfield[i] = (recv_buffer[1 + (i>>3)] & (1 << (7 - (i&7)))) != 0;
|
||||
|
||||
incoming_bitfield(bitfield);
|
||||
incoming_bitfield(bits);
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
|
@ -1426,7 +1416,7 @@ namespace libtorrent
|
|||
send_buffer(msg, sizeof(msg));
|
||||
}
|
||||
|
||||
void bt_peer_connection::write_bitfield(std::vector<bool> const& bitfield)
|
||||
void bt_peer_connection::write_bitfield(bitfield const& bits)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
|
@ -1459,12 +1449,14 @@ namespace libtorrent
|
|||
return;
|
||||
}
|
||||
|
||||
int num_pieces = bitfield.size();
|
||||
int num_pieces = bits.size();
|
||||
int lazy_pieces[50];
|
||||
int num_lazy_pieces = 0;
|
||||
int lazy_piece = 0;
|
||||
|
||||
TORRENT_ASSERT(t->is_seed() == (std::count(bitfield.begin(), bitfield.end(), true) == num_pieces));
|
||||
TORRENT_ASSERT(t->is_seed() == (bits.count()
|
||||
== num_pieces));
|
||||
|
||||
if (t->is_seed() && m_ses.settings().lazy_bitfields)
|
||||
{
|
||||
num_lazy_pieces = (std::min)(50, num_pieces / 10);
|
||||
|
@ -1491,7 +1483,7 @@ namespace libtorrent
|
|||
++lazy_piece;
|
||||
continue;
|
||||
}
|
||||
if (bitfield[i]) bitfield_string << "1";
|
||||
if (bits[i]) bitfield_string << "1";
|
||||
else bitfield_string << "0";
|
||||
}
|
||||
bitfield_string << "\n";
|
||||
|
@ -1506,18 +1498,9 @@ namespace libtorrent
|
|||
detail::write_int32(packet_size - 4, i.begin);
|
||||
detail::write_uint8(msg_bitfield, i.begin);
|
||||
|
||||
std::fill(i.begin, i.end, 0);
|
||||
for (int c = 0; c < num_pieces; ++c)
|
||||
{
|
||||
if (lazy_piece < num_lazy_pieces
|
||||
&& lazy_pieces[lazy_piece] == c)
|
||||
{
|
||||
++lazy_piece;
|
||||
continue;
|
||||
}
|
||||
if (bitfield[c])
|
||||
i.begin[c >> 3] |= 1 << (7 - (c & 7));
|
||||
}
|
||||
memcpy(i.begin, bits.bytes(), packet_size - 5);
|
||||
for (int c = 0; c < num_lazy_pieces; ++c)
|
||||
i.begin[lazy_pieces[c] / 8] &= ~(0x80 >> (lazy_pieces[c] & 7));
|
||||
TORRENT_ASSERT(i.end - i.begin == (num_pieces + 7) / 8);
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
|
|
@ -31,7 +31,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/file_pool.hpp"
|
||||
#include "libtorrent/storage.hpp"
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/date_time/gregorian/gregorian.hpp>
|
||||
|
@ -41,22 +42,61 @@ namespace gr = boost::gregorian;
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
create_torrent::create_torrent()
|
||||
: m_piece_length(0)
|
||||
, m_total_size(0)
|
||||
, m_num_pieces(0)
|
||||
, m_info_hash()
|
||||
, m_name()
|
||||
create_torrent::create_torrent(file_storage& fs, int size)
|
||||
: m_files(fs)
|
||||
, m_creation_date(pt::second_clock::universal_time())
|
||||
, m_multifile(false)
|
||||
, m_multifile(fs.num_files() > 1)
|
||||
, m_private(false)
|
||||
{}
|
||||
{
|
||||
TORRENT_ASSERT(fs.num_files() > 0);
|
||||
if (!m_multifile && m_files.at(0).path.has_branch_path()) m_multifile = true;
|
||||
|
||||
// make sure the size is an even power of 2
|
||||
#ifndef NDEBUG
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
if (size & (1 << i))
|
||||
{
|
||||
TORRENT_ASSERT((size & ~(1 << i)) == 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
m_files.set_piece_length(size);
|
||||
m_files.set_num_pieces(static_cast<int>(
|
||||
(m_files.total_size() + m_files.piece_length() - 1) / m_files.piece_length()));
|
||||
m_piece_hash.resize(m_files.num_pieces());
|
||||
}
|
||||
|
||||
create_torrent::create_torrent(file_storage& fs)
|
||||
: m_files(fs)
|
||||
, m_creation_date(pt::second_clock::universal_time())
|
||||
, m_multifile(fs.num_files() > 1)
|
||||
, m_private(false)
|
||||
{
|
||||
TORRENT_ASSERT(fs.num_files() > 0);
|
||||
if (!m_multifile && m_files.at(0).path.has_branch_path()) m_multifile = true;
|
||||
|
||||
const int target_size = 40 * 1024;
|
||||
int size = fs.total_size() / (target_size / 20);
|
||||
|
||||
for (int i = 4*1024*1024; i > 16*1024; i /= 2)
|
||||
{
|
||||
if (size < i) continue;
|
||||
size = i;
|
||||
break;
|
||||
}
|
||||
|
||||
m_files.set_piece_length(size);
|
||||
m_files.set_num_pieces(static_cast<int>(
|
||||
(m_files.total_size() + m_files.piece_length() - 1) / m_files.piece_length()));
|
||||
m_piece_hash.resize(m_files.num_pieces());
|
||||
}
|
||||
entry create_torrent::generate() const
|
||||
{
|
||||
TORRENT_ASSERT(m_piece_length > 0);
|
||||
TORRENT_ASSERT(m_files.piece_length() > 0);
|
||||
|
||||
if (m_files.empty())
|
||||
if (m_files.num_files() == 0)
|
||||
{
|
||||
// TODO: throw something here
|
||||
// throw
|
||||
|
@ -128,15 +168,13 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
entry& info = dict["info"];
|
||||
|
||||
info["name"] = m_name;
|
||||
|
||||
info["name"] = m_files.name();
|
||||
|
||||
if (m_private) info["private"] = 1;
|
||||
|
||||
if (!m_multifile)
|
||||
{
|
||||
info["length"] = m_files.front().second;
|
||||
info["length"] = m_files.at(0).size;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -144,19 +182,19 @@ namespace libtorrent
|
|||
{
|
||||
entry& files = info["files"];
|
||||
|
||||
for (std::vector<file_entry>::const_iterator i = m_files.begin();
|
||||
for (file_storage::iterator i = m_files.begin();
|
||||
i != m_files.end(); ++i)
|
||||
{
|
||||
files.list().push_back(entry());
|
||||
entry& file_e = files.list().back();
|
||||
file_e["length"] = i->second;
|
||||
file_e["length"] = i->size;
|
||||
entry& path_e = file_e["path"];
|
||||
|
||||
TORRENT_ASSERT(i->first.has_branch_path());
|
||||
TORRENT_ASSERT(*i->first.begin() == m_name);
|
||||
TORRENT_ASSERT(i->path.has_branch_path());
|
||||
TORRENT_ASSERT(*i->path.begin() == m_files.name());
|
||||
|
||||
for (fs::path::iterator j = boost::next(i->first.begin());
|
||||
j != i->first.end(); ++j)
|
||||
for (fs::path::iterator j = boost::next(i->path.begin());
|
||||
j != i->path.end(); ++j)
|
||||
{
|
||||
path_e.list().push_back(entry(*j));
|
||||
}
|
||||
|
@ -164,7 +202,7 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
info["piece length"] = m_piece_length;
|
||||
info["piece length"] = m_files.piece_length();
|
||||
entry& pieces = info["pieces"];
|
||||
|
||||
std::string& p = pieces.string();
|
||||
|
@ -183,21 +221,6 @@ namespace libtorrent
|
|||
|
||||
}
|
||||
|
||||
int create_torrent::piece_size(int index) const
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0 && index < num_pieces());
|
||||
if (index == num_pieces()-1)
|
||||
{
|
||||
int size = int(m_total_size
|
||||
- (num_pieces() - 1) * piece_length());
|
||||
TORRENT_ASSERT(size > 0);
|
||||
TORRENT_ASSERT(size <= piece_length());
|
||||
return int(size);
|
||||
}
|
||||
else
|
||||
return piece_length();
|
||||
}
|
||||
|
||||
void create_torrent::add_tracker(std::string const& url, int tier)
|
||||
{
|
||||
m_urls.push_back(announce_entry(url, tier));
|
||||
|
@ -207,32 +230,6 @@ namespace libtorrent
|
|||
, bind(&announce_entry::second, _1) < bind(&announce_entry::second, _2));
|
||||
}
|
||||
|
||||
void create_torrent::set_piece_size(int size)
|
||||
{
|
||||
// make sure the size is an even power of 2
|
||||
#ifndef NDEBUG
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
if (size & (1 << i))
|
||||
{
|
||||
TORRENT_ASSERT((size & ~(1 << i)) == 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
m_piece_length = size;
|
||||
|
||||
m_num_pieces = static_cast<int>(
|
||||
(m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
int old_num_pieces = static_cast<int>(m_piece_hash.size());
|
||||
|
||||
m_piece_hash.resize(m_num_pieces);
|
||||
for (int i = old_num_pieces; i < m_num_pieces; ++i)
|
||||
{
|
||||
m_piece_hash[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
void create_torrent::set_hash(int index, sha1_hash const& h)
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0);
|
||||
|
@ -240,46 +237,6 @@ namespace libtorrent
|
|||
m_piece_hash[index] = h;
|
||||
}
|
||||
|
||||
void create_torrent::add_file(fs::path file, size_type size)
|
||||
{
|
||||
// TORRENT_ASSERT(file.begin() != file.end());
|
||||
|
||||
if (!file.has_branch_path())
|
||||
{
|
||||
// you have already added at least one file with a
|
||||
// path to the file (branch_path), which means that
|
||||
// all the other files need to be in the same top
|
||||
// directory as the first file.
|
||||
TORRENT_ASSERT(m_files.empty());
|
||||
TORRENT_ASSERT(!m_multifile);
|
||||
m_name = file.string();
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (!m_files.empty())
|
||||
TORRENT_ASSERT(m_name == *file.begin());
|
||||
#endif
|
||||
m_multifile = true;
|
||||
m_name = *file.begin();
|
||||
}
|
||||
|
||||
m_files.push_back(file_entry(file, size));
|
||||
|
||||
m_total_size += size;
|
||||
|
||||
if (m_piece_length == 0)
|
||||
m_piece_length = 256 * 1024;
|
||||
|
||||
m_num_pieces = int((m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
int old_num_pieces = int(m_piece_hash.size());
|
||||
|
||||
m_piece_hash.resize(m_num_pieces);
|
||||
if (m_num_pieces > old_num_pieces)
|
||||
std::for_each(m_piece_hash.begin() + old_num_pieces
|
||||
, m_piece_hash.end(), boost::bind(&sha1_hash::clear, _1));
|
||||
}
|
||||
|
||||
void create_torrent::add_node(std::pair<std::string, int> const& node)
|
||||
{
|
||||
m_nodes.push_back(node);
|
||||
|
@ -299,5 +256,6 @@ namespace libtorrent
|
|||
{
|
||||
m_created_by = str;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1049,6 +1049,13 @@ namespace libtorrent
|
|||
ret = 0;
|
||||
break;
|
||||
}
|
||||
case disk_io_job::rename_file:
|
||||
{
|
||||
#ifdef TORRENT_DISK_STATS
|
||||
m_log << log_time() << " rename file" << std::endl;
|
||||
#endif
|
||||
ret = j.storage->rename_file_impl(j.piece, j.str);
|
||||
}
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
} catch (std::exception& e)
|
||||
|
|
|
@ -115,6 +115,16 @@ namespace libtorrent
|
|||
return e.file_ptr;
|
||||
}
|
||||
|
||||
void file_pool::release(fs::path const& p)
|
||||
{
|
||||
boost::mutex::scoped_lock l(m_mutex);
|
||||
|
||||
typedef nth_index<file_set, 0>::type path_view;
|
||||
path_view& pt = get<0>(m_files);
|
||||
path_view::iterator i = pt.find(p);
|
||||
if (i != pt.end()) pt.erase(i);
|
||||
}
|
||||
|
||||
void file_pool::release(void* st)
|
||||
{
|
||||
boost::mutex::scoped_lock l(m_mutex);
|
||||
|
|
150
libtorrent/src/file_storage.cpp
Normal file
150
libtorrent/src/file_storage.cpp
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2003-2008, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include "libtorrent/file_storage.hpp"
|
||||
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
file_storage::file_storage()
|
||||
: m_piece_length(0)
|
||||
, m_total_size(0)
|
||||
, m_num_pieces(0)
|
||||
{}
|
||||
|
||||
int file_storage::piece_size(int index) const
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0 && index < num_pieces());
|
||||
if (index == num_pieces()-1)
|
||||
{
|
||||
int size = int(total_size()
|
||||
- size_type(num_pieces() - 1) * piece_length());
|
||||
TORRENT_ASSERT(size > 0);
|
||||
TORRENT_ASSERT(size <= piece_length());
|
||||
return int(size);
|
||||
}
|
||||
else
|
||||
return piece_length();
|
||||
}
|
||||
|
||||
void file_storage::rename_file(int index, std::string const& new_filename)
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0 && index < int(m_files.size()));
|
||||
m_files[index].path = new_filename;
|
||||
}
|
||||
|
||||
std::vector<file_slice> file_storage::map_block(int piece, size_type offset
|
||||
, int size_) const
|
||||
{
|
||||
TORRENT_ASSERT(num_files() > 0);
|
||||
std::vector<file_slice> ret;
|
||||
|
||||
size_type start = piece * (size_type)m_piece_length + offset;
|
||||
size_type size = size_;
|
||||
TORRENT_ASSERT(start + size <= m_total_size);
|
||||
|
||||
// find the file iterator and file offset
|
||||
// TODO: make a vector that can map piece -> file index in O(1)
|
||||
size_type file_offset = start;
|
||||
std::vector<file_entry>::const_iterator file_iter;
|
||||
|
||||
int counter = 0;
|
||||
for (file_iter = begin();; ++counter, ++file_iter)
|
||||
{
|
||||
TORRENT_ASSERT(file_iter != end());
|
||||
if (file_offset < file_iter->size)
|
||||
{
|
||||
file_slice f;
|
||||
f.file_index = counter;
|
||||
f.offset = file_offset + file_iter->file_base;
|
||||
f.size = (std::min)(file_iter->size - file_offset, (size_type)size);
|
||||
size -= f.size;
|
||||
file_offset += f.size;
|
||||
ret.push_back(f);
|
||||
}
|
||||
|
||||
TORRENT_ASSERT(size >= 0);
|
||||
if (size <= 0) break;
|
||||
|
||||
file_offset -= file_iter->size;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
peer_request file_storage::map_file(int file_index, size_type file_offset
|
||||
, int size) const
|
||||
{
|
||||
TORRENT_ASSERT(file_index < num_files());
|
||||
TORRENT_ASSERT(file_index >= 0);
|
||||
size_type offset = file_offset + at(file_index).offset;
|
||||
|
||||
peer_request ret;
|
||||
ret.piece = int(offset / piece_length());
|
||||
ret.start = int(offset - ret.piece * piece_length());
|
||||
ret.length = size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void file_storage::add_file(fs::path const& file, size_type size)
|
||||
{
|
||||
TORRENT_ASSERT(size >= 0);
|
||||
if (!file.has_branch_path())
|
||||
{
|
||||
// you have already added at least one file with a
|
||||
// path to the file (branch_path), which means that
|
||||
// all the other files need to be in the same top
|
||||
// directory as the first file.
|
||||
TORRENT_ASSERT(m_files.empty());
|
||||
m_name = file.string();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_files.empty())
|
||||
m_name = *file.begin();
|
||||
}
|
||||
TORRENT_ASSERT(m_name == *file.begin());
|
||||
file_entry e;
|
||||
m_files.push_back(e);
|
||||
m_files.back().size = size;
|
||||
m_files.back().path = file;
|
||||
m_files.back().offset = m_total_size;
|
||||
m_total_size += size;
|
||||
}
|
||||
|
||||
void file_storage::add_file(file_entry const& e)
|
||||
{
|
||||
add_file(e.path, e.size);
|
||||
}
|
||||
}
|
||||
|
|
@ -408,7 +408,7 @@ void node_impl::on_announce(msg const& m, msg& reply)
|
|||
|
||||
torrent_entry& v = m_map[m.info_hash];
|
||||
peer_entry e;
|
||||
e.addr = tcp::endpoint(m.addr.address(), m.addr.port());
|
||||
e.addr = tcp::endpoint(m.addr.address(), m.port);
|
||||
e.added = time_now();
|
||||
std::set<peer_entry>::iterator i = v.peers.find(e);
|
||||
if (i != v.peers.end()) v.peers.erase(i++);
|
||||
|
|
|
@ -206,7 +206,7 @@ namespace libtorrent
|
|||
int num_digits(int val)
|
||||
{
|
||||
int ret = 1;
|
||||
while (val > 10)
|
||||
while (val >= 10)
|
||||
{
|
||||
++ret;
|
||||
val /= 10;
|
||||
|
|
|
@ -64,7 +64,9 @@ namespace libtorrent
|
|||
{
|
||||
namespace fs = boost::filesystem;
|
||||
#if BOOST_VERSION >= 103500
|
||||
using boost::system::error_code;
|
||||
typedef boost::system::error_code ec_t;
|
||||
#else
|
||||
typedef error_code ec_t;
|
||||
#endif
|
||||
|
||||
struct mapped_file_pool
|
||||
|
@ -85,7 +87,7 @@ namespace libtorrent
|
|||
#ifndef NDEBUG
|
||||
if (file_size > 0)
|
||||
{
|
||||
error_code ec;
|
||||
ec_t ec;
|
||||
fs::file_status st = fs::status(path, ec);
|
||||
TORRENT_ASSERT(!fs::exists(st));
|
||||
}
|
||||
|
@ -207,7 +209,7 @@ namespace libtorrent
|
|||
#if BOOST_VERSION < 103500
|
||||
fs::system_error_type ec;
|
||||
#else
|
||||
error_code ec;
|
||||
ec_t ec;
|
||||
#endif
|
||||
fs::file_status st = fs::status(p, ec);
|
||||
|
||||
|
@ -260,8 +262,8 @@ namespace libtorrent
|
|||
|
||||
struct mapped_storage: storage_interface
|
||||
{
|
||||
mapped_storage(boost::intrusive_ptr<torrent_info const> const& info, fs::path save_path)
|
||||
: m_info(info)
|
||||
mapped_storage(file_storage const& fs, fs::path save_path)
|
||||
: m_files(fs)
|
||||
, m_save_path(save_path)
|
||||
{}
|
||||
|
||||
|
@ -270,9 +272,9 @@ namespace libtorrent
|
|||
int read(char* buf, int slot, int offset, int size)
|
||||
{
|
||||
TORRENT_ASSERT(buf != 0);
|
||||
TORRENT_ASSERT(slot >= 0 && slot < m_info->num_pieces());
|
||||
TORRENT_ASSERT(slot >= 0 && slot < m_files.num_pieces());
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(offset < m_info->piece_size(slot));
|
||||
TORRENT_ASSERT(offset < m_files.piece_size(slot));
|
||||
TORRENT_ASSERT(size > 0);
|
||||
|
||||
size_type result = -1;
|
||||
|
@ -281,17 +283,17 @@ namespace libtorrent
|
|||
|
||||
#ifndef NDEBUG
|
||||
std::vector<file_slice> slices
|
||||
= m_info->map_block(slot, offset, size, true);
|
||||
= files().map_block(slot, offset, size);
|
||||
TORRENT_ASSERT(!slices.empty());
|
||||
#endif
|
||||
size_type start = slot * (size_type)m_info->piece_length() + offset;
|
||||
TORRENT_ASSERT(start + size <= m_info->total_size());
|
||||
size_type start = slot * (size_type)m_files.piece_length() + offset;
|
||||
TORRENT_ASSERT(start + size <= m_files.total_size());
|
||||
|
||||
// find the file iterator and file offset
|
||||
size_type file_offset = start;
|
||||
std::vector<file_entry>::const_iterator file_iter;
|
||||
|
||||
for (file_iter = m_info->begin_files(true);;)
|
||||
for (file_iter = files().begin();;)
|
||||
{
|
||||
if (file_offset < file_iter->size)
|
||||
break;
|
||||
|
@ -331,7 +333,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(int(slices.size()) > counter);
|
||||
size_type slice_size = slices[counter].size;
|
||||
TORRENT_ASSERT(slice_size == read_bytes);
|
||||
TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path
|
||||
TORRENT_ASSERT(files().at(slices[counter].file_index).path
|
||||
== file_iter->path);
|
||||
#endif
|
||||
|
||||
|
@ -351,7 +353,7 @@ namespace libtorrent
|
|||
{
|
||||
++file_iter;
|
||||
// skip empty files
|
||||
while (file_iter != m_info->end_files(true) && file_iter->size == 0)
|
||||
while (file_iter != files().end() && file_iter->size == 0)
|
||||
++file_iter;
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
@ -388,24 +390,24 @@ namespace libtorrent
|
|||
int write(const char* buf, int slot, int offset, int size)
|
||||
{
|
||||
TORRENT_ASSERT(buf != 0);
|
||||
TORRENT_ASSERT(slot >= 0 && slot < m_info->num_pieces());
|
||||
TORRENT_ASSERT(slot >= 0 && slot < m_files.num_pieces());
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(offset < m_info->piece_size(slot));
|
||||
TORRENT_ASSERT(offset < m_files.piece_size(slot));
|
||||
TORRENT_ASSERT(size > 0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::vector<file_slice> slices
|
||||
= m_info->map_block(slot, offset, size, true);
|
||||
= files().map_block(slot, offset, size);
|
||||
TORRENT_ASSERT(!slices.empty());
|
||||
#endif
|
||||
size_type start = slot * (size_type)m_info->piece_length() + offset;
|
||||
TORRENT_ASSERT(start + size <= m_info->total_size());
|
||||
size_type start = slot * (size_type)m_files.piece_length() + offset;
|
||||
TORRENT_ASSERT(start + size <= m_files.total_size());
|
||||
|
||||
// find the file iterator and file offset
|
||||
size_type file_offset = start;
|
||||
std::vector<file_entry>::const_iterator file_iter;
|
||||
|
||||
for (file_iter = m_info->begin_files(true);;)
|
||||
for (file_iter = files().begin();;)
|
||||
{
|
||||
if (file_offset < file_iter->size)
|
||||
break;
|
||||
|
@ -447,7 +449,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(int(slices.size()) > counter);
|
||||
size_type slice_size = slices[counter].size;
|
||||
TORRENT_ASSERT(slice_size == write_bytes);
|
||||
TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path
|
||||
TORRENT_ASSERT(files().at(slices[counter].file_index).path
|
||||
== file_iter->path);
|
||||
#endif
|
||||
|
||||
|
@ -466,7 +468,7 @@ namespace libtorrent
|
|||
if (left_to_write > 0)
|
||||
{
|
||||
++file_iter;
|
||||
while (file_iter != m_info->end_files(true) && file_iter->size == 0)
|
||||
while (file_iter != files().end() && file_iter->size == 0)
|
||||
++file_iter;
|
||||
#ifndef NDEBUG
|
||||
// empty files are not returned by map_block, so if
|
||||
|
@ -531,11 +533,11 @@ namespace libtorrent
|
|||
m_pool.release(this);
|
||||
|
||||
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
|
||||
old_path = safe_convert((m_save_path / m_info->name()).string());
|
||||
new_path = safe_convert((save_path / m_info->name()).string());
|
||||
old_path = safe_convert((m_save_path / files().name()).string());
|
||||
new_path = safe_convert((save_path / files().name()).string());
|
||||
#else
|
||||
old_path = m_save_path / m_info->name();
|
||||
new_path = save_path / m_info->name();
|
||||
old_path = m_save_path / files().name();
|
||||
new_path = save_path / files().name();
|
||||
#endif
|
||||
|
||||
try
|
||||
|
@ -602,7 +604,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
entry::list_type const& slots = slots_ent->list();
|
||||
bool seed = int(slots.size()) == m_info->num_pieces()
|
||||
bool seed = int(slots.size()) == files().num_pieces()
|
||||
&& std::find_if(slots.begin(), slots.end()
|
||||
, boost::bind<bool>(std::less<int>()
|
||||
, boost::bind((size_type const& (entry::*)() const)
|
||||
|
@ -615,11 +617,11 @@ namespace libtorrent
|
|||
|
||||
if (seed)
|
||||
{
|
||||
if (m_info->num_files(true) != (int)file_sizes.size())
|
||||
if (files().num_files() != (int)file_sizes.size())
|
||||
{
|
||||
error = "the number of files does not match the torrent (num: "
|
||||
+ boost::lexical_cast<std::string>(file_sizes.size()) + " actual: "
|
||||
+ boost::lexical_cast<std::string>(m_info->num_files(true)) + ")";
|
||||
+ boost::lexical_cast<std::string>(files().num_files()) + ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -627,8 +629,8 @@ namespace libtorrent
|
|||
fs = file_sizes.begin();
|
||||
// the resume data says we have the entire torrent
|
||||
// make sure the file sizes are the right ones
|
||||
for (torrent_info::file_iterator i = m_info->begin_files(true)
|
||||
, end(m_info->end_files(true)); i != end; ++i, ++fs)
|
||||
for (file_storage::iterator i = files().begin()
|
||||
, end(files().end()); i != end; ++i, ++fs)
|
||||
{
|
||||
if (i->size != fs->first)
|
||||
{
|
||||
|
@ -641,7 +643,7 @@ namespace libtorrent
|
|||
return true;
|
||||
}
|
||||
|
||||
return match_filesizes(*m_info, m_save_path, file_sizes
|
||||
return match_filesizes(files(), m_save_path, file_sizes
|
||||
, !full_allocation_mode, &error);
|
||||
}
|
||||
|
||||
|
@ -653,7 +655,7 @@ namespace libtorrent
|
|||
return true;
|
||||
}
|
||||
std::vector<std::pair<size_type, std::time_t> > file_sizes
|
||||
= get_filesizes(*m_info, m_save_path);
|
||||
= get_filesizes(m_files, m_save_path);
|
||||
|
||||
entry::list_type& fl = rd["file sizes"].list();
|
||||
for (std::vector<std::pair<size_type, std::time_t> >::iterator i
|
||||
|
@ -670,7 +672,7 @@ namespace libtorrent
|
|||
bool move_slot(int src_slot, int dst_slot)
|
||||
{
|
||||
// TODO: this can be optimized by mapping both slots and do a straight memcpy
|
||||
int piece_size = m_info->piece_size(dst_slot);
|
||||
int piece_size = m_files.piece_size(dst_slot);
|
||||
m_scratch_buffer.resize(piece_size);
|
||||
size_type ret1 = read(&m_scratch_buffer[0], src_slot, 0, piece_size);
|
||||
size_type ret2 = write(&m_scratch_buffer[0], dst_slot, 0, piece_size);
|
||||
|
@ -681,9 +683,9 @@ namespace libtorrent
|
|||
{
|
||||
// TODO: this can be optimized by mapping both slots and do a straight memcpy
|
||||
// the size of the target slot is the size of the piece
|
||||
int piece_size = m_info->piece_length();
|
||||
int piece1_size = m_info->piece_size(slot2);
|
||||
int piece2_size = m_info->piece_size(slot1);
|
||||
int piece_size = m_files.piece_length();
|
||||
int piece1_size = m_files.piece_size(slot2);
|
||||
int piece2_size = m_files.piece_size(slot1);
|
||||
m_scratch_buffer.resize(piece_size * 2);
|
||||
size_type ret1 = read(&m_scratch_buffer[0], slot1, 0, piece1_size);
|
||||
size_type ret2 = read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size);
|
||||
|
@ -697,10 +699,10 @@ namespace libtorrent
|
|||
{
|
||||
// TODO: this can be optimized by mapping both slots and do a straight memcpy
|
||||
// the size of the target slot is the size of the piece
|
||||
int piece_size = m_info->piece_length();
|
||||
int piece1_size = m_info->piece_size(slot2);
|
||||
int piece2_size = m_info->piece_size(slot3);
|
||||
int piece3_size = m_info->piece_size(slot1);
|
||||
int piece_size = m_files.piece_length();
|
||||
int piece1_size = m_files.piece_size(slot2);
|
||||
int piece2_size = m_files.piece_size(slot3);
|
||||
int piece3_size = m_files.piece_size(slot1);
|
||||
m_scratch_buffer.resize(piece_size * 2);
|
||||
size_type ret1 = read(&m_scratch_buffer[0], slot1, 0, piece1_size);
|
||||
size_type ret2 = read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size);
|
||||
|
@ -743,6 +745,39 @@ namespace libtorrent
|
|||
#endif
|
||||
}
|
||||
|
||||
bool rename_file(int index, std::string const& new_filename)
|
||||
{
|
||||
if (index < 0 || index >= m_files.num_files()) return true;
|
||||
fs::path old_name = m_save_path / files().at(index).path;
|
||||
m_pool.release(this);
|
||||
|
||||
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
|
||||
fs::wpath old_path = safe_convert(old_name);
|
||||
fs::wpath new_path = safe_convert(m_save_path / new_filename);
|
||||
#else
|
||||
fs::path const& old_path = old_name;
|
||||
fs::path new_path = m_save_path / new_filename;
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
rename(old_path, new_path);
|
||||
if (!m_mapped_files)
|
||||
{ m_mapped_files.reset(new file_storage(m_files)); }
|
||||
m_mapped_files->rename_file(index, new_filename);
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
set_error(old_name.string(), e.what());
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool release_files()
|
||||
{
|
||||
m_pool.release(this);
|
||||
|
@ -762,8 +797,8 @@ namespace libtorrent
|
|||
// delete the files from disk
|
||||
std::set<std::string> directories;
|
||||
typedef std::set<std::string>::iterator iter_t;
|
||||
for (torrent_info::file_iterator i = m_info->begin_files(true)
|
||||
, end(m_info->end_files(true)); i != end; ++i)
|
||||
for (file_storage::iterator i = m_files.begin()
|
||||
, end(m_files.end()); i != end; ++i)
|
||||
{
|
||||
std::string p = (m_save_path / i->path).string();
|
||||
fs::path bp = i->path.branch_path();
|
||||
|
@ -802,7 +837,10 @@ namespace libtorrent
|
|||
|
||||
private:
|
||||
|
||||
boost::intrusive_ptr<torrent_info const> m_info;
|
||||
file_storage const& files() const { return m_mapped_files?*m_mapped_files:m_files; }
|
||||
|
||||
boost::scoped_ptr<file_storage> m_mapped_files;
|
||||
file_storage const& m_files;
|
||||
fs::path m_save_path;
|
||||
|
||||
// temporary storage for moving pieces
|
||||
|
@ -811,10 +849,10 @@ namespace libtorrent
|
|||
static mapped_file_pool m_pool;
|
||||
};
|
||||
|
||||
storage_interface* mapped_storage_constructor(boost::intrusive_ptr<torrent_info const> ti
|
||||
storage_interface* mapped_storage_constructor(file_storage const& fs
|
||||
, fs::path const& path, file_pool& fp)
|
||||
{
|
||||
return new mapped_storage(ti, path);
|
||||
return new mapped_storage(fs, path);
|
||||
}
|
||||
|
||||
mapped_file_pool mapped_storage::m_pool;
|
||||
|
|
|
@ -32,7 +32,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "libtorrent/pch.hpp"
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#if BOOST_VERSION < 103500
|
||||
#include <asio/ip/host_name.hpp>
|
||||
#else
|
||||
|
|
|
@ -326,7 +326,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(t);
|
||||
|
||||
bool interested = false;
|
||||
const std::vector<bool>& we_have = t->pieces();
|
||||
bitfield const& we_have = t->pieces();
|
||||
for (int j = 0; j != (int)we_have.size(); ++j)
|
||||
{
|
||||
if (!we_have[j]
|
||||
|
@ -579,7 +579,7 @@ namespace libtorrent
|
|||
m_statistics.add_stat(downloaded, uploaded);
|
||||
}
|
||||
|
||||
std::vector<bool> const& peer_connection::get_bitfield() const
|
||||
bitfield const& peer_connection::get_bitfield() const
|
||||
{
|
||||
return m_have_piece;
|
||||
}
|
||||
|
@ -749,7 +749,7 @@ namespace libtorrent
|
|||
// if we don't have valid metadata yet,
|
||||
// leave the vector unallocated
|
||||
TORRENT_ASSERT(m_num_pieces == 0);
|
||||
std::fill(m_have_piece.begin(), m_have_piece.end(), false);
|
||||
m_have_piece.clear_all();
|
||||
TORRENT_ASSERT(!m_torrent.expired());
|
||||
}
|
||||
|
||||
|
@ -1082,7 +1082,7 @@ namespace libtorrent
|
|||
}
|
||||
else
|
||||
{
|
||||
m_have_piece[index] = true;
|
||||
m_have_piece.set_bit(index);
|
||||
|
||||
// only update the piece_picker if
|
||||
// we have the metadata and if
|
||||
|
@ -1127,7 +1127,7 @@ namespace libtorrent
|
|||
// --------- BITFIELD ----------
|
||||
// -----------------------------
|
||||
|
||||
void peer_connection::incoming_bitfield(std::vector<bool> const& bitfield)
|
||||
void peer_connection::incoming_bitfield(bitfield const& bits)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
|
@ -1138,7 +1138,7 @@ namespace libtorrent
|
|||
for (extension_list_t::iterator i = m_extensions.begin()
|
||||
, end(m_extensions.end()); i != end; ++i)
|
||||
{
|
||||
if ((*i)->on_bitfield(bitfield)) return;
|
||||
if ((*i)->on_bitfield(bits)) return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1147,9 +1147,9 @@ namespace libtorrent
|
|||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
(*m_logger) << time_now_string() << " <== BITFIELD ";
|
||||
|
||||
for (int i = 0; i < int(bitfield.size()); ++i)
|
||||
for (int i = 0; i < int(bits.size()); ++i)
|
||||
{
|
||||
if (bitfield[i]) (*m_logger) << "1";
|
||||
if (bits[i]) (*m_logger) << "1";
|
||||
else (*m_logger) << "0";
|
||||
}
|
||||
(*m_logger) << "\n";
|
||||
|
@ -1158,10 +1158,10 @@ namespace libtorrent
|
|||
// if we don't have the metedata, we cannot
|
||||
// verify the bitfield size
|
||||
if (t->valid_metadata()
|
||||
&& (bitfield.size() / 8) != (m_have_piece.size() / 8))
|
||||
&& (bits.size() / 8) != (m_have_piece.size() / 8))
|
||||
{
|
||||
std::stringstream msg;
|
||||
msg << "got bitfield with invalid size: " << (bitfield.size() / 8)
|
||||
msg << "got bitfield with invalid size: " << (bits.size() / 8)
|
||||
<< "bytes. expected: " << (m_have_piece.size() / 8)
|
||||
<< " bytes";
|
||||
disconnect(msg.str().c_str(), 2);
|
||||
|
@ -1174,15 +1174,15 @@ namespace libtorrent
|
|||
// (since it doesn't exist yet)
|
||||
if (!t->ready_for_connections())
|
||||
{
|
||||
m_have_piece = bitfield;
|
||||
m_num_pieces = std::count(bitfield.begin(), bitfield.end(), true);
|
||||
if (m_peer_info) m_peer_info->seed = (m_num_pieces == int(bitfield.size()));
|
||||
m_have_piece = bits;
|
||||
m_num_pieces = bits.count();
|
||||
if (m_peer_info) m_peer_info->seed = (m_num_pieces == int(bits.size()));
|
||||
return;
|
||||
}
|
||||
|
||||
TORRENT_ASSERT(t->valid_metadata());
|
||||
|
||||
int num_pieces = std::count(bitfield.begin(), bitfield.end(), true);
|
||||
int num_pieces = bits.count();
|
||||
if (num_pieces == int(m_have_piece.size()))
|
||||
{
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
|
@ -1197,7 +1197,7 @@ namespace libtorrent
|
|||
return;
|
||||
}
|
||||
|
||||
std::fill(m_have_piece.begin(), m_have_piece.end(), true);
|
||||
m_have_piece.set_all();
|
||||
m_num_pieces = num_pieces;
|
||||
t->peer_has_all();
|
||||
if (!t->is_finished())
|
||||
|
@ -1211,11 +1211,11 @@ namespace libtorrent
|
|||
bool interesting = false;
|
||||
if (!t->is_seed())
|
||||
{
|
||||
t->peer_has(bitfield);
|
||||
t->peer_has(bits);
|
||||
|
||||
for (int i = 0; i < (int)m_have_piece.size(); ++i)
|
||||
{
|
||||
bool have = bitfield[i];
|
||||
bool have = bits[i];
|
||||
if (have && !m_have_piece[i])
|
||||
{
|
||||
if (!t->have_piece(i) && t->picker().piece_priority(i) != 0)
|
||||
|
@ -1229,7 +1229,7 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
m_have_piece = bitfield;
|
||||
m_have_piece = bits;
|
||||
m_num_pieces = num_pieces;
|
||||
|
||||
if (interesting) t->get_policy().peer_is_interesting(*this);
|
||||
|
@ -1764,7 +1764,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
TORRENT_ASSERT(!m_have_piece.empty());
|
||||
std::fill(m_have_piece.begin(), m_have_piece.end(), true);
|
||||
m_have_piece.set_all();
|
||||
m_num_pieces = m_have_piece.size();
|
||||
|
||||
t->peer_has_all();
|
||||
|
|
|
@ -42,6 +42,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "libtorrent/piece_picker.hpp"
|
||||
#include "libtorrent/aux_/session_impl.hpp"
|
||||
#include "libtorrent/bitfield.hpp"
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include "libtorrent/peer_connection.hpp"
|
||||
|
@ -122,16 +123,17 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
// pieces is a bitmask with the pieces we have
|
||||
void piece_picker::init(std::vector<bool> const& pieces)
|
||||
void piece_picker::init(bitfield const& pieces)
|
||||
{
|
||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||
#ifndef NDEBUG
|
||||
m_files_checked_called = true;
|
||||
#endif
|
||||
for (std::vector<bool>::const_iterator i = pieces.begin();
|
||||
i != pieces.end(); ++i)
|
||||
int index = 0;
|
||||
for (bitfield::const_iterator i = pieces.begin();
|
||||
i != pieces.end(); ++i, ++index)
|
||||
{
|
||||
int index = static_cast<int>(i - pieces.begin());
|
||||
TORRENT_ASSERT(index < pieces.size());
|
||||
piece_pos& p = m_piece_map[index];
|
||||
if (*i) we_have(index);
|
||||
else TORRENT_ASSERT(p.index == 0);
|
||||
|
@ -214,15 +216,15 @@ namespace libtorrent
|
|||
#ifndef NDEBUG
|
||||
|
||||
void piece_picker::verify_pick(std::vector<piece_block> const& picked
|
||||
, std::vector<bool> const& bitfield) const
|
||||
, bitfield const& bits) const
|
||||
{
|
||||
TORRENT_ASSERT(bitfield.size() == m_piece_map.size());
|
||||
TORRENT_ASSERT(bits.size() == m_piece_map.size());
|
||||
for (std::vector<piece_block>::const_iterator i = picked.begin()
|
||||
, end(picked.end()); i != end; ++i)
|
||||
{
|
||||
TORRENT_ASSERT(i->piece_index >= 0);
|
||||
TORRENT_ASSERT(i->piece_index < int(bitfield.size()));
|
||||
TORRENT_ASSERT(bitfield[i->piece_index]);
|
||||
TORRENT_ASSERT(i->piece_index < int(bits.size()));
|
||||
TORRENT_ASSERT(bits[i->piece_index]);
|
||||
TORRENT_ASSERT(!m_piece_map[i->piece_index].have());
|
||||
}
|
||||
}
|
||||
|
@ -887,14 +889,14 @@ namespace libtorrent
|
|||
if (prev_priority >= 0) update(prev_priority, p.index);
|
||||
}
|
||||
|
||||
void piece_picker::inc_refcount(std::vector<bool> const& bitmask)
|
||||
void piece_picker::inc_refcount(bitfield const& bitmask)
|
||||
{
|
||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||
TORRENT_ASSERT(bitmask.size() == m_piece_map.size());
|
||||
|
||||
int index = 0;
|
||||
bool updated = false;
|
||||
for (std::vector<bool>::const_iterator i = bitmask.begin()
|
||||
for (bitfield::const_iterator i = bitmask.begin()
|
||||
, end(bitmask.end()); i != end; ++i, ++index)
|
||||
{
|
||||
if (*i)
|
||||
|
@ -907,14 +909,14 @@ namespace libtorrent
|
|||
if (updated && m_sequential_download == -1) m_dirty = true;
|
||||
}
|
||||
|
||||
void piece_picker::dec_refcount(std::vector<bool> const& bitmask)
|
||||
void piece_picker::dec_refcount(bitfield const& bitmask)
|
||||
{
|
||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||
TORRENT_ASSERT(bitmask.size() == m_piece_map.size());
|
||||
|
||||
int index = 0;
|
||||
bool updated = false;
|
||||
for (std::vector<bool>::const_iterator i = bitmask.begin()
|
||||
for (bitfield::const_iterator i = bitmask.begin()
|
||||
, end(bitmask.end()); i != end; ++i, ++index)
|
||||
{
|
||||
if (*i)
|
||||
|
@ -1156,7 +1158,7 @@ namespace libtorrent
|
|||
// to pick blocks from the same pieces as fast peers, and vice
|
||||
// versa. Downloading pieces are marked as being fast, medium
|
||||
// or slow once they're started.
|
||||
void piece_picker::pick_pieces(const std::vector<bool>& pieces
|
||||
void piece_picker::pick_pieces(bitfield const& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, int num_blocks, int prefer_whole_pieces
|
||||
, void* peer, piece_state_t speed, bool rarest_first
|
||||
|
@ -1279,7 +1281,7 @@ namespace libtorrent
|
|||
, backup_blocks.begin(), backup_blocks.end());
|
||||
}
|
||||
|
||||
bool piece_picker::can_pick(int piece, std::vector<bool> const& bitmask) const
|
||||
bool piece_picker::can_pick(int piece, bitfield const& bitmask) const
|
||||
{
|
||||
TORRENT_ASSERT(piece >= 0 && piece < int(m_piece_map.size()));
|
||||
return bitmask[piece]
|
||||
|
@ -1326,7 +1328,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
int piece_picker::add_blocks(std::vector<int> const& piece_list
|
||||
, std::vector<bool> const& pieces
|
||||
, bitfield const& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, int num_blocks, int prefer_whole_pieces
|
||||
, void* peer, std::vector<int> const& ignore) const
|
||||
|
@ -1388,7 +1390,7 @@ namespace libtorrent
|
|||
return num_blocks;
|
||||
}
|
||||
|
||||
int piece_picker::add_blocks_downloading(std::vector<bool> const& pieces
|
||||
int piece_picker::add_blocks_downloading(bitfield const& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, int num_blocks, int prefer_whole_pieces
|
||||
|
@ -1580,7 +1582,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
std::pair<int, int> piece_picker::expand_piece(int piece, int whole_pieces
|
||||
, std::vector<bool> const& have) const
|
||||
, bitfield const& have) const
|
||||
{
|
||||
if (whole_pieces == 0) return std::make_pair(piece, piece + 1);
|
||||
|
||||
|
|
|
@ -150,18 +150,7 @@ namespace
|
|||
tcp::endpoint const& m_ep;
|
||||
};
|
||||
|
||||
struct match_peer_id
|
||||
{
|
||||
match_peer_id(peer_id const& id_)
|
||||
: m_id(id_)
|
||||
{}
|
||||
|
||||
bool operator()(std::pair<const address, policy::peer> const& p) const
|
||||
{ return p.second.connection && p.second.connection->pid() == m_id; }
|
||||
|
||||
peer_id const& m_id;
|
||||
};
|
||||
|
||||
#ifndef NDEBUG
|
||||
struct match_peer_connection
|
||||
{
|
||||
match_peer_connection(peer_connection const& c)
|
||||
|
@ -177,7 +166,7 @@ namespace
|
|||
|
||||
peer_connection const& m_conn;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
@ -244,7 +233,7 @@ namespace libtorrent
|
|||
busy_pieces.reserve(num_requests);
|
||||
|
||||
std::vector<int> const& suggested = c.suggested_pieces();
|
||||
std::vector<bool> const& bitfield = c.get_bitfield();
|
||||
bitfield const& bits = c.get_bitfield();
|
||||
|
||||
if (c.has_peer_choked())
|
||||
{
|
||||
|
@ -254,10 +243,10 @@ namespace libtorrent
|
|||
std::vector<int> const& allowed_fast = c.allowed_fast();
|
||||
|
||||
// build a bitmask with only the allowed pieces in it
|
||||
std::vector<bool> mask(c.get_bitfield().size(), false);
|
||||
bitfield mask(c.get_bitfield().size(), false);
|
||||
for (std::vector<int>::const_iterator i = allowed_fast.begin()
|
||||
, end(allowed_fast.end()); i != end; ++i)
|
||||
if (bitfield[*i]) mask[*i] = true;
|
||||
if (bits[*i]) mask.set_bit(*i);
|
||||
|
||||
p.pick_pieces(mask, interesting_pieces
|
||||
, num_requests, prefer_whole_pieces, c.peer_info_struct()
|
||||
|
@ -273,7 +262,7 @@ namespace libtorrent
|
|||
// the last argument is if we should prefer whole pieces
|
||||
// for this peer. If we're downloading one piece in 20 seconds
|
||||
// then use this mode.
|
||||
p.pick_pieces(bitfield, interesting_pieces
|
||||
p.pick_pieces(bits, interesting_pieces
|
||||
, num_requests, prefer_whole_pieces, c.peer_info_struct()
|
||||
, state, rarest_first, c.on_parole(), suggested);
|
||||
}
|
||||
|
@ -445,21 +434,57 @@ namespace libtorrent
|
|||
|
||||
if (m_round_robin == m_peers.end()) m_round_robin = m_peers.begin();
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
bool pinged = false;
|
||||
#endif
|
||||
|
||||
for (int iterations = (std::min)(int(m_peers.size()), 300);
|
||||
iterations > 0; ++m_round_robin, --iterations)
|
||||
iterations > 0; --iterations)
|
||||
{
|
||||
if (m_round_robin == m_peers.end()) m_round_robin = m_peers.begin();
|
||||
|
||||
if (!is_connect_candidate(m_round_robin->second, finished)) continue;
|
||||
peer& pe = m_round_robin->second;
|
||||
iterator current = m_round_robin;
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
// try to send a DHT ping to this peer
|
||||
// as well, to figure out if it supports
|
||||
// DHT (uTorrent and BitComet doesn't
|
||||
// advertise support)
|
||||
if (!pinged && !pe.added_to_dht)
|
||||
{
|
||||
udp::endpoint node(pe.ip.address(), pe.ip.port());
|
||||
m_torrent->session().add_dht_node(node);
|
||||
pe.added_to_dht = true;
|
||||
pinged = true;
|
||||
}
|
||||
#endif
|
||||
// this timeout has to be customizable!
|
||||
// don't remove banned peers, they should
|
||||
// remain banned
|
||||
if (pe.connection == 0
|
||||
&& pe.connected != min_time()
|
||||
&& !pe.banned
|
||||
&& (now - pe.connected > minutes(120)
|
||||
|| m_peers.size() >= m_torrent->settings().max_peerlist_size * 0.9))
|
||||
{
|
||||
erase_peer(m_round_robin++);
|
||||
continue;
|
||||
}
|
||||
|
||||
++m_round_robin;
|
||||
|
||||
|
||||
if (!is_connect_candidate(pe, finished)) continue;
|
||||
|
||||
if (candidate != m_peers.end()
|
||||
&& !compare_peer(candidate->second, m_round_robin->second, external_ip)) continue;
|
||||
&& !compare_peer(candidate->second, pe, external_ip)) continue;
|
||||
|
||||
if (now - m_round_robin->second.connected <
|
||||
seconds(m_round_robin->second.failcount * min_reconnect_time))
|
||||
if (now - pe.connected <
|
||||
seconds(pe.failcount * min_reconnect_time))
|
||||
continue;
|
||||
|
||||
candidate = m_round_robin;
|
||||
candidate = current;
|
||||
}
|
||||
|
||||
#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING
|
||||
|
@ -484,45 +509,6 @@ namespace libtorrent
|
|||
|
||||
if (m_torrent->is_paused()) return;
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
bool pinged = false;
|
||||
#endif
|
||||
|
||||
ptime now = time_now();
|
||||
// remove old disconnected peers from the list
|
||||
for (iterator i = m_peers.begin(); i != m_peers.end();)
|
||||
{
|
||||
peer& pe = i->second;
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
// try to send a DHT ping to this peer
|
||||
// as well, to figure out if it supports
|
||||
// DHT (uTorrent and BitComet doesn't
|
||||
// advertise support)
|
||||
if (!pinged && !pe.added_to_dht)
|
||||
{
|
||||
udp::endpoint node(pe.ip.address(), pe.ip.port());
|
||||
m_torrent->session().add_dht_node(node);
|
||||
pe.added_to_dht = true;
|
||||
pinged = true;
|
||||
}
|
||||
#endif
|
||||
// this timeout has to be customizable!
|
||||
// don't remove banned peers, they should
|
||||
// remain banned
|
||||
if (pe.connection == 0
|
||||
&& pe.connected != min_time()
|
||||
&& !pe.banned
|
||||
&& now - pe.connected > minutes(120))
|
||||
{
|
||||
erase_peer(i++);
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------
|
||||
// upload shift
|
||||
// ------------------------
|
||||
|
@ -658,6 +644,12 @@ namespace libtorrent
|
|||
error_code ec;
|
||||
TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint(ec) || ec);
|
||||
|
||||
if (m_peers.size() >= m_torrent->settings().max_peerlist_size)
|
||||
{
|
||||
c.disconnect("peer list size exceeded, refusing incoming connection");
|
||||
return false;
|
||||
}
|
||||
|
||||
peer p(c.remote(), peer::not_connectable, 0);
|
||||
i = m_peers.insert(std::make_pair(c.remote().address(), p));
|
||||
#ifndef TORRENT_DISABLE_GEO_IP
|
||||
|
@ -750,7 +742,7 @@ namespace libtorrent
|
|||
if (ses.m_alerts.should_post(alert::info))
|
||||
{
|
||||
ses.m_alerts.post_alert(peer_blocked_alert(remote.address()
|
||||
, "outgoing port blocked, peer not added to peer list"));
|
||||
, "outgoing port blocked, peer not added to peer list"));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -776,11 +768,14 @@ namespace libtorrent
|
|||
if (ses.m_alerts.should_post(alert::info))
|
||||
{
|
||||
ses.m_alerts.post_alert(peer_blocked_alert(remote.address()
|
||||
, "blocked peer not added to peer list"));
|
||||
, "blocked peer not added to peer list"));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_peers.size() >= m_torrent->settings().max_peerlist_size)
|
||||
return 0;
|
||||
|
||||
// we don't have any info about this peer.
|
||||
// add a new entry
|
||||
i = m_peers.insert(std::make_pair(remote.address()
|
||||
|
|
|
@ -169,7 +169,6 @@ namespace aux {
|
|||
, m_auto_scrape_time_scaler(180)
|
||||
, m_incoming_connection(false)
|
||||
, m_last_tick(time_now())
|
||||
, m_torrent_sequence(0)
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
, m_dht_same_port(true)
|
||||
, m_external_udp_port(0)
|
||||
|
@ -1043,7 +1042,7 @@ namespace aux {
|
|||
else
|
||||
++uncongested_torrents;
|
||||
|
||||
if (t.is_auto_managed() && t.is_paused())
|
||||
if (t.is_auto_managed() && t.is_paused() && !t.has_error())
|
||||
{
|
||||
++num_paused_auto_managed;
|
||||
if (!least_recently_scraped->second->is_auto_managed()
|
||||
|
@ -1308,7 +1307,7 @@ namespace aux {
|
|||
{
|
||||
torrent* t = i->second.get();
|
||||
TORRENT_ASSERT(t);
|
||||
if (t->is_auto_managed())
|
||||
if (t->is_auto_managed() && !t->has_error())
|
||||
{
|
||||
// this torrent is auto managed, add it to
|
||||
// the list (depending on if it's a seed or not)
|
||||
|
@ -1661,7 +1660,7 @@ namespace aux {
|
|||
{
|
||||
TORRENT_ASSERT(!params.save_path.empty());
|
||||
|
||||
if (params.ti && params.ti->num_files() == 0)
|
||||
if (params.ti && params.ti->files().num_files() == 0)
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
throw std::runtime_error("no files in torrent");
|
||||
|
@ -1703,6 +1702,14 @@ namespace aux {
|
|||
#endif
|
||||
}
|
||||
|
||||
int queue_pos = 0;
|
||||
for (torrent_map::const_iterator i = m_torrents.begin()
|
||||
, end(m_torrents.end()); i != end; ++i)
|
||||
{
|
||||
int pos = i->second->queue_position();
|
||||
if (pos >= queue_pos) queue_pos = pos + 1;
|
||||
}
|
||||
|
||||
// create the torrent and the data associated with
|
||||
// the checker thread and store it before starting
|
||||
// the thread
|
||||
|
@ -1711,17 +1718,16 @@ namespace aux {
|
|||
torrent_ptr.reset(new torrent(*this, params.ti, params.save_path
|
||||
, m_listen_interface, params.storage_mode, 16 * 1024
|
||||
, params.storage, params.paused, params.resume_data
|
||||
, m_torrent_sequence, params.auto_managed));
|
||||
, queue_pos, params.auto_managed));
|
||||
}
|
||||
else
|
||||
{
|
||||
torrent_ptr.reset(new torrent(*this, params.tracker_url, *ih, params.name
|
||||
, params.save_path, m_listen_interface, params.storage_mode, 16 * 1024
|
||||
, params.storage, params.paused, params.resume_data
|
||||
, m_torrent_sequence, params.auto_managed));
|
||||
, queue_pos, params.auto_managed));
|
||||
}
|
||||
torrent_ptr->start();
|
||||
++m_torrent_sequence;
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
for (extension_list_t::iterator i = m_extensions.begin()
|
||||
|
@ -1745,6 +1751,11 @@ namespace aux {
|
|||
|
||||
m_torrents.insert(std::make_pair(*ih, torrent_ptr));
|
||||
|
||||
// if this is an auto managed torrent, force a recalculation
|
||||
// of which torrents to have active
|
||||
if (params.auto_managed && m_auto_manage_time_scaler > 2)
|
||||
m_auto_manage_time_scaler = 2;
|
||||
|
||||
return torrent_handle(torrent_ptr);
|
||||
}
|
||||
|
||||
|
@ -1816,6 +1827,7 @@ namespace aux {
|
|||
#ifndef NDEBUG
|
||||
sha1_hash i_hash = t.torrent_file().info_hash();
|
||||
#endif
|
||||
i->second->set_queue_position(-1);
|
||||
m_torrents.erase(i);
|
||||
TORRENT_ASSERT(m_torrents.find(i_hash) == m_torrents.end());
|
||||
return;
|
||||
|
@ -2440,6 +2452,22 @@ namespace aux {
|
|||
#ifndef NDEBUG
|
||||
void session_impl::check_invariant() const
|
||||
{
|
||||
std::set<int> unique;
|
||||
int total_downloaders = 0;
|
||||
for (torrent_map::const_iterator i = m_torrents.begin()
|
||||
, end(m_torrents.end()); i != end; ++i)
|
||||
{
|
||||
int pos = i->second->queue_position();
|
||||
if (pos < 0)
|
||||
{
|
||||
TORRENT_ASSERT(pos == -1);
|
||||
continue;
|
||||
}
|
||||
++total_downloaders;
|
||||
unique.insert(i->second->queue_position());
|
||||
}
|
||||
TORRENT_ASSERT(unique.size() == total_downloaders);
|
||||
|
||||
TORRENT_ASSERT(m_max_connections > 0);
|
||||
TORRENT_ASSERT(m_max_uploads > 0);
|
||||
TORRENT_ASSERT(m_allowed_upload_slots >= m_max_uploads);
|
||||
|
|
|
@ -251,12 +251,12 @@ namespace libtorrent
|
|||
{
|
||||
|
||||
std::vector<std::pair<size_type, std::time_t> > get_filesizes(
|
||||
torrent_info const& t, fs::path p)
|
||||
file_storage const& s, fs::path p)
|
||||
{
|
||||
p = complete(p);
|
||||
std::vector<std::pair<size_type, std::time_t> > sizes;
|
||||
for (torrent_info::file_iterator i = t.begin_files(true);
|
||||
i != t.end_files(true); ++i)
|
||||
for (file_storage::iterator i = s.begin()
|
||||
, end(s.end());i != end; ++i)
|
||||
{
|
||||
size_type size = 0;
|
||||
std::time_t time = 0;
|
||||
|
@ -289,13 +289,13 @@ namespace libtorrent
|
|||
// pieces, so any older version of the resume data will
|
||||
// still be a correct subset of the actual data on disk.
|
||||
bool match_filesizes(
|
||||
torrent_info const& t
|
||||
file_storage const& fs
|
||||
, fs::path p
|
||||
, std::vector<std::pair<size_type, std::time_t> > const& sizes
|
||||
, bool compact_mode
|
||||
, std::string* error)
|
||||
{
|
||||
if ((int)sizes.size() != t.num_files(true))
|
||||
if ((int)sizes.size() != fs.num_files())
|
||||
{
|
||||
if (error) *error = "mismatching number of files";
|
||||
return false;
|
||||
|
@ -304,8 +304,8 @@ namespace libtorrent
|
|||
|
||||
std::vector<std::pair<size_type, std::time_t> >::const_iterator s
|
||||
= sizes.begin();
|
||||
for (torrent_info::file_iterator i = t.begin_files(true);
|
||||
i != t.end_files(true); ++i, ++s)
|
||||
for (file_storage::iterator i = fs.begin()
|
||||
, end(fs.end());i != end; ++i, ++s)
|
||||
{
|
||||
size_type size = 0;
|
||||
std::time_t time = 0;
|
||||
|
@ -354,15 +354,16 @@ namespace libtorrent
|
|||
class storage : public storage_interface, boost::noncopyable
|
||||
{
|
||||
public:
|
||||
storage(boost::intrusive_ptr<torrent_info const> info, fs::path const& path, file_pool& fp)
|
||||
: m_info(info)
|
||||
, m_files(fp)
|
||||
storage(file_storage const& fs, fs::path const& path, file_pool& fp)
|
||||
: m_files(fs)
|
||||
, m_pool(fp)
|
||||
{
|
||||
TORRENT_ASSERT(info->begin_files(true) != info->end_files(true));
|
||||
TORRENT_ASSERT(m_files.begin() != m_files.end());
|
||||
m_save_path = fs::complete(path);
|
||||
TORRENT_ASSERT(m_save_path.is_complete());
|
||||
}
|
||||
|
||||
bool rename_file(int index, std::string const& new_filename);
|
||||
bool release_files();
|
||||
bool delete_files();
|
||||
bool initialize(bool allocate_files);
|
||||
|
@ -379,14 +380,18 @@ namespace libtorrent
|
|||
int read_impl(char* buf, int slot, int offset, int size, bool fill_zero);
|
||||
|
||||
~storage()
|
||||
{ m_files.release(this); }
|
||||
{ m_pool.release(this); }
|
||||
|
||||
file_storage const& files() const { return m_mapped_files?*m_mapped_files:m_files; }
|
||||
|
||||
boost::scoped_ptr<file_storage> m_mapped_files;
|
||||
file_storage const& m_files;
|
||||
|
||||
boost::intrusive_ptr<torrent_info const> m_info;
|
||||
fs::path m_save_path;
|
||||
// the file pool is typically stored in
|
||||
// the session, to make all storage
|
||||
// instances use the same pool
|
||||
file_pool& m_files;
|
||||
file_pool& m_pool;
|
||||
|
||||
// temporary storage for moving pieces
|
||||
buffer m_scratch_buffer;
|
||||
|
@ -399,7 +404,7 @@ namespace libtorrent
|
|||
hasher whole;
|
||||
int slot_size1 = piece_size;
|
||||
m_scratch_buffer.resize(slot_size1);
|
||||
int read_result = read_impl(&m_scratch_buffer[0], slot, 0, slot_size1, true);
|
||||
read_impl(&m_scratch_buffer[0], slot, 0, slot_size1, true);
|
||||
if (ph.offset > 0)
|
||||
partial.update(&m_scratch_buffer[0], ph.offset);
|
||||
whole.update(&m_scratch_buffer[0], slot_size1);
|
||||
|
@ -426,8 +431,8 @@ namespace libtorrent
|
|||
{
|
||||
// first, create all missing directories
|
||||
fs::path last_path;
|
||||
for (torrent_info::file_iterator file_iter = m_info->begin_files(true),
|
||||
end_iter = m_info->end_files(true); file_iter != end_iter; ++file_iter)
|
||||
for (file_storage::iterator file_iter = files().begin(),
|
||||
end_iter = files().end(); file_iter != end_iter; ++file_iter)
|
||||
{
|
||||
fs::path dir = (m_save_path / file_iter->path).branch_path();
|
||||
|
||||
|
@ -475,7 +480,7 @@ namespace libtorrent
|
|||
if (allocate_files)
|
||||
{
|
||||
std::string error;
|
||||
boost::shared_ptr<file> f = m_files.open_file(this
|
||||
boost::shared_ptr<file> f = m_pool.open_file(this
|
||||
, m_save_path / file_iter->path, file::in | file::out
|
||||
, error);
|
||||
if (f && f->error().empty())
|
||||
|
@ -491,13 +496,46 @@ namespace libtorrent
|
|||
#endif
|
||||
}
|
||||
// close files that were opened in write mode
|
||||
m_files.release(this);
|
||||
m_pool.release(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool storage::rename_file(int index, std::string const& new_filename)
|
||||
{
|
||||
if (index < 0 || index >= m_files.num_files()) return true;
|
||||
fs::path old_name = m_save_path / files().at(index).path;
|
||||
m_pool.release(old_name);
|
||||
|
||||
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
|
||||
fs::wpath old_path = safe_convert(old_name);
|
||||
fs::wpath new_path = safe_convert(m_save_path / new_filename);
|
||||
#else
|
||||
fs::path const& old_path = old_name;
|
||||
fs::path new_path = m_save_path / new_filename;
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
rename(old_path, new_path);
|
||||
if (!m_mapped_files)
|
||||
{ m_mapped_files.reset(new file_storage(m_files)); }
|
||||
m_mapped_files->rename_file(index, new_filename);
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
set_error(old_name.string(), e.what());
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool storage::release_files()
|
||||
{
|
||||
m_files.release(this);
|
||||
m_pool.release(this);
|
||||
buffer().swap(m_scratch_buffer);
|
||||
return false;
|
||||
}
|
||||
|
@ -505,7 +543,7 @@ namespace libtorrent
|
|||
bool storage::delete_files()
|
||||
{
|
||||
// make sure we don't have the files open
|
||||
m_files.release(this);
|
||||
m_pool.release(this);
|
||||
buffer().swap(m_scratch_buffer);
|
||||
|
||||
int result = 0;
|
||||
|
@ -515,8 +553,8 @@ namespace libtorrent
|
|||
// delete the files from disk
|
||||
std::set<std::string> directories;
|
||||
typedef std::set<std::string>::iterator iter_t;
|
||||
for (torrent_info::file_iterator i = m_info->begin_files(true)
|
||||
, end(m_info->end_files(true)); i != end; ++i)
|
||||
for (file_storage::iterator i = files().begin()
|
||||
, end(files().end()); i != end; ++i)
|
||||
{
|
||||
std::string p = (m_save_path / i->path).string();
|
||||
fs::path bp = i->path.branch_path();
|
||||
|
@ -584,7 +622,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(rd.type() == entry::dictionary_t);
|
||||
|
||||
std::vector<std::pair<size_type, std::time_t> > file_sizes
|
||||
= get_filesizes(*m_info, m_save_path);
|
||||
= get_filesizes(files(), m_save_path);
|
||||
|
||||
entry::list_type& fl = rd["file sizes"].list();
|
||||
for (std::vector<std::pair<size_type, std::time_t> >::iterator i
|
||||
|
@ -642,7 +680,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
entry::list_type const& slots = slots_ent->list();
|
||||
bool seed = int(slots.size()) == m_info->num_pieces()
|
||||
bool seed = int(slots.size()) == m_files.num_pieces()
|
||||
&& std::find_if(slots.begin(), slots.end()
|
||||
, boost::bind<bool>(std::less<int>()
|
||||
, boost::bind((size_type const& (entry::*)() const)
|
||||
|
@ -655,11 +693,11 @@ namespace libtorrent
|
|||
|
||||
if (seed)
|
||||
{
|
||||
if (m_info->num_files(true) != (int)file_sizes.size())
|
||||
if (m_files.num_files() != (int)file_sizes.size())
|
||||
{
|
||||
error = "the number of files does not match the torrent (num: "
|
||||
+ boost::lexical_cast<std::string>(file_sizes.size()) + " actual: "
|
||||
+ boost::lexical_cast<std::string>(m_info->num_files(true)) + ")";
|
||||
+ boost::lexical_cast<std::string>(m_files.num_files()) + ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -667,8 +705,8 @@ namespace libtorrent
|
|||
fs = file_sizes.begin();
|
||||
// the resume data says we have the entire torrent
|
||||
// make sure the file sizes are the right ones
|
||||
for (torrent_info::file_iterator i = m_info->begin_files(true)
|
||||
, end(m_info->end_files(true)); i != end; ++i, ++fs)
|
||||
for (file_storage::iterator i = files().begin()
|
||||
, end(files().end()); i != end; ++i, ++fs)
|
||||
{
|
||||
if (i->size != fs->first)
|
||||
{
|
||||
|
@ -680,7 +718,7 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
return match_filesizes(*m_info, m_save_path, file_sizes
|
||||
return match_filesizes(files(), m_save_path, file_sizes
|
||||
, !full_allocation_mode, &error);
|
||||
}
|
||||
|
||||
|
@ -716,14 +754,14 @@ namespace libtorrent
|
|||
return false;
|
||||
#endif
|
||||
|
||||
m_files.release(this);
|
||||
m_pool.release(this);
|
||||
|
||||
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
|
||||
old_path = safe_convert((m_save_path / m_info->name()).string());
|
||||
new_path = safe_convert((save_path / m_info->name()).string());
|
||||
old_path = safe_convert((m_save_path / files().name()).string());
|
||||
new_path = safe_convert((save_path / files().name()).string());
|
||||
#else
|
||||
old_path = m_save_path / m_info->name();
|
||||
new_path = save_path / m_info->name();
|
||||
old_path = m_save_path / files().name();
|
||||
new_path = save_path / files().name();
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
|
@ -740,16 +778,20 @@ namespace libtorrent
|
|||
return true;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch (std::exception&) {}
|
||||
return false;
|
||||
catch (std::exception& e)
|
||||
{
|
||||
set_error((m_save_path / files().name()).string(), e.what());
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
void storage::shuffle()
|
||||
{
|
||||
int num_pieces = m_info->num_pieces();
|
||||
int num_pieces = files().num_pieces();
|
||||
|
||||
std::vector<int> pieces(num_pieces);
|
||||
for (std::vector<int>::iterator i = pieces.begin();
|
||||
|
@ -766,7 +808,7 @@ namespace libtorrent
|
|||
{
|
||||
const int slot_index = targets[i];
|
||||
const int piece_index = pieces[i];
|
||||
const int slot_size =static_cast<int>(m_info->piece_size(slot_index));
|
||||
const int slot_size =static_cast<int>(m_files.piece_size(slot_index));
|
||||
std::vector<char> buf(slot_size);
|
||||
read(&buf[0], piece_index, 0, slot_size);
|
||||
write(&buf[0], slot_index, 0, slot_size);
|
||||
|
@ -777,7 +819,7 @@ namespace libtorrent
|
|||
|
||||
bool storage::move_slot(int src_slot, int dst_slot)
|
||||
{
|
||||
int piece_size = m_info->piece_size(dst_slot);
|
||||
int piece_size = m_files.piece_size(dst_slot);
|
||||
m_scratch_buffer.resize(piece_size);
|
||||
int ret1 = read_impl(&m_scratch_buffer[0], src_slot, 0, piece_size, true);
|
||||
int ret2 = write(&m_scratch_buffer[0], dst_slot, 0, piece_size);
|
||||
|
@ -787,9 +829,9 @@ namespace libtorrent
|
|||
bool storage::swap_slots(int slot1, int slot2)
|
||||
{
|
||||
// the size of the target slot is the size of the piece
|
||||
int piece_size = m_info->piece_length();
|
||||
int piece1_size = m_info->piece_size(slot2);
|
||||
int piece2_size = m_info->piece_size(slot1);
|
||||
int piece_size = m_files.piece_length();
|
||||
int piece1_size = m_files.piece_size(slot2);
|
||||
int piece2_size = m_files.piece_size(slot1);
|
||||
m_scratch_buffer.resize(piece_size * 2);
|
||||
int ret1 = read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true);
|
||||
int ret2 = read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true);
|
||||
|
@ -802,10 +844,10 @@ namespace libtorrent
|
|||
bool storage::swap_slots3(int slot1, int slot2, int slot3)
|
||||
{
|
||||
// the size of the target slot is the size of the piece
|
||||
int piece_size = m_info->piece_length();
|
||||
int piece1_size = m_info->piece_size(slot2);
|
||||
int piece2_size = m_info->piece_size(slot3);
|
||||
int piece3_size = m_info->piece_size(slot1);
|
||||
int piece_size = m_files.piece_length();
|
||||
int piece1_size = m_files.piece_size(slot2);
|
||||
int piece2_size = m_files.piece_size(slot3);
|
||||
int piece3_size = m_files.piece_size(slot1);
|
||||
m_scratch_buffer.resize(piece_size * 2);
|
||||
int ret1 = read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true);
|
||||
int ret2 = read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true);
|
||||
|
@ -835,25 +877,25 @@ namespace libtorrent
|
|||
, bool fill_zero)
|
||||
{
|
||||
TORRENT_ASSERT(buf != 0);
|
||||
TORRENT_ASSERT(slot >= 0 && slot < m_info->num_pieces());
|
||||
TORRENT_ASSERT(slot >= 0 && slot < m_files.num_pieces());
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(offset < m_info->piece_size(slot));
|
||||
TORRENT_ASSERT(offset < m_files.piece_size(slot));
|
||||
TORRENT_ASSERT(size > 0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::vector<file_slice> slices
|
||||
= m_info->map_block(slot, offset, size, true);
|
||||
= files().map_block(slot, offset, size);
|
||||
TORRENT_ASSERT(!slices.empty());
|
||||
#endif
|
||||
|
||||
size_type start = slot * (size_type)m_info->piece_length() + offset;
|
||||
TORRENT_ASSERT(start + size <= m_info->total_size());
|
||||
size_type start = slot * (size_type)m_files.piece_length() + offset;
|
||||
TORRENT_ASSERT(start + size <= m_files.total_size());
|
||||
|
||||
// find the file iterator and file offset
|
||||
size_type file_offset = start;
|
||||
std::vector<file_entry>::const_iterator file_iter;
|
||||
|
||||
for (file_iter = m_info->begin_files(true);;)
|
||||
for (file_iter = files().begin();;)
|
||||
{
|
||||
if (file_offset < file_iter->size)
|
||||
break;
|
||||
|
@ -864,7 +906,7 @@ namespace libtorrent
|
|||
|
||||
int buf_pos = 0;
|
||||
std::string error;
|
||||
boost::shared_ptr<file> in(m_files.open_file(
|
||||
boost::shared_ptr<file> in(m_pool.open_file(
|
||||
this, m_save_path / file_iter->path, file::in
|
||||
, error));
|
||||
if (!in)
|
||||
|
@ -899,7 +941,7 @@ namespace libtorrent
|
|||
#endif
|
||||
|
||||
int left_to_read = size;
|
||||
int slot_size = static_cast<int>(m_info->piece_size(slot));
|
||||
int slot_size = static_cast<int>(m_files.piece_size(slot));
|
||||
|
||||
if (offset + left_to_read > slot_size)
|
||||
left_to_read = slot_size - offset;
|
||||
|
@ -924,7 +966,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(int(slices.size()) > counter);
|
||||
size_type slice_size = slices[counter].size;
|
||||
TORRENT_ASSERT(slice_size == read_bytes);
|
||||
TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path
|
||||
TORRENT_ASSERT(files().at(slices[counter].file_index).path
|
||||
== file_iter->path);
|
||||
#endif
|
||||
|
||||
|
@ -961,7 +1003,7 @@ namespace libtorrent
|
|||
|
||||
file_offset = 0;
|
||||
std::string error;
|
||||
in = m_files.open_file(
|
||||
in = m_pool.open_file(
|
||||
this, path, file::in, error);
|
||||
if (!in)
|
||||
{
|
||||
|
@ -997,35 +1039,35 @@ namespace libtorrent
|
|||
{
|
||||
TORRENT_ASSERT(buf != 0);
|
||||
TORRENT_ASSERT(slot >= 0);
|
||||
TORRENT_ASSERT(slot < m_info->num_pieces());
|
||||
TORRENT_ASSERT(slot < m_files.num_pieces());
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(size > 0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::vector<file_slice> slices
|
||||
= m_info->map_block(slot, offset, size, true);
|
||||
= files().map_block(slot, offset, size);
|
||||
TORRENT_ASSERT(!slices.empty());
|
||||
#endif
|
||||
|
||||
size_type start = slot * (size_type)m_info->piece_length() + offset;
|
||||
size_type start = slot * (size_type)m_files.piece_length() + offset;
|
||||
|
||||
// find the file iterator and file offset
|
||||
size_type file_offset = start;
|
||||
std::vector<file_entry>::const_iterator file_iter;
|
||||
|
||||
for (file_iter = m_info->begin_files(true);;)
|
||||
for (file_iter = files().begin();;)
|
||||
{
|
||||
if (file_offset < file_iter->size)
|
||||
break;
|
||||
|
||||
file_offset -= file_iter->size;
|
||||
++file_iter;
|
||||
TORRENT_ASSERT(file_iter != m_info->end_files(true));
|
||||
TORRENT_ASSERT(file_iter != files().end());
|
||||
}
|
||||
|
||||
fs::path p(m_save_path / file_iter->path);
|
||||
std::string error;
|
||||
boost::shared_ptr<file> out = m_files.open_file(
|
||||
boost::shared_ptr<file> out = m_pool.open_file(
|
||||
this, p, file::out | file::in, error);
|
||||
|
||||
if (!out)
|
||||
|
@ -1050,7 +1092,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
int left_to_write = size;
|
||||
int slot_size = static_cast<int>(m_info->piece_size(slot));
|
||||
int slot_size = static_cast<int>(m_files.piece_size(slot));
|
||||
|
||||
if (offset + left_to_write > slot_size)
|
||||
left_to_write = slot_size - offset;
|
||||
|
@ -1074,7 +1116,7 @@ namespace libtorrent
|
|||
{
|
||||
TORRENT_ASSERT(int(slices.size()) > counter);
|
||||
TORRENT_ASSERT(slices[counter].size == write_bytes);
|
||||
TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path
|
||||
TORRENT_ASSERT(files().at(slices[counter].file_index).path
|
||||
== file_iter->path);
|
||||
|
||||
TORRENT_ASSERT(buf_pos >= 0);
|
||||
|
@ -1101,11 +1143,11 @@ namespace libtorrent
|
|||
#endif
|
||||
++file_iter;
|
||||
|
||||
TORRENT_ASSERT(file_iter != m_info->end_files(true));
|
||||
TORRENT_ASSERT(file_iter != files().end());
|
||||
fs::path p = m_save_path / file_iter->path;
|
||||
file_offset = 0;
|
||||
std::string error;
|
||||
out = m_files.open_file(
|
||||
out = m_pool.open_file(
|
||||
this, p, file::out | file::in, error);
|
||||
|
||||
if (!out)
|
||||
|
@ -1131,25 +1173,26 @@ namespace libtorrent
|
|||
return size;
|
||||
}
|
||||
|
||||
storage_interface* default_storage_constructor(boost::intrusive_ptr<torrent_info const> ti
|
||||
storage_interface* default_storage_constructor(file_storage const& fs
|
||||
, fs::path const& path, file_pool& fp)
|
||||
{
|
||||
return new storage(ti, path, fp);
|
||||
return new storage(fs, path, fp);
|
||||
}
|
||||
|
||||
// -- piece_manager -----------------------------------------------------
|
||||
|
||||
piece_manager::piece_manager(
|
||||
boost::shared_ptr<void> const& torrent
|
||||
, boost::intrusive_ptr<torrent_info const> ti
|
||||
, boost::intrusive_ptr<torrent_info const> info
|
||||
, fs::path const& save_path
|
||||
, file_pool& fp
|
||||
, disk_io_thread& io
|
||||
, storage_constructor_type sc
|
||||
, storage_mode_t sm)
|
||||
: m_storage(sc(ti, save_path, fp))
|
||||
: m_info(info)
|
||||
, m_files(m_info->files())
|
||||
, m_storage(sc(m_files, save_path, fp))
|
||||
, m_storage_mode(sm)
|
||||
, m_info(ti)
|
||||
, m_save_path(complete(save_path))
|
||||
, m_state(state_none)
|
||||
, m_current_slot(0)
|
||||
|
@ -1213,6 +1256,17 @@ namespace libtorrent
|
|||
m_io_thread.add_job(j, handler);
|
||||
}
|
||||
|
||||
void piece_manager::async_rename_file(int index, std::string const& name
|
||||
, boost::function<void(int, disk_io_job const&)> const& handler)
|
||||
{
|
||||
disk_io_job j;
|
||||
j.storage = this;
|
||||
j.piece = index;
|
||||
j.str = name;
|
||||
j.action = disk_io_job::rename_file;
|
||||
m_io_thread.add_job(j, handler);
|
||||
}
|
||||
|
||||
void piece_manager::async_check_files(
|
||||
boost::function<void(int, disk_io_job const&)> const& handler)
|
||||
{
|
||||
|
@ -1241,6 +1295,8 @@ namespace libtorrent
|
|||
m_io_thread.add_job(j, handler);
|
||||
#ifndef NDEBUG
|
||||
boost::recursive_mutex::scoped_lock l(m_mutex);
|
||||
// if this assert is hit, it suggests
|
||||
// that check_files was not successful
|
||||
TORRENT_ASSERT(slot_for(r.piece) >= 0);
|
||||
#endif
|
||||
}
|
||||
|
@ -1295,7 +1351,7 @@ namespace libtorrent
|
|||
|
||||
int slot = slot_for(piece);
|
||||
TORRENT_ASSERT(slot != has_no_slot);
|
||||
return m_storage->hash_for_slot(slot, ph, m_info->piece_size(piece));
|
||||
return m_storage->hash_for_slot(slot, ph, m_files.piece_size(piece));
|
||||
}
|
||||
|
||||
bool piece_manager::move_storage_impl(fs::path const& save_path)
|
||||
|
@ -1373,7 +1429,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(buf);
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(size > 0);
|
||||
TORRENT_ASSERT(piece_index >= 0 && piece_index < m_info->num_pieces());
|
||||
TORRENT_ASSERT(piece_index >= 0 && piece_index < m_files.num_pieces());
|
||||
|
||||
int slot = allocate_slot_for_piece(piece_index);
|
||||
int ret = m_storage->write(buf, slot, offset, size);
|
||||
|
@ -1455,9 +1511,9 @@ namespace libtorrent
|
|||
{
|
||||
// INVARIANT_CHECK;
|
||||
|
||||
const int piece_size = static_cast<int>(m_info->piece_length());
|
||||
const int last_piece_size = static_cast<int>(m_info->piece_size(
|
||||
m_info->num_pieces() - 1));
|
||||
const int piece_size = static_cast<int>(m_files.piece_length());
|
||||
const int last_piece_size = static_cast<int>(m_files.piece_size(
|
||||
m_files.num_pieces() - 1));
|
||||
|
||||
TORRENT_ASSERT((int)piece_data.size() >= last_piece_size);
|
||||
|
||||
|
@ -1579,8 +1635,8 @@ namespace libtorrent
|
|||
|
||||
int piece_manager::check_no_fastresume(std::string& error)
|
||||
{
|
||||
torrent_info::file_iterator i = m_info->begin_files(true);
|
||||
torrent_info::file_iterator end = m_info->end_files(true);
|
||||
file_storage::iterator i = m_files.begin();
|
||||
file_storage::iterator end = m_files.end();
|
||||
|
||||
for (; i != end; ++i)
|
||||
{
|
||||
|
@ -1612,9 +1668,9 @@ namespace libtorrent
|
|||
{
|
||||
m_state = state_full_check;
|
||||
m_piece_to_slot.clear();
|
||||
m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot);
|
||||
m_piece_to_slot.resize(m_files.num_pieces(), has_no_slot);
|
||||
m_slot_to_piece.clear();
|
||||
m_slot_to_piece.resize(m_info->num_pieces(), unallocated);
|
||||
m_slot_to_piece.resize(m_files.num_pieces(), unallocated);
|
||||
if (m_storage_mode == storage_mode_compact)
|
||||
{
|
||||
m_unallocated_slots.clear();
|
||||
|
@ -1629,12 +1685,12 @@ namespace libtorrent
|
|||
// in compact mode without checking, we need to
|
||||
// populate the unallocated list
|
||||
TORRENT_ASSERT(m_unallocated_slots.empty());
|
||||
for (int i = 0, end(m_info->num_pieces()); i < end; ++i)
|
||||
for (int i = 0, end(m_files.num_pieces()); i < end; ++i)
|
||||
m_unallocated_slots.push_back(i);
|
||||
m_piece_to_slot.clear();
|
||||
m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot);
|
||||
m_piece_to_slot.resize(m_files.num_pieces(), has_no_slot);
|
||||
m_slot_to_piece.clear();
|
||||
m_slot_to_piece.resize(m_info->num_pieces(), unallocated);
|
||||
m_slot_to_piece.resize(m_files.num_pieces(), unallocated);
|
||||
}
|
||||
|
||||
return check_init_storage(error);
|
||||
|
@ -1675,7 +1731,7 @@ namespace libtorrent
|
|||
|
||||
INVARIANT_CHECK;
|
||||
|
||||
TORRENT_ASSERT(m_info->piece_length() > 0);
|
||||
TORRENT_ASSERT(m_files.piece_length() > 0);
|
||||
|
||||
// if we don't have any resume data, return
|
||||
if (rd.type() == entry::undefined_t) return check_no_fastresume(error);
|
||||
|
@ -1686,38 +1742,11 @@ namespace libtorrent
|
|||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
entry const* file_format = rd.find_key("file-format");
|
||||
|
||||
if (file_format == 0 || file_format->type() != entry::string_t)
|
||||
{
|
||||
error = "missing file format tag";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
if (file_format->string() != "libtorrent resume file")
|
||||
{
|
||||
error = "invalid file format tag";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
entry const* info_hash = rd.find_key("info-hash");
|
||||
if (info_hash == 0 || info_hash->type() != entry::string_t)
|
||||
{
|
||||
error = "missing info-hash";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
if (sha1_hash(info_hash->string()) != m_info->info_hash())
|
||||
{
|
||||
error = "mismatching info-hash";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
int block_size = (std::min)(16 * 1024, m_info->piece_length());
|
||||
int block_size = (std::min)(16 * 1024, m_files.piece_length());
|
||||
entry const* blocks_per_piece_ent = rd.find_key("blocks per piece");
|
||||
if (blocks_per_piece_ent != 0
|
||||
&& blocks_per_piece_ent->type() == entry::int_t
|
||||
&& blocks_per_piece_ent->integer() != m_info->piece_length() / block_size)
|
||||
&& blocks_per_piece_ent->integer() != m_files.piece_length() / block_size)
|
||||
{
|
||||
error = "invalid 'blocks per piece' entry";
|
||||
return check_no_fastresume(error);
|
||||
|
@ -1746,17 +1775,17 @@ namespace libtorrent
|
|||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
if ((int)slots->list().size() > m_info->num_pieces())
|
||||
if ((int)slots->list().size() > m_files.num_pieces())
|
||||
{
|
||||
error = "file has more slots than torrent (slots: "
|
||||
+ boost::lexical_cast<std::string>(slots->list().size()) + " size: "
|
||||
+ boost::lexical_cast<std::string>(m_info->num_pieces()) + " )";
|
||||
+ boost::lexical_cast<std::string>(m_files.num_pieces()) + " )";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
if (storage_mode == storage_mode_compact)
|
||||
{
|
||||
int num_pieces = int(m_info->num_pieces());
|
||||
int num_pieces = int(m_files.num_pieces());
|
||||
m_slot_to_piece.resize(num_pieces, unallocated);
|
||||
m_piece_to_slot.resize(num_pieces, has_no_slot);
|
||||
int slot = 0;
|
||||
|
@ -1877,7 +1906,7 @@ namespace libtorrent
|
|||
// is finished
|
||||
int piece_manager::check_files(int& current_slot, int& have_piece, std::string& error)
|
||||
{
|
||||
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_info->num_pieces());
|
||||
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces());
|
||||
|
||||
current_slot = m_current_slot;
|
||||
have_piece = -1;
|
||||
|
@ -1894,9 +1923,9 @@ namespace libtorrent
|
|||
if (other_piece >= 0)
|
||||
{
|
||||
if (m_scratch_buffer2.empty())
|
||||
m_scratch_buffer2.resize(m_info->piece_length());
|
||||
m_scratch_buffer2.resize(m_files.piece_length());
|
||||
|
||||
int piece_size = m_info->piece_size(other_piece);
|
||||
int piece_size = m_files.piece_size(other_piece);
|
||||
if (m_storage->read(&m_scratch_buffer2[0], piece, 0, piece_size)
|
||||
!= piece_size)
|
||||
{
|
||||
|
@ -1910,7 +1939,7 @@ namespace libtorrent
|
|||
|
||||
// the slot where this piece belongs is
|
||||
// free. Just move the piece there.
|
||||
int piece_size = m_info->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)
|
||||
{
|
||||
error = m_storage->error();
|
||||
|
@ -1926,19 +1955,19 @@ namespace libtorrent
|
|||
return need_full_check;
|
||||
}
|
||||
|
||||
while (m_current_slot < m_info->num_pieces()
|
||||
while (m_current_slot < m_files.num_pieces()
|
||||
&& (m_slot_to_piece[m_current_slot] == m_current_slot
|
||||
|| m_slot_to_piece[m_current_slot] < 0))
|
||||
{
|
||||
++m_current_slot;
|
||||
}
|
||||
|
||||
if (m_current_slot == m_info->num_pieces())
|
||||
if (m_current_slot == m_files.num_pieces())
|
||||
{
|
||||
return check_init_storage(error);
|
||||
}
|
||||
|
||||
TORRENT_ASSERT(m_current_slot < m_info->num_pieces());
|
||||
TORRENT_ASSERT(m_current_slot < m_files.num_pieces());
|
||||
|
||||
int piece = m_slot_to_piece[m_current_slot];
|
||||
TORRENT_ASSERT(piece >= 0);
|
||||
|
@ -1949,9 +1978,9 @@ namespace libtorrent
|
|||
// where this one goes. Store it in the scratch
|
||||
// buffer until next iteration.
|
||||
if (m_scratch_buffer.empty())
|
||||
m_scratch_buffer.resize(m_info->piece_length());
|
||||
m_scratch_buffer.resize(m_files.piece_length());
|
||||
|
||||
int piece_size = m_info->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)
|
||||
{
|
||||
error = m_storage->error();
|
||||
|
@ -1975,7 +2004,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(m_state == state_full_check);
|
||||
|
||||
bool skip = check_one_piece(have_piece);
|
||||
TORRENT_ASSERT(m_current_slot <= m_info->num_pieces());
|
||||
TORRENT_ASSERT(m_current_slot <= m_files.num_pieces());
|
||||
|
||||
if (skip)
|
||||
{
|
||||
|
@ -1984,9 +2013,9 @@ namespace libtorrent
|
|||
// completely. We should skip all pieces belonging to that file.
|
||||
// find the file that failed, and skip all the pieces in that file
|
||||
size_type file_offset = 0;
|
||||
size_type current_offset = size_type(m_current_slot) * m_info->piece_length();
|
||||
for (torrent_info::file_iterator i = m_info->begin_files(true);
|
||||
i != m_info->end_files(true); ++i)
|
||||
size_type current_offset = size_type(m_current_slot) * m_files.piece_length();
|
||||
for (file_storage::iterator i = m_files.begin()
|
||||
, end(m_files.end()); i != end; ++i)
|
||||
{
|
||||
file_offset += i->size;
|
||||
if (file_offset > current_offset) break;
|
||||
|
@ -1994,8 +2023,8 @@ namespace libtorrent
|
|||
|
||||
TORRENT_ASSERT(file_offset > current_offset);
|
||||
int skip_blocks = static_cast<int>(
|
||||
(file_offset - current_offset + m_info->piece_length() - 1)
|
||||
/ m_info->piece_length());
|
||||
(file_offset - current_offset + m_files.piece_length() - 1)
|
||||
/ m_files.piece_length());
|
||||
|
||||
if (m_storage_mode == storage_mode_compact)
|
||||
{
|
||||
|
@ -2008,15 +2037,15 @@ namespace libtorrent
|
|||
|
||||
// current slot will increase by one at the end of the for-loop too
|
||||
m_current_slot += skip_blocks - 1;
|
||||
TORRENT_ASSERT(m_current_slot <= m_info->num_pieces());
|
||||
TORRENT_ASSERT(m_current_slot <= m_files.num_pieces());
|
||||
}
|
||||
|
||||
++m_current_slot;
|
||||
current_slot = m_current_slot;
|
||||
|
||||
if (m_current_slot >= m_info->num_pieces())
|
||||
if (m_current_slot >= m_files.num_pieces())
|
||||
{
|
||||
TORRENT_ASSERT(m_current_slot == m_info->num_pieces());
|
||||
TORRENT_ASSERT(m_current_slot == m_files.num_pieces());
|
||||
|
||||
// clear the memory we've been using
|
||||
std::vector<char>().swap(m_piece_data);
|
||||
|
@ -2059,19 +2088,19 @@ namespace libtorrent
|
|||
// DO THE FULL CHECK
|
||||
// ------------------------
|
||||
|
||||
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_info->num_pieces());
|
||||
TORRENT_ASSERT(int(m_slot_to_piece.size()) == m_info->num_pieces());
|
||||
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces());
|
||||
TORRENT_ASSERT(int(m_slot_to_piece.size()) == m_files.num_pieces());
|
||||
TORRENT_ASSERT(have_piece == -1);
|
||||
|
||||
// initialization for the full check
|
||||
if (m_hash_to_piece.empty())
|
||||
{
|
||||
for (int i = 0; i < m_info->num_pieces(); ++i)
|
||||
for (int i = 0; i < m_files.num_pieces(); ++i)
|
||||
m_hash_to_piece.insert(std::make_pair(m_info->hash_for_piece(i), i));
|
||||
}
|
||||
|
||||
m_piece_data.resize(int(m_info->piece_length()));
|
||||
int piece_size = m_info->piece_size(m_current_slot);
|
||||
m_piece_data.resize(int(m_files.piece_length()));
|
||||
int piece_size = m_files.piece_size(m_current_slot);
|
||||
int num_read = m_storage->read(&m_piece_data[0]
|
||||
, m_current_slot, 0, piece_size);
|
||||
|
||||
|
@ -2348,7 +2377,7 @@ namespace libtorrent
|
|||
|
||||
// special case to make sure we don't use the last slot
|
||||
// when we shouldn't, since it's smaller than ordinary slots
|
||||
if (*iter == m_info->num_pieces() - 1 && piece_index != *iter)
|
||||
if (*iter == m_files.num_pieces() - 1 && piece_index != *iter)
|
||||
{
|
||||
if (m_free_slots.size() == 1)
|
||||
allocate_slots(1);
|
||||
|
@ -2481,14 +2510,14 @@ namespace libtorrent
|
|||
{
|
||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||
|
||||
TORRENT_ASSERT(m_current_slot <= m_info->num_pieces());
|
||||
TORRENT_ASSERT(m_current_slot <= m_files.num_pieces());
|
||||
|
||||
if (m_unallocated_slots.empty()
|
||||
&& m_free_slots.empty()
|
||||
&& m_state == state_finished)
|
||||
{
|
||||
TORRENT_ASSERT(m_storage_mode != storage_mode_compact
|
||||
|| m_info->num_pieces() == 0);
|
||||
|| m_files.num_pieces() == 0);
|
||||
}
|
||||
|
||||
if (m_storage_mode != storage_mode_compact)
|
||||
|
@ -2508,8 +2537,8 @@ namespace libtorrent
|
|||
{
|
||||
if (m_piece_to_slot.empty()) return;
|
||||
|
||||
TORRENT_ASSERT((int)m_piece_to_slot.size() == m_info->num_pieces());
|
||||
TORRENT_ASSERT((int)m_slot_to_piece.size() == m_info->num_pieces());
|
||||
TORRENT_ASSERT((int)m_piece_to_slot.size() == m_files.num_pieces());
|
||||
TORRENT_ASSERT((int)m_slot_to_piece.size() == m_files.num_pieces());
|
||||
|
||||
for (std::vector<int>::const_iterator i = m_free_slots.begin();
|
||||
i != m_free_slots.end(); ++i)
|
||||
|
@ -2531,7 +2560,7 @@ namespace libtorrent
|
|||
== m_unallocated_slots.end());
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_info->num_pieces(); ++i)
|
||||
for (int i = 0; i < m_files.num_pieces(); ++i)
|
||||
{
|
||||
// Check domain of piece_to_slot's elements
|
||||
if (m_piece_to_slot[i] != has_no_slot)
|
||||
|
@ -2620,7 +2649,7 @@ namespace libtorrent
|
|||
|
||||
s << "index\tslot\tpiece\n";
|
||||
|
||||
for (int i = 0; i < m_info->num_pieces(); ++i)
|
||||
for (int i = 0; i < m_files.num_pieces(); ++i)
|
||||
{
|
||||
s << i << "\t" << m_slot_to_piece[i] << "\t";
|
||||
s << m_piece_to_slot[i] << "\n";
|
||||
|
|
|
@ -424,8 +424,34 @@ namespace libtorrent
|
|||
|
||||
m_state = torrent_status::queued_for_checking;
|
||||
|
||||
if (m_resume_data.type() == entry::dictionary_t) read_resume_data(m_resume_data);
|
||||
|
||||
if (m_resume_data.type() == entry::dictionary_t)
|
||||
{
|
||||
char const* error = 0;
|
||||
entry const* file_format = m_resume_data.find_key("file-format");
|
||||
if (file_format->string() != "libtorrent resume file")
|
||||
error = "invalid file format tag";
|
||||
|
||||
entry const* info_hash = m_resume_data.find_key("info-hash");
|
||||
if (!error && (info_hash == 0 || info_hash->type() != entry::string_t))
|
||||
error = "missing info-hash";
|
||||
|
||||
if (!error && sha1_hash(info_hash->string()) != m_torrent_file->info_hash())
|
||||
error = "mismatching info-hash";
|
||||
|
||||
if (error && m_ses.m_alerts.should_post(alert::warning))
|
||||
{
|
||||
m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), error));
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_ses.m_logger) << "fastresume data for "
|
||||
<< torrent_file().name() << " rejected: "
|
||||
<< error << "\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
if (error) m_resume_data = entry();
|
||||
else read_resume_data(m_resume_data);
|
||||
}
|
||||
|
||||
m_storage->async_check_fastresume(&m_resume_data
|
||||
, bind(&torrent::on_resume_data_checked
|
||||
, shared_from_this(), _1, _2));
|
||||
|
@ -447,9 +473,9 @@ namespace libtorrent
|
|||
" ]\n";
|
||||
#endif
|
||||
}
|
||||
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
|
||||
m_have_pieces.clear_all();
|
||||
m_num_pieces = 0;
|
||||
auto_managed(false);
|
||||
m_error = j.str;
|
||||
pause();
|
||||
return;
|
||||
}
|
||||
|
@ -523,7 +549,7 @@ namespace libtorrent
|
|||
// or the resume_data was accepted
|
||||
|
||||
m_num_pieces = 0;
|
||||
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
|
||||
m_have_pieces.clear_all();
|
||||
if (!fastresume_rejected)
|
||||
{
|
||||
TORRENT_ASSERT(m_resume_data.type() == entry::dictionary_t);
|
||||
|
@ -531,14 +557,14 @@ namespace libtorrent
|
|||
// parse have bitmask
|
||||
entry const* pieces = m_resume_data.find_key("pieces");
|
||||
if (pieces && pieces->type() == entry::string_t
|
||||
&& pieces->string().length() == m_torrent_file->num_pieces())
|
||||
&& int(pieces->string().length()) == m_torrent_file->num_pieces())
|
||||
{
|
||||
std::string const& pieces_str = pieces->string();
|
||||
for (int i = 0, end(pieces_str.size()); i < end; ++i)
|
||||
{
|
||||
bool have = pieces_str[i] & 1;
|
||||
m_have_pieces[i] = have;
|
||||
m_num_pieces += have;
|
||||
if ((pieces_str[i] & 1) == 0) continue;
|
||||
m_have_pieces.set_bit(i);
|
||||
++m_num_pieces;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -563,7 +589,7 @@ namespace libtorrent
|
|||
|
||||
if (m_have_pieces[piece_index])
|
||||
{
|
||||
m_have_pieces[piece_index] = false;
|
||||
m_have_pieces.clear_bit(piece_index);
|
||||
--m_num_pieces;
|
||||
}
|
||||
|
||||
|
@ -593,7 +619,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
int index = 0;
|
||||
for (std::vector<bool>::iterator i = m_have_pieces.begin()
|
||||
for (bitfield::const_iterator i = m_have_pieces.begin()
|
||||
, end(m_have_pieces.end()); i != end; ++i, ++index)
|
||||
{
|
||||
if (*i) m_picker->we_have(index);
|
||||
|
@ -635,9 +661,9 @@ namespace libtorrent
|
|||
" ]\n";
|
||||
#endif
|
||||
}
|
||||
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
|
||||
m_have_pieces.clear_all();
|
||||
m_num_pieces = 0;
|
||||
auto_managed(false);
|
||||
m_error = j.str;
|
||||
pause();
|
||||
m_ses.done_checking(shared_from_this());
|
||||
return;
|
||||
|
@ -647,7 +673,7 @@ namespace libtorrent
|
|||
|
||||
if (j.offset >= 0 && !m_have_pieces[j.offset])
|
||||
{
|
||||
m_have_pieces[j.offset] = true;
|
||||
m_have_pieces.set_bit(j.offset);
|
||||
++m_num_pieces;
|
||||
TORRENT_ASSERT(m_picker);
|
||||
m_picker->we_have(j.offset);
|
||||
|
@ -1169,7 +1195,6 @@ namespace libtorrent
|
|||
?"disk failed":"failed") << " ]\n";
|
||||
#endif
|
||||
|
||||
bool was_seed = is_seed();
|
||||
bool was_finished = m_picker->num_filtered() + num_pieces()
|
||||
== torrent_file().num_pieces();
|
||||
|
||||
|
@ -1186,17 +1211,6 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(valid_metadata());
|
||||
// if we just became a seed, picker is now invalid, since it
|
||||
// is deallocated by the torrent once it starts seeding
|
||||
if (!was_finished
|
||||
&& (is_seed()
|
||||
|| m_picker->num_filtered() + num_pieces()
|
||||
== torrent_file().num_pieces()))
|
||||
{
|
||||
// torrent finished
|
||||
// i.e. all the pieces we're interested in have
|
||||
// been downloaded. Release the files (they will open
|
||||
// in read only mode if needed)
|
||||
finished();
|
||||
}
|
||||
}
|
||||
else if (passed_hash_check == -2)
|
||||
{
|
||||
|
@ -1210,10 +1224,17 @@ namespace libtorrent
|
|||
|
||||
m_policy.piece_finished(index, passed_hash_check == 0);
|
||||
|
||||
if (!was_seed && is_seed())
|
||||
if (!was_finished
|
||||
&& (is_seed()
|
||||
|| m_picker->num_filtered() + num_pieces()
|
||||
== torrent_file().num_pieces()))
|
||||
{
|
||||
TORRENT_ASSERT(passed_hash_check == 0);
|
||||
completed();
|
||||
// torrent finished
|
||||
// i.e. all the pieces we're interested in have
|
||||
// been downloaded. Release the files (they will open
|
||||
// in read only mode if needed)
|
||||
finished();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1425,6 +1446,21 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void torrent::on_file_renamed(int ret, disk_io_job const& j)
|
||||
{
|
||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||
|
||||
if (alerts().should_post(alert::warning))
|
||||
{
|
||||
|
||||
if (ret == 0)
|
||||
alerts().post_alert(file_renamed_alert(get_handle(), j.str
|
||||
, "renamed file: " + j.str));
|
||||
else
|
||||
alerts().post_alert(file_renamed_alert(get_handle(), "", j.str));
|
||||
}
|
||||
}
|
||||
|
||||
void torrent::on_torrent_paused(int ret, disk_io_job const& j)
|
||||
{
|
||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||
|
@ -1452,7 +1488,7 @@ namespace libtorrent
|
|||
|
||||
if (!m_have_pieces[index])
|
||||
m_num_pieces++;
|
||||
m_have_pieces[index] = true;
|
||||
m_have_pieces.set_bit(index);
|
||||
|
||||
TORRENT_ASSERT(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0)
|
||||
== m_num_pieces);
|
||||
|
@ -1486,11 +1522,6 @@ namespace libtorrent
|
|||
#endif
|
||||
}
|
||||
#endif
|
||||
if (is_seed())
|
||||
{
|
||||
m_state = torrent_status::seeding;
|
||||
m_picker.reset();
|
||||
}
|
||||
}
|
||||
|
||||
std::string torrent::tracker_login() const
|
||||
|
@ -1619,7 +1650,7 @@ namespace libtorrent
|
|||
for (int i = 0; i < int(files.size()); ++i)
|
||||
{
|
||||
size_type start = position;
|
||||
size_type size = m_torrent_file->file_at(i).size;
|
||||
size_type size = m_torrent_file->files().at(i).size;
|
||||
if (size == 0) continue;
|
||||
position += size;
|
||||
// mark all pieces of the file with this file's priority
|
||||
|
@ -1750,7 +1781,7 @@ namespace libtorrent
|
|||
for (int i = 0; i < (int)bitmask.size(); ++i)
|
||||
{
|
||||
size_type start = position;
|
||||
position += m_torrent_file->file_at(i).size;
|
||||
position += m_torrent_file->files().at(i).size;
|
||||
// is the file selected for download?
|
||||
if (!bitmask[i])
|
||||
{
|
||||
|
@ -1872,9 +1903,8 @@ namespace libtorrent
|
|||
{
|
||||
if (m_picker.get())
|
||||
{
|
||||
const std::vector<bool>& pieces = p->get_bitfield();
|
||||
TORRENT_ASSERT(std::count(pieces.begin(), pieces.end(), true)
|
||||
< int(pieces.size()));
|
||||
bitfield const& pieces = p->get_bitfield();
|
||||
TORRENT_ASSERT(pieces.count() < int(pieces.size()));
|
||||
m_picker->dec_refcount(pieces);
|
||||
}
|
||||
}
|
||||
|
@ -2956,6 +2986,12 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
m_state = torrent_status::finished;
|
||||
set_queue_position(-1);
|
||||
|
||||
// we have to call completed() before we start
|
||||
// disconnecting peers, since there's an assert
|
||||
// to make sure we're cleared the piece picker
|
||||
if (is_seed()) completed();
|
||||
|
||||
// disconnect all seeds
|
||||
// TODO: should disconnect all peers that have the pieces we have
|
||||
|
@ -2990,6 +3026,7 @@ namespace libtorrent
|
|||
INVARIANT_CHECK;
|
||||
|
||||
m_state = torrent_status::downloading;
|
||||
set_queue_position((std::numeric_limits<int>::max)());
|
||||
}
|
||||
|
||||
// called when torrent is complete (all pieces downloaded)
|
||||
|
@ -2997,6 +3034,8 @@ namespace libtorrent
|
|||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
m_picker.reset();
|
||||
|
||||
// make the next tracker request
|
||||
// be a completed-event
|
||||
m_event = tracker_request::completed;
|
||||
|
@ -3095,11 +3134,7 @@ namespace libtorrent
|
|||
}
|
||||
#endif
|
||||
|
||||
if (is_seed())
|
||||
{
|
||||
m_state = torrent_status::seeding;
|
||||
m_picker.reset();
|
||||
}
|
||||
if (is_seed()) finished();
|
||||
|
||||
if (!m_connections_initialized)
|
||||
{
|
||||
|
@ -3149,6 +3184,20 @@ namespace libtorrent
|
|||
return m_save_path;
|
||||
}
|
||||
|
||||
bool torrent::rename_file(int index, std::string const& name)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
TORRENT_ASSERT(index >= 0);
|
||||
TORRENT_ASSERT(index < m_torrent_file->num_files());
|
||||
|
||||
if (!m_owning_storage.get()) return false;
|
||||
|
||||
m_owning_storage->async_rename_file(index, name
|
||||
, bind(&torrent::on_file_renamed, shared_from_this(), _1, _2));
|
||||
return true;
|
||||
}
|
||||
|
||||
void torrent::move_storage(fs::path const& save_path)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
@ -3315,6 +3364,55 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void torrent::set_queue_position(int p)
|
||||
{
|
||||
if (p == m_sequence_number) return;
|
||||
|
||||
session_impl::torrent_map& torrents = m_ses.m_torrents;
|
||||
if (p < 0)
|
||||
{
|
||||
for (session_impl::torrent_map::iterator i = torrents.begin()
|
||||
, end(torrents.end()); i != end; ++i)
|
||||
{
|
||||
torrent* t = i->second.get();
|
||||
if (t == this) continue;
|
||||
if (t->m_sequence_number >= m_sequence_number
|
||||
&& t->m_sequence_number != -1)
|
||||
--t->m_sequence_number;
|
||||
}
|
||||
m_sequence_number = p;
|
||||
}
|
||||
else if (p < m_sequence_number)
|
||||
{
|
||||
for (session_impl::torrent_map::iterator i = torrents.begin()
|
||||
, end(torrents.end()); i != end; ++i)
|
||||
{
|
||||
torrent* t = i->second.get();
|
||||
if (t == this) continue;
|
||||
if (t->m_sequence_number >= p
|
||||
&& t->m_sequence_number != -1)
|
||||
++t->m_sequence_number;
|
||||
}
|
||||
m_sequence_number = p;
|
||||
}
|
||||
else if (p > m_sequence_number)
|
||||
{
|
||||
int max_seq = 0;
|
||||
for (session_impl::torrent_map::iterator i = torrents.begin()
|
||||
, end(torrents.end()); i != end; ++i)
|
||||
{
|
||||
torrent* t = i->second.get();
|
||||
if (t == this) continue;
|
||||
int pos = t->m_sequence_number;
|
||||
if (pos <= p
|
||||
&& pos > m_sequence_number
|
||||
&& pos != -1)
|
||||
--t->m_sequence_number;
|
||||
if (pos > max_seq) max_seq = pos;
|
||||
}
|
||||
m_sequence_number = (std::min)(max_seq + 1, p);
|
||||
}
|
||||
}
|
||||
|
||||
void torrent::set_max_uploads(int limit)
|
||||
{
|
||||
|
@ -3564,6 +3662,7 @@ namespace libtorrent
|
|||
|
||||
m_paused = false;
|
||||
m_started = time_now();
|
||||
m_error.clear();
|
||||
|
||||
// tell the tracker that we're back
|
||||
m_event = tracker_request::started;
|
||||
|
@ -3750,6 +3849,7 @@ namespace libtorrent
|
|||
{
|
||||
alerts().post_alert(file_error_alert(j.error_file, get_handle(), j.str));
|
||||
}
|
||||
m_error = j.str;
|
||||
pause();
|
||||
}
|
||||
f(ret);
|
||||
|
@ -3769,8 +3869,8 @@ namespace libtorrent
|
|||
|
||||
for (int i = 0; i < m_torrent_file->num_files(); ++i)
|
||||
{
|
||||
peer_request ret = m_torrent_file->map_file(i, 0, 0);
|
||||
size_type size = m_torrent_file->file_at(i).size;
|
||||
peer_request ret = m_torrent_file->files().map_file(i, 0, 0);
|
||||
size_type size = m_torrent_file->files().at(i).size;
|
||||
|
||||
// zero sized files are considered
|
||||
// 100% done all the time
|
||||
|
@ -3792,7 +3892,7 @@ namespace libtorrent
|
|||
}
|
||||
TORRENT_ASSERT(size == 0);
|
||||
|
||||
fp[i] = static_cast<float>(done) / m_torrent_file->file_at(i).size;
|
||||
fp[i] = static_cast<float>(done) / m_torrent_file->files().at(i).size;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3809,6 +3909,8 @@ namespace libtorrent
|
|||
|
||||
torrent_status st;
|
||||
|
||||
st.error = m_error;
|
||||
|
||||
if (m_last_scrape == min_time())
|
||||
{
|
||||
st.last_scrape = -1;
|
||||
|
@ -3902,20 +4004,22 @@ namespace libtorrent
|
|||
|
||||
st.total_wanted = m_torrent_file->total_size();
|
||||
TORRENT_ASSERT(st.total_wanted >= 0);
|
||||
TORRENT_ASSERT(st.total_wanted >= m_torrent_file->piece_length()
|
||||
* (m_torrent_file->num_pieces() - 1));
|
||||
|
||||
if (m_picker.get() && (m_picker->num_filtered() > 0
|
||||
|| m_picker->num_have_filtered() > 0))
|
||||
{
|
||||
int filtered_pieces = m_picker->num_filtered()
|
||||
int num_filtered_pieces = m_picker->num_filtered()
|
||||
+ m_picker->num_have_filtered();
|
||||
int last_piece_index = m_torrent_file->num_pieces() - 1;
|
||||
if (m_picker->piece_priority(last_piece_index) == 0)
|
||||
{
|
||||
st.total_wanted -= m_torrent_file->piece_size(last_piece_index);
|
||||
--filtered_pieces;
|
||||
--num_filtered_pieces;
|
||||
}
|
||||
|
||||
st.total_wanted -= filtered_pieces * m_torrent_file->piece_length();
|
||||
st.total_wanted -= size_type(num_filtered_pieces) * m_torrent_file->piece_length();
|
||||
}
|
||||
|
||||
TORRENT_ASSERT(st.total_wanted >= st.total_wanted_done);
|
||||
|
|
|
@ -215,6 +215,12 @@ namespace libtorrent
|
|||
TORRENT_FORWARD(move_storage(save_path));
|
||||
}
|
||||
|
||||
void torrent_handle::rename_file(int index, fs::path const& new_name) const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
TORRENT_FORWARD(rename_file(index, new_name.string()));
|
||||
}
|
||||
|
||||
void torrent_handle::add_extension(
|
||||
boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext
|
||||
, void* userdata)
|
||||
|
@ -277,6 +283,36 @@ namespace libtorrent
|
|||
TORRENT_FORWARD(auto_managed(m));
|
||||
}
|
||||
|
||||
int torrent_handle::queue_position() const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
TORRENT_FORWARD_RETURN(queue_position(), -1);
|
||||
}
|
||||
|
||||
void torrent_handle::queue_position_up() const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
TORRENT_FORWARD(set_queue_position(t->queue_position() - 1));
|
||||
}
|
||||
|
||||
void torrent_handle::queue_position_down() const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
TORRENT_FORWARD(set_queue_position(t->queue_position() + 1));
|
||||
}
|
||||
|
||||
void torrent_handle::queue_position_top() const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
TORRENT_FORWARD(set_queue_position(0));
|
||||
}
|
||||
|
||||
void torrent_handle::queue_position_bottom() const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
TORRENT_FORWARD(set_queue_position((std::numeric_limits<int>::max)()));
|
||||
}
|
||||
|
||||
void torrent_handle::set_tracker_login(std::string const& name
|
||||
, std::string const& password) const
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2008, Arvid Norberg
|
||||
Copyright (c) 2003-2008, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -153,11 +153,7 @@ namespace
|
|||
// save the original encoding and replace the
|
||||
// commonly used path with the correctly
|
||||
// encoded string
|
||||
if (!valid_encoding)
|
||||
{
|
||||
target.orig_path.reset(new fs::path(target.path));
|
||||
target.path = tmp_path;
|
||||
}
|
||||
if (!valid_encoding) target.path = tmp_path;
|
||||
}
|
||||
|
||||
bool extract_single_file(lazy_entry const& dict, file_entry& target
|
||||
|
@ -194,40 +190,26 @@ namespace
|
|||
return true;
|
||||
}
|
||||
|
||||
bool extract_files(lazy_entry const& list, std::vector<file_entry>& target
|
||||
bool extract_files(lazy_entry const& list, file_storage& target
|
||||
, std::string const& root_dir)
|
||||
{
|
||||
size_type offset = 0;
|
||||
if (list.type() != lazy_entry::list_t) return false;
|
||||
for (int i = 0, end(list.list_size()); i < end; ++i)
|
||||
{
|
||||
target.push_back(file_entry());
|
||||
if (!extract_single_file(*list.list_at(i), target.back(), root_dir))
|
||||
file_entry e;
|
||||
if (!extract_single_file(*list.list_at(i), e, root_dir))
|
||||
return false;
|
||||
target.back().offset = offset;
|
||||
offset += target.back().size;
|
||||
target.add_file(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
void remove_dir(fs::path& p)
|
||||
{
|
||||
TORRENT_ASSERT(p.begin() != p.end());
|
||||
path tmp;
|
||||
for (path::iterator i = boost::next(p.begin()); i != p.end(); ++i)
|
||||
tmp /= *i;
|
||||
p = tmp;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
// standard constructor that parses a torrent file
|
||||
torrent_info::torrent_info(entry const& torrent_file)
|
||||
: m_num_pieces(0)
|
||||
, m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_info_section_size(0)
|
||||
|
@ -249,8 +231,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
torrent_info::torrent_info(lazy_entry const& torrent_file)
|
||||
: m_num_pieces(0)
|
||||
, m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_info_section_size(0)
|
||||
|
@ -266,8 +247,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
torrent_info::torrent_info(char const* buffer, int size)
|
||||
: m_num_pieces(0)
|
||||
, m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_info_section_size(0)
|
||||
|
@ -289,36 +269,16 @@ namespace libtorrent
|
|||
// just the necessary to use it with piece manager
|
||||
// used for torrents with no metadata
|
||||
torrent_info::torrent_info(sha1_hash const& info_hash)
|
||||
: m_piece_length(0)
|
||||
, m_total_size(0)
|
||||
, m_num_pieces(0)
|
||||
, m_info_hash(info_hash)
|
||||
, m_name()
|
||||
: m_info_hash(info_hash)
|
||||
, m_creation_date(pt::second_clock::universal_time())
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_info_section_size(0)
|
||||
, m_piece_hashes(0)
|
||||
{
|
||||
}
|
||||
|
||||
torrent_info::torrent_info()
|
||||
: m_piece_length(0)
|
||||
, m_total_size(0)
|
||||
, m_num_pieces(0)
|
||||
, m_info_hash(0)
|
||||
, m_name()
|
||||
, m_creation_date(pt::second_clock::universal_time())
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_info_section_size(0)
|
||||
, m_piece_hashes(0)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
torrent_info::torrent_info(char const* filename)
|
||||
: m_num_pieces(0)
|
||||
, m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
{
|
||||
|
@ -349,11 +309,8 @@ namespace libtorrent
|
|||
m_urls.swap(ti.m_urls);
|
||||
m_url_seeds.swap(ti.m_url_seeds);
|
||||
m_files.swap(ti.m_files);
|
||||
m_files.swap(ti.m_remapped_files);
|
||||
m_nodes.swap(ti.m_nodes);
|
||||
swap(m_num_pieces, ti.m_num_pieces);
|
||||
swap(m_info_hash, ti.m_info_hash);
|
||||
m_name.swap(ti.m_name);
|
||||
swap(m_creation_date, ti.m_creation_date);
|
||||
m_comment.swap(ti.m_comment);
|
||||
m_created_by.swap(ti.m_created_by);
|
||||
|
@ -387,27 +344,27 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(section.first[m_info_section_size-1] == 'e');
|
||||
|
||||
// extract piece length
|
||||
m_piece_length = info.dict_find_int_value("piece length", -1);
|
||||
if (m_piece_length <= 0)
|
||||
int piece_length = info.dict_find_int_value("piece length", -1);
|
||||
if (piece_length <= 0)
|
||||
{
|
||||
error = "invalid or missing 'piece length' entry in torrent file";
|
||||
return false;
|
||||
}
|
||||
m_files.set_piece_length(piece_length);
|
||||
|
||||
// extract file name (or the directory name if it's a multifile libtorrent)
|
||||
m_name = info.dict_find_string_value("name.utf-8");
|
||||
if (m_name.empty()) m_name = info.dict_find_string_value("name");
|
||||
|
||||
if (m_name.empty())
|
||||
std::string name = info.dict_find_string_value("name.utf-8");
|
||||
if (name.empty()) name = info.dict_find_string_value("name");
|
||||
if (name.empty())
|
||||
{
|
||||
error = "invalid name in torrent file";
|
||||
error = "missing name in torrent file";
|
||||
return false;
|
||||
}
|
||||
|
||||
fs::path tmp = m_name;
|
||||
fs::path tmp = name;
|
||||
if (tmp.is_complete())
|
||||
{
|
||||
m_name = tmp.leaf();
|
||||
name = tmp.leaf();
|
||||
}
|
||||
else if (tmp.has_branch_path())
|
||||
{
|
||||
|
@ -418,9 +375,9 @@ namespace libtorrent
|
|||
if (*i == "." || *i == "..") continue;
|
||||
p /= *i;
|
||||
}
|
||||
m_name = p.string();
|
||||
name = p.string();
|
||||
}
|
||||
if (m_name == ".." || m_name == ".")
|
||||
if (name == ".." || name == ".")
|
||||
{
|
||||
error = "invalid 'name' of torrent (possible exploit attempt)";
|
||||
return false;
|
||||
|
@ -433,7 +390,7 @@ namespace libtorrent
|
|||
// if there's no list of files, there has to be a length
|
||||
// field.
|
||||
file_entry e;
|
||||
e.path = m_name;
|
||||
e.path = name;
|
||||
e.offset = 0;
|
||||
e.size = info.dict_find_int_value("length", -1);
|
||||
if (e.size < 0)
|
||||
|
@ -441,29 +398,26 @@ namespace libtorrent
|
|||
error = "invalid length of torrent";
|
||||
return false;
|
||||
}
|
||||
m_files.push_back(e);
|
||||
m_files.add_file(e);
|
||||
m_multifile = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!extract_files(*i, m_files, m_name))
|
||||
if (!extract_files(*i, m_files, name))
|
||||
{
|
||||
error = "failed to parse files from torrent file";
|
||||
return false;
|
||||
}
|
||||
m_multifile = true;
|
||||
}
|
||||
|
||||
// calculate total size of all pieces
|
||||
m_total_size = 0;
|
||||
for (std::vector<file_entry>::iterator i = m_files.begin(); i != m_files.end(); ++i)
|
||||
m_total_size += i->size;
|
||||
m_files.set_name(name);
|
||||
|
||||
// extract sha-1 hashes for all pieces
|
||||
// we want this division to round upwards, that's why we have the
|
||||
// extra addition
|
||||
|
||||
m_num_pieces = static_cast<int>((m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
m_files.set_num_pieces(int((m_files.total_size() + m_files.piece_length() - 1)
|
||||
/ m_files.piece_length()));
|
||||
|
||||
lazy_entry const* pieces = info.dict_find("pieces");
|
||||
if (pieces == 0 || pieces->type() != lazy_entry::string_t)
|
||||
|
@ -472,7 +426,7 @@ namespace libtorrent
|
|||
return false;
|
||||
}
|
||||
|
||||
if (pieces->string_length() != m_num_pieces * 20)
|
||||
if (pieces->string_length() != m_files.num_pieces() * 20)
|
||||
{
|
||||
error = "incorrect number of piece hashes in torrent file";
|
||||
return false;
|
||||
|
@ -630,122 +584,11 @@ namespace libtorrent
|
|||
os << "number of pieces: " << num_pieces() << "\n";
|
||||
os << "piece length: " << piece_length() << "\n";
|
||||
os << "files:\n";
|
||||
for (file_iterator i = begin_files(); i != end_files(); ++i)
|
||||
for (file_storage::iterator i = m_files.begin(); i != m_files.end(); ++i)
|
||||
os << " " << std::setw(11) << i->size << " " << i->path.string() << "\n";
|
||||
}
|
||||
|
||||
// ------- end deprecation -------
|
||||
|
||||
int torrent_info::piece_size(int index) const
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0 && index < num_pieces());
|
||||
if (index == num_pieces()-1)
|
||||
{
|
||||
int size = int(total_size()
|
||||
- (num_pieces() - 1) * piece_length());
|
||||
TORRENT_ASSERT(size > 0);
|
||||
TORRENT_ASSERT(size <= piece_length());
|
||||
return int(size);
|
||||
}
|
||||
else
|
||||
return piece_length();
|
||||
}
|
||||
|
||||
bool torrent_info::remap_files(std::vector<file_entry> const& map)
|
||||
{
|
||||
size_type offset = 0;
|
||||
m_remapped_files.resize(map.size());
|
||||
|
||||
for (int i = 0; i < int(map.size()); ++i)
|
||||
{
|
||||
file_entry& fe = m_remapped_files[i];
|
||||
fe.path = map[i].path;
|
||||
fe.offset = offset;
|
||||
fe.size = map[i].size;
|
||||
fe.file_base = map[i].file_base;
|
||||
fe.orig_path.reset();
|
||||
offset += fe.size;
|
||||
}
|
||||
if (offset != total_size())
|
||||
{
|
||||
m_remapped_files.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::vector<file_entry> map2(m_remapped_files);
|
||||
std::sort(map2.begin(), map2.end()
|
||||
, bind(&file_entry::file_base, _1) < bind(&file_entry::file_base, _2));
|
||||
std::stable_sort(map2.begin(), map2.end()
|
||||
, bind(&file_entry::path, _1) < bind(&file_entry::path, _2));
|
||||
fs::path last_path;
|
||||
size_type last_end = 0;
|
||||
for (std::vector<file_entry>::iterator i = map2.begin(), end(map2.end());
|
||||
i != end; ++i)
|
||||
{
|
||||
if (last_path == i->path)
|
||||
{
|
||||
assert(last_end <= i->file_base);
|
||||
}
|
||||
last_end = i->file_base + i->size;
|
||||
last_path = i->path;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<file_slice> torrent_info::map_block(int piece, size_type offset
|
||||
, int size_, bool storage) const
|
||||
{
|
||||
TORRENT_ASSERT(num_files() > 0);
|
||||
std::vector<file_slice> ret;
|
||||
|
||||
size_type start = piece * (size_type)m_piece_length + offset;
|
||||
size_type size = size_;
|
||||
TORRENT_ASSERT(start + size <= m_total_size);
|
||||
|
||||
// find the file iterator and file offset
|
||||
// TODO: make a vector that can map piece -> file index in O(1)
|
||||
size_type file_offset = start;
|
||||
std::vector<file_entry>::const_iterator file_iter;
|
||||
|
||||
int counter = 0;
|
||||
for (file_iter = begin_files(storage);; ++counter, ++file_iter)
|
||||
{
|
||||
TORRENT_ASSERT(file_iter != end_files(storage));
|
||||
if (file_offset < file_iter->size)
|
||||
{
|
||||
file_slice f;
|
||||
f.file_index = counter;
|
||||
f.offset = file_offset + file_iter->file_base;
|
||||
f.size = (std::min)(file_iter->size - file_offset, (size_type)size);
|
||||
size -= f.size;
|
||||
file_offset += f.size;
|
||||
ret.push_back(f);
|
||||
}
|
||||
|
||||
TORRENT_ASSERT(size >= 0);
|
||||
if (size <= 0) break;
|
||||
|
||||
file_offset -= file_iter->size;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
peer_request torrent_info::map_file(int file_index, size_type file_offset
|
||||
, int size, bool storage) const
|
||||
{
|
||||
TORRENT_ASSERT(file_index < num_files(storage));
|
||||
TORRENT_ASSERT(file_index >= 0);
|
||||
size_type offset = file_offset + file_at(file_index, storage).offset;
|
||||
|
||||
peer_request ret;
|
||||
ret.piece = int(offset / piece_length());
|
||||
ret.start = int(offset - ret.piece * piece_length());
|
||||
ret.length = size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -156,8 +156,8 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(t);
|
||||
|
||||
// this is always a seed
|
||||
incoming_bitfield(std::vector<bool>(
|
||||
t->torrent_file().num_pieces(), true));
|
||||
incoming_have_all();
|
||||
|
||||
// it is always possible to request pieces
|
||||
incoming_unchoke();
|
||||
|
||||
|
@ -229,7 +229,7 @@ namespace libtorrent
|
|||
request += "\r\nProxy-Connection: keep-alive";
|
||||
}
|
||||
request += "\r\nRange: bytes=";
|
||||
request += boost::lexical_cast<std::string>(r.piece
|
||||
request += boost::lexical_cast<std::string>(size_type(r.piece)
|
||||
* info.piece_length() + r.start);
|
||||
request += "-";
|
||||
request += boost::lexical_cast<std::string>(r.piece
|
||||
|
@ -242,7 +242,7 @@ namespace libtorrent
|
|||
}
|
||||
else
|
||||
{
|
||||
std::vector<file_slice> files = info.map_block(r.piece, r.start
|
||||
std::vector<file_slice> files = info.files().map_block(r.piece, r.start
|
||||
, r.length);
|
||||
|
||||
for (std::vector<file_slice>::iterator i = files.begin();
|
||||
|
@ -254,13 +254,13 @@ namespace libtorrent
|
|||
if (using_proxy)
|
||||
{
|
||||
request += m_url;
|
||||
std::string path = info.file_at(f.file_index).path.string();
|
||||
std::string path = info.files().at(f.file_index).path.string();
|
||||
request += escape_path(path.c_str(), path.length());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string path = m_path;
|
||||
path += info.file_at(f.file_index).path.string();
|
||||
path += info.files().at(f.file_index).path.string();
|
||||
request += escape_path(path.c_str(), path.length());
|
||||
}
|
||||
request += " HTTP/1.1\r\n";
|
||||
|
@ -426,7 +426,7 @@ namespace libtorrent
|
|||
int file_index = m_file_requests.front();
|
||||
|
||||
torrent_info const& info = t->torrent_file();
|
||||
std::string path = info.file_at(file_index).path.string();
|
||||
std::string path = info.files().at(file_index).path.string();
|
||||
path = escape_path(path.c_str(), path.length());
|
||||
size_t i = location.rfind(path);
|
||||
if (i == std::string::npos)
|
||||
|
@ -511,7 +511,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
int file_index = m_file_requests.front();
|
||||
peer_request in_range = info.map_file(file_index, range_start
|
||||
peer_request in_range = info.files().map_file(file_index, range_start
|
||||
, int(range_end - range_start));
|
||||
|
||||
peer_request front_request = m_requests.front();
|
||||
|
|
Loading…
Add table
Reference in a new issue