lt sync 2370

This commit is contained in:
Andrew Resch 2008-06-02 17:40:37 +00:00
parent 8e11197ac9
commit 772f80e622
44 changed files with 1497 additions and 897 deletions

View file

@ -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);

View file

@ -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)

View file

@ -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)

View file

@ -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;

View file

@ -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

View file

@ -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;

View 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

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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()

View file

@ -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:

View 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

View file

@ -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

View file

@ -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;

View file

@ -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
{

View file

@ -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)

View file

@ -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

View file

@ -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>

View file

@ -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

View file

@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_TIME_HPP_INCLUDED
#include <ctime>
#include <boost/version.hpp>
#ifndef _WIN32
#include <unistd.h>

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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>

View file

@ -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

View file

@ -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;
}
}

View file

@ -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)

View file

@ -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);

View 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);
}
}

View file

@ -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++);

View file

@ -206,7 +206,7 @@ namespace libtorrent
int num_digits(int val)
{
int ret = 1;
while (val > 10)
while (val >= 10)
{
++ret;
val /= 10;

View file

@ -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;

View file

@ -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

View file

@ -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();

View file

@ -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);

View file

@ -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()

View file

@ -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);

View file

@ -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";

View file

@ -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);

View file

@ -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
{

View file

@ -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;
}
}

View file

@ -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();