lt sync 2370

This commit is contained in:
Andrew Resch 2008-06-02 17:40:37 +00:00
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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <libtorrent/peer_info.hpp> #include <libtorrent/peer_info.hpp>
#include <libtorrent/bitfield.hpp>
#include <boost/python.hpp> #include <boost/python.hpp>
#include <boost/python/iterator.hpp> #include <boost/python/iterator.hpp>
@ -35,7 +36,7 @@ list get_pieces(peer_info const& pi)
{ {
list ret; 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) , end(pi.pieces.end()); i != end; ++i)
{ {
ret.append(*i); ret.append(*i);

View file

@ -6,6 +6,7 @@
#include <libtorrent/entry.hpp> #include <libtorrent/entry.hpp>
#include <libtorrent/peer_request.hpp> #include <libtorrent/peer_request.hpp>
#include <libtorrent/disk_buffer_holder.hpp> #include <libtorrent/disk_buffer_holder.hpp>
#include <libtorrent/bitfield.hpp>
#include <boost/python.hpp> #include <boost/python.hpp>
using namespace boost::python; using namespace boost::python;
@ -119,17 +120,26 @@ namespace
return this->peer_plugin::on_have(index); 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")) if (override f = this->get_override("on_bitfield"))
return f(bitfield); return f(bf);
else 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) bool on_request(peer_request const& req)

View file

@ -41,14 +41,14 @@ namespace
return result; 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) { //list files(torrent_info const& ti, bool storage) {
@ -57,7 +57,7 @@ namespace
typedef std::vector<file_entry> list_type; 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); result.append(*i);
return result; return result;
@ -70,10 +70,12 @@ void bind_torrent_info()
{ {
return_value_policy<copy_const_reference> copy; 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<entry const&>())
.def(init<sha1_hash 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_tracker", &torrent_info::add_tracker, (arg("url"), arg("tier")=0))
.def("add_url_seed", &torrent_info::add_url_seed) .def("add_url_seed", &torrent_info::add_url_seed)

View file

@ -4,6 +4,7 @@
#include <libtorrent/torrent_handle.hpp> #include <libtorrent/torrent_handle.hpp>
#include <boost/python.hpp> #include <boost/python.hpp>
#include <libtorrent/bitfield.hpp>
using namespace boost::python; using namespace boost::python;
using namespace libtorrent; using namespace libtorrent;
@ -12,7 +13,7 @@ object pieces(torrent_status const& s)
{ {
list result; 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); result.append(*i);
return result; return result;

View file

@ -53,6 +53,21 @@ namespace libtorrent
torrent_handle handle; 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 struct TORRENT_EXPORT tracker_alert: torrent_alert
{ {
tracker_alert(torrent_handle const& h tracker_alert(torrent_handle const& h

View file

@ -514,10 +514,6 @@ namespace libtorrent
// port we'll bind the next outgoing socket to // port we'll bind the next outgoing socket to
int m_next_port; int m_next_port;
// the sequence number to assign to the
// next torrent that's added
int m_torrent_sequence;
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
boost::intrusive_ptr<dht::dht_tracker> m_dht; boost::intrusive_ptr<dht::dht_tracker> m_dht;
dht_settings m_dht_settings; 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_not_interested();
void write_request(peer_request const& r); void write_request(peer_request const& r);
void write_cancel(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_have(int index);
void write_piece(peer_request const& r, disk_buffer_holder& buffer); void write_piece(peer_request const& r, disk_buffer_holder& buffer);
void write_handshake(); void write_handshake();

View file

@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_CHAINED_BUFFER_HPP_INCLUDED #define TORRENT_CHAINED_BUFFER_HPP_INCLUDED
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/version.hpp>
#if BOOST_VERSION < 103500 #if BOOST_VERSION < 103500
#include <asio/buffer.hpp> #include <asio/buffer.hpp>
#else #else

View file

@ -35,6 +35,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/bencode.hpp" #include "libtorrent/bencode.hpp"
#include "libtorrent/peer_id.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 <vector>
#include <string> #include <string>
#include <utility> #include <utility>
@ -44,8 +50,10 @@ POSSIBILITY OF SUCH DAMAGE.
#endif #endif
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/scoped_ptr.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
@ -56,26 +64,29 @@ namespace libtorrent
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
namespace pt = boost::posix_time; 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; entry generate() const;
file_storage const& files() const { return m_files; }
void set_comment(char const* str); void set_comment(char const* str);
void set_creator(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 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_url_seed(std::string const& url);
void add_node(std::pair<std::string, int> const& node); void add_node(std::pair<std::string, int> const& node);
void add_tracker(std::string const& url, int tier = 0); void add_tracker(std::string const& url, int tier = 0);
int num_pieces() const { return m_num_pieces; } int num_pieces() const { return m_files.num_pieces(); }
int piece_length() const { return m_piece_length; } int piece_length() const { return m_files.piece_length(); }
int piece_size(int i) const; int piece_size(int i) const { return m_files.piece_size(i); }
private: private:
file_storage& m_files;
// the urls to the trackers // the urls to the trackers
typedef std::pair<std::string, int> announce_entry; typedef std::pair<std::string, int> announce_entry;
std::vector<announce_entry> m_urls; std::vector<announce_entry> m_urls;
@ -84,32 +95,15 @@ namespace libtorrent
std::vector<sha1_hash> m_piece_hash; 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 // dht nodes to add to the routing table/bootstrap from
typedef std::vector<std::pair<std::string, int> > nodes_t; typedef std::vector<std::pair<std::string, int> > nodes_t;
nodes_t m_nodes; 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 // the hash that identifies this torrent
// is mutable because it's calculated // is mutable because it's calculated
// lazily // lazily
mutable sha1_hash m_info_hash; mutable sha1_hash m_info_hash;
std::string m_name;
// if a creation date is found in the torrent file // if a creation date is found in the torrent file
// this will be set to that, otherwise it'll be // this will be set to that, otherwise it'll be
// 1970, Jan 1 // 1970, Jan 1
@ -134,6 +128,72 @@ namespace libtorrent
// be announced on the dht // be announced on the dht
bool m_private; 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 #endif

View file

@ -82,6 +82,7 @@ namespace libtorrent
, check_fastresume , check_fastresume
, check_files , check_files
, save_resume_data , save_resume_data
, rename_file
}; };
action_t action; action_t action;
@ -91,7 +92,7 @@ namespace libtorrent
boost::intrusive_ptr<piece_manager> storage; boost::intrusive_ptr<piece_manager> storage;
// arguments used for read and write // arguments used for read and write
int piece, offset; 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 // to the error message
std::string str; std::string str;

View file

@ -57,6 +57,7 @@ namespace libtorrent
class peer_connection; class peer_connection;
class entry; class entry;
struct disk_buffer_holder; struct disk_buffer_holder;
struct bitfield;
struct TORRENT_EXPORT torrent_plugin struct TORRENT_EXPORT torrent_plugin
{ {
@ -129,7 +130,7 @@ namespace libtorrent
virtual bool on_have(int index) virtual bool on_have(int index)
{ return false; } { return false; }
virtual bool on_bitfield(std::vector<bool> const& bitfield) virtual bool on_bitfield(bitfield const& bitfield)
{ return false; } { return false; }
virtual bool on_have_all() 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 boost::shared_ptr<file> open_file(void* st, fs::path const& p
, file::open_mode m, std::string& error); , file::open_mode m, std::string& error);
void release(void* st); void release(void* st);
void release(fs::path const& p);
void resize(int size); void resize(int size);
private: 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/assert.hpp"
#include "libtorrent/chained_buffer.hpp" #include "libtorrent/chained_buffer.hpp"
#include "libtorrent/disk_buffer_holder.hpp" #include "libtorrent/disk_buffer_holder.hpp"
#include "libtorrent/bitfield.hpp"
namespace libtorrent namespace libtorrent
{ {
@ -242,7 +243,7 @@ namespace libtorrent
boost::shared_ptr<socket_type> get_socket() const { return m_socket; } boost::shared_ptr<socket_type> get_socket() const { return m_socket; }
tcp::endpoint const& remote() const { return m_remote; } 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& allowed_fast();
std::vector<int> const& suggested_pieces() const { return m_suggested_pieces; } std::vector<int> const& suggested_pieces() const { return m_suggested_pieces; }
@ -328,7 +329,7 @@ namespace libtorrent
void incoming_interested(); void incoming_interested();
void incoming_not_interested(); void incoming_not_interested();
void incoming_have(int piece_index); 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_request(peer_request const& r);
void incoming_piece(peer_request const& p, disk_buffer_holder& data); void incoming_piece(peer_request const& p, disk_buffer_holder& data);
void incoming_piece(peer_request const& p, char const* data); void incoming_piece(peer_request const& p, char const* data);
@ -629,7 +630,7 @@ namespace libtorrent
peer_id m_peer_id; peer_id m_peer_id;
// the pieces the other end have // the pieces the other end have
std::vector<bool> m_have_piece; bitfield m_have_piece;
// the queue of requests we have got // the queue of requests we have got
// from this peer // from this peer

View file

@ -33,12 +33,11 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef TORRENT_PEER_INFO_HPP_INCLUDED #ifndef TORRENT_PEER_INFO_HPP_INCLUDED
#define TORRENT_PEER_INFO_HPP_INCLUDED #define TORRENT_PEER_INFO_HPP_INCLUDED
#include <vector>
#include "libtorrent/socket.hpp" #include "libtorrent/socket.hpp"
#include "libtorrent/peer_id.hpp" #include "libtorrent/peer_id.hpp"
#include "libtorrent/size_type.hpp" #include "libtorrent/size_type.hpp"
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/bitfield.hpp"
namespace libtorrent namespace libtorrent
{ {
@ -96,7 +95,7 @@ namespace libtorrent
size_type total_download; size_type total_download;
size_type total_upload; size_type total_upload;
peer_id pid; peer_id pid;
std::vector<bool> pieces; bitfield pieces;
int upload_limit; int upload_limit;
int download_limit; int download_limit;

View file

@ -58,6 +58,7 @@ namespace libtorrent
class torrent; class torrent;
class peer_connection; class peer_connection;
class bitfield;
struct TORRENT_EXPORT piece_block struct TORRENT_EXPORT piece_block
{ {
@ -138,7 +139,7 @@ namespace libtorrent
// the vector tells which pieces we already have // the vector tells which pieces we already have
// and which we don't 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 // increases the peer count for the given piece
// (is used when a HAVE message is received) // (is used when a HAVE message is received)
@ -147,10 +148,10 @@ namespace libtorrent
// increases the peer count for the given piece // increases the peer count for the given piece
// (is used when a BITFIELD message is received) // (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 // decreases the peer count for the given piece
// (used when a peer disconnects) // (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 // these will increase and decrease the peer count
// of all pieces. They are used when seeds join // 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! // THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION!
// The last argument is the policy::peer pointer for the peer that // The last argument is the policy::peer pointer for the peer that
// we'll download from. // we'll download from.
void pick_pieces(std::vector<bool> const& pieces void pick_pieces(bitfield const& pieces
, std::vector<piece_block>& interesting_blocks , std::vector<piece_block>& interesting_blocks
, int num_pieces, int prefer_whole_pieces , int num_pieces, int prefer_whole_pieces
, void* peer, piece_state_t speed , void* peer, piece_state_t speed
@ -207,14 +208,14 @@ namespace libtorrent
// blocks to be picked. Blocks are not picked from pieces // blocks to be picked. Blocks are not picked from pieces
// that are being downloaded // that are being downloaded
int add_blocks(std::vector<int> const& piece_list int add_blocks(std::vector<int> const& piece_list
, const std::vector<bool>& pieces , bitfield const& pieces
, std::vector<piece_block>& interesting_blocks , std::vector<piece_block>& interesting_blocks
, int num_blocks, int prefer_whole_pieces , int num_blocks, int prefer_whole_pieces
, void* peer, std::vector<int> const& ignore) const; , void* peer, std::vector<int> const& ignore) const;
// picks blocks only from downloading pieces // picks blocks only from downloading pieces
int add_blocks_downloading( int add_blocks_downloading(
std::vector<bool> const& pieces bitfield const& pieces
, std::vector<piece_block>& interesting_blocks , std::vector<piece_block>& interesting_blocks
, std::vector<piece_block>& backup_blocks , std::vector<piece_block>& backup_blocks
, int num_blocks, int prefer_whole_pieces , int num_blocks, int prefer_whole_pieces
@ -280,7 +281,7 @@ namespace libtorrent
void verify_priority(int start, int end, int prio) const; void verify_priority(int start, int end, int prio) const;
void check_invariant(const torrent* t = 0) const; void check_invariant(const torrent* t = 0) const;
void verify_pick(std::vector<piece_block> const& picked void verify_pick(std::vector<piece_block> const& picked
, std::vector<bool> const& bitfield) const; , bitfield const& bits) const;
void print_pieces() const; void print_pieces() const;
#endif #endif
@ -302,9 +303,9 @@ namespace libtorrent
friend struct piece_pos; 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::pair<int, int> expand_piece(int piece, int whole_pieces
, std::vector<bool> const& have) const; , bitfield const& have) const;
struct piece_pos struct piece_pos
{ {

View file

@ -129,7 +129,7 @@ namespace libtorrent
, resume_data(0) , resume_data(0)
, storage_mode(storage_mode_sparse) , storage_mode(storage_mode_sparse)
, paused(true) , paused(true)
, auto_managed(true) , auto_managed(false)
, duplicate_is_error(false) , duplicate_is_error(false)
, storage(sc) , storage(sc)
, userdata(0) , userdata(0)

View file

@ -135,6 +135,7 @@ namespace libtorrent
, close_redundant_connections(true) , close_redundant_connections(true)
, auto_scrape_interval(1800) , auto_scrape_interval(1800)
, auto_scrape_min_interval(300) , auto_scrape_min_interval(300)
, max_peerlist_size(8000)
{} {}
// this is the user agent that will be sent to the tracker // 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 // the minimum number of seconds between any
// automatic scrape (regardless of torrent) // automatic scrape (regardless of torrent)
int auto_scrape_min_interval; 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 #ifndef TORRENT_DISABLE_DHT

View file

@ -45,6 +45,8 @@ POSSIBILITY OF SUCH DAMAGE.
#define Protocol Protocol_ #define Protocol Protocol_
#endif #endif
#include <boost/version.hpp>
#if BOOST_VERSION < 103500 #if BOOST_VERSION < 103500
#include <asio/ip/tcp.hpp> #include <asio/ip/tcp.hpp>
#include <asio/ip/udp.hpp> #include <asio/ip/udp.hpp>

View file

@ -87,11 +87,11 @@ namespace libtorrent
#endif #endif
TORRENT_EXPORT std::vector<std::pair<size_type, std::time_t> > get_filesizes( TORRENT_EXPORT std::vector<std::pair<size_type, std::time_t> > get_filesizes(
torrent_info const& t file_storage const& t
, fs::path p); , fs::path p);
TORRENT_EXPORT bool match_filesizes( TORRENT_EXPORT bool match_filesizes(
torrent_info const& t file_storage const& t
, fs::path p , fs::path p
, std::vector<std::pair<size_type, std::time_t> > const& sizes , std::vector<std::pair<size_type, std::time_t> > const& sizes
, bool compact_mode , bool compact_mode
@ -157,6 +157,9 @@ namespace libtorrent
// non-zero return value indicates an error // non-zero return value indicates an error
virtual bool release_files() = 0; 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 // this will close all open files and delete them
// non-zero return value indicates an error // non-zero return value indicates an error
virtual bool delete_files() = 0; virtual bool delete_files() = 0;
@ -178,16 +181,12 @@ namespace libtorrent
}; };
typedef storage_interface* (&storage_constructor_type)( typedef storage_interface* (&storage_constructor_type)(
boost::intrusive_ptr<torrent_info const>, fs::path const& file_storage const&, fs::path const&, file_pool&);
, file_pool&);
TORRENT_EXPORT storage_interface* default_storage_constructor( TORRENT_EXPORT storage_interface* default_storage_constructor(
boost::intrusive_ptr<torrent_info const> ti file_storage const&, fs::path const&, file_pool&);
, fs::path const& path, file_pool& fp);
TORRENT_EXPORT storage_interface* mapped_storage_constructor( TORRENT_EXPORT storage_interface* mapped_storage_constructor(
boost::intrusive_ptr<torrent_info const> ti file_storage const&, fs::path const&, file_pool&);
, fs::path const& path, file_pool& fp);
struct disk_io_thread; struct disk_io_thread;
@ -201,7 +200,7 @@ namespace libtorrent
piece_manager( piece_manager(
boost::shared_ptr<void> const& torrent boost::shared_ptr<void> const& torrent
, boost::intrusive_ptr<torrent_info const> ti , boost::intrusive_ptr<torrent_info const> info
, fs::path const& path , fs::path const& path
, file_pool& fp , file_pool& fp
, disk_io_thread& io , disk_io_thread& io
@ -210,8 +209,7 @@ namespace libtorrent
~piece_manager(); ~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 write_resume_data(entry& rd) const;
void async_check_fastresume(entry const* resume_data 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_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( void async_read(
peer_request const& r peer_request const& r
, boost::function<void(int, disk_io_job const&)> const& handler , 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 release_files_impl() { return m_storage->release_files(); }
int delete_files_impl() { return m_storage->delete_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); bool move_storage_impl(fs::path const& save_path);
@ -326,12 +329,13 @@ namespace libtorrent
void debug_log() const; void debug_log() const;
#endif #endif
#endif #endif
boost::intrusive_ptr<torrent_info const> m_info;
file_storage const& m_files;
boost::scoped_ptr<storage_interface> m_storage; boost::scoped_ptr<storage_interface> m_storage;
storage_mode_t m_storage_mode; storage_mode_t m_storage_mode;
boost::intrusive_ptr<torrent_info const> m_info;
// slots that haven't had any file storage allocated // slots that haven't had any file storage allocated
std::vector<int> m_unallocated_slots; std::vector<int> m_unallocated_slots;
// slots that have file storage, but isn't assigned to a piece // 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 #define TORRENT_TIME_HPP_INCLUDED
#include <ctime> #include <ctime>
#include <boost/version.hpp>
#ifndef _WIN32 #ifndef _WIN32
#include <unistd.h> #include <unistd.h>

View file

@ -70,6 +70,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/storage.hpp" #include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp" #include "libtorrent/hasher.hpp"
#include "libtorrent/assert.hpp" #include "libtorrent/assert.hpp"
#include "libtorrent/bitfield.hpp"
namespace libtorrent namespace libtorrent
{ {
@ -79,6 +80,7 @@ namespace libtorrent
class piece_manager; class piece_manager;
struct torrent_plugin; struct torrent_plugin;
struct bitfield;
namespace aux namespace aux
{ {
@ -167,6 +169,9 @@ namespace libtorrent
void set_sequential_download(bool sd); 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); void second_tick(stat& accumulator, float tick_interval);
// debug purpose only // debug purpose only
@ -181,6 +186,7 @@ namespace libtorrent
void ip_filter_updated() { m_policy.ip_filter_updated(); } void ip_filter_updated() { m_policy.ip_filter_updated(); }
bool has_error() const { return !m_error.empty(); }
void pause(); void pause();
void resume(); void resume();
bool is_paused() const { return m_paused; } bool is_paused() const { return m_paused; }
@ -375,7 +381,7 @@ namespace libtorrent
return m_have_pieces[index]; return m_have_pieces[index];
} }
const std::vector<bool>& pieces() const bitfield const& pieces() const
{ return m_have_pieces; } { return m_have_pieces; }
int num_pieces() const { return m_num_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 // 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()) if (m_picker.get())
{ {
TORRENT_ASSERT(!is_seed()); TORRENT_ASSERT(!is_seed());
m_picker->inc_refcount(bitfield); m_picker->inc_refcount(bits);
} }
#ifndef NDEBUG #ifndef NDEBUG
else else
@ -562,8 +568,14 @@ namespace libtorrent
int max_uploads() const { return m_max_uploads; } int max_uploads() const { return m_max_uploads; }
void set_max_connections(int limit); void set_max_connections(int limit);
int max_connections() const { return m_max_connections; } int max_connections() const { return m_max_connections; }
void move_storage(fs::path const& save_path); 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 // unless this returns true, new connections must wait
// with their initialization. // with their initialization.
bool ready_for_connections() const bool ready_for_connections() const
@ -587,6 +599,7 @@ namespace libtorrent
void on_torrent_paused(int ret, disk_io_job const& j); void on_torrent_paused(int ret, disk_io_job const& j);
void on_storage_moved(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_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 void on_piece_verified(int ret, disk_io_job const& j
, boost::function<void(int)> f); , boost::function<void(int)> f);
@ -728,7 +741,7 @@ namespace libtorrent
// this is an index into m_trackers // this is an index into m_trackers
// the bitmask that says which pieces we have // 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 // the number of bytes that has been
// downloaded that failed the hash-test // downloaded that failed the hash-test
@ -750,6 +763,10 @@ namespace libtorrent
// the state of this torrent (queued, checking, downloading) // the state of this torrent (queued, checking, downloading)
torrent_status::state_t m_state; 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; entry m_resume_data;
// if the torrent is started without metadata, it may // if the torrent is started without metadata, it may

View file

@ -137,6 +137,8 @@ namespace libtorrent
state_t state; state_t state;
bool paused; bool paused;
float progress; float progress;
std::string error;
boost::posix_time::time_duration next_announce; boost::posix_time::time_duration next_announce;
boost::posix_time::time_duration announce_interval; boost::posix_time::time_duration announce_interval;
@ -198,7 +200,7 @@ namespace libtorrent
// we potentially could connect to // we potentially could connect to
int connect_candidates; int connect_candidates;
const std::vector<bool>* pieces; bitfield const* pieces;
// this is the number of pieces the client has // this is the number of pieces the client has
// downloaded. it is equal to: // downloaded. it is equal to:
@ -344,6 +346,12 @@ namespace libtorrent
bool is_auto_managed() const; bool is_auto_managed() const;
void auto_managed(bool m) 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 #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
void resolve_countries(bool r); void resolve_countries(bool r);
bool resolve_countries() const; bool resolve_countries() const;
@ -440,6 +448,7 @@ namespace libtorrent
// post condition: save_path() == save_path if true is returned // post condition: save_path() == save_path if true is returned
void move_storage(fs::path const& save_path) const; 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; 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. All rights reserved.
Redistribution and use in source and binary forms, with or without 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 #ifndef TORRENT_TORRENT_INFO_HPP_INCLUDED
#define TORRENT_TORRENT_INFO_HPP_INCLUDE #define TORRENT_TORRENT_INFO_HPP_INCLUDED
#include <string> #include <string>
#include <vector> #include <vector>
@ -44,7 +43,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp> #include <boost/shared_array.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
@ -56,44 +54,17 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/socket.hpp" #include "libtorrent/socket.hpp"
#include "libtorrent/peer_id.hpp" #include "libtorrent/peer_id.hpp"
#include "libtorrent/size_type.hpp" #include "libtorrent/size_type.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/time.hpp" #include "libtorrent/time.hpp"
#include "libtorrent/intrusive_ptr_base.hpp" #include "libtorrent/intrusive_ptr_base.hpp"
#include "libtorrent/assert.hpp" #include "libtorrent/assert.hpp"
#include "libtorrent/file_storage.hpp"
namespace libtorrent namespace libtorrent
{ {
namespace pt = boost::posix_time; namespace pt = boost::posix_time;
namespace gr = boost::gregorian; 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 struct TORRENT_EXPORT announce_entry
{ {
announce_entry(std::string const& u): url(u), tier(0) {} announce_entry(std::string const& u): url(u), tier(0) {}
@ -101,124 +72,73 @@ namespace libtorrent
int tier; int tier;
}; };
#ifndef BOOST_NO_EXCEPTIONS
struct TORRENT_EXPORT invalid_torrent_file: std::exception struct TORRENT_EXPORT invalid_torrent_file: std::exception
{ {
virtual const char* what() const throw() { return "invalid torrent file"; } virtual const char* what() const throw() { return "invalid torrent file"; }
}; };
#endif
class TORRENT_EXPORT torrent_info : public intrusive_ptr_base<torrent_info> class TORRENT_EXPORT torrent_info : public intrusive_ptr_base<torrent_info>
{ {
public: public:
torrent_info();
torrent_info(sha1_hash const& info_hash); torrent_info(sha1_hash const& info_hash);
torrent_info(lazy_entry const& torrent_file); torrent_info(lazy_entry const& torrent_file);
torrent_info(char const* buffer, int size); torrent_info(char const* buffer, int size);
torrent_info(char const* filename); torrent_info(char const* filename);
~torrent_info(); ~torrent_info();
file_storage const& files() const { return m_files; }
void add_tracker(std::string const& url, int tier = 0); 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 std::vector<std::string> const& url_seeds() const
{ return m_url_seeds; } { return m_url_seeds; }
void add_url_seed(std::string const& url) void add_url_seed(std::string const& url)
{ m_url_seeds.push_back(url); } { m_url_seeds.push_back(url); }
typedef std::vector<file_entry>::const_iterator file_iterator; size_type total_size() const { return m_files.total_size(); }
typedef std::vector<file_entry>::const_reverse_iterator reverse_file_iterator; int piece_length() const { return m_files.piece_length(); }
int num_pieces() const { return m_files.num_pieces(); }
// 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; }
const sha1_hash& info_hash() const { return m_info_hash; } 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 ------- // ------- start deprecation -------
// these functions will be removed in a future version // these functions will be removed in a future version
torrent_info(entry const& torrent_file) TORRENT_DEPRECATED; torrent_info(entry const& torrent_file) TORRENT_DEPRECATED;
void print(std::ostream& os) const TORRENT_DEPRECATED; void print(std::ostream& os) const TORRENT_DEPRECATED;
// ------- end deprecation ------- // ------- 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; } 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 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 char const* hash_for_piece_ptr(int index) const
{ {
TORRENT_ASSERT(index >= 0); 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);
TORRENT_ASSERT(m_piece_hashes >= m_info_section.get()); TORRENT_ASSERT(m_piece_hashes >= m_info_section.get());
TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size); 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); bool parse_torrent_file(lazy_entry const& libtorrent, std::string& error);
file_storage m_files;
// the urls to the trackers // the urls to the trackers
std::vector<announce_entry> m_urls; std::vector<announce_entry> m_urls;
std::vector<std::string> m_url_seeds; 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; 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 // the hash that identifies this torrent
// is mutable because it's calculated // is mutable because it's calculated
// lazily // lazily
sha1_hash m_info_hash; sha1_hash m_info_hash;
std::string m_name;
// if a creation date is found in the torrent file // if a creation date is found in the torrent file
// this will be set to that, otherwise it'll be // this will be set to that, otherwise it'll be
// 1970, Jan 1 // 1970, Jan 1

View file

@ -30,6 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <boost/version.hpp>
#if BOOST_VERSION < 103500 #if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp> #include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp> #include <asio/ip/multicast.hpp>

View file

@ -937,21 +937,11 @@ namespace libtorrent
buffer::const_interval recv_buffer = receive_buffer(); 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()) incoming_bitfield(bits);
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);
} }
// ----------------------------- // -----------------------------
@ -1426,7 +1416,7 @@ namespace libtorrent
send_buffer(msg, sizeof(msg)); 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; INVARIANT_CHECK;
@ -1459,12 +1449,14 @@ namespace libtorrent
return; return;
} }
int num_pieces = bitfield.size(); int num_pieces = bits.size();
int lazy_pieces[50]; int lazy_pieces[50];
int num_lazy_pieces = 0; int num_lazy_pieces = 0;
int lazy_piece = 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) if (t->is_seed() && m_ses.settings().lazy_bitfields)
{ {
num_lazy_pieces = (std::min)(50, num_pieces / 10); num_lazy_pieces = (std::min)(50, num_pieces / 10);
@ -1491,7 +1483,7 @@ namespace libtorrent
++lazy_piece; ++lazy_piece;
continue; continue;
} }
if (bitfield[i]) bitfield_string << "1"; if (bits[i]) bitfield_string << "1";
else bitfield_string << "0"; else bitfield_string << "0";
} }
bitfield_string << "\n"; bitfield_string << "\n";
@ -1506,18 +1498,9 @@ namespace libtorrent
detail::write_int32(packet_size - 4, i.begin); detail::write_int32(packet_size - 4, i.begin);
detail::write_uint8(msg_bitfield, i.begin); detail::write_uint8(msg_bitfield, i.begin);
std::fill(i.begin, i.end, 0); memcpy(i.begin, bits.bytes(), packet_size - 5);
for (int c = 0; c < num_pieces; ++c) for (int c = 0; c < num_lazy_pieces; ++c)
{ i.begin[lazy_pieces[c] / 8] &= ~(0x80 >> (lazy_pieces[c] & 7));
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));
}
TORRENT_ASSERT(i.end - i.begin == (num_pieces + 7) / 8); TORRENT_ASSERT(i.end - i.begin == (num_pieces + 7) / 8);
#ifndef NDEBUG #ifndef NDEBUG

View file

@ -31,7 +31,8 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "libtorrent/create_torrent.hpp" #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/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp> #include <boost/date_time/gregorian/gregorian.hpp>
@ -41,22 +42,61 @@ namespace gr = boost::gregorian;
namespace libtorrent namespace libtorrent
{ {
create_torrent::create_torrent() create_torrent::create_torrent(file_storage& fs, int size)
: m_piece_length(0) : m_files(fs)
, m_total_size(0)
, m_num_pieces(0)
, m_info_hash()
, m_name()
, m_creation_date(pt::second_clock::universal_time()) , m_creation_date(pt::second_clock::universal_time())
, m_multifile(false) , m_multifile(fs.num_files() > 1)
, m_private(false) , 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 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 // TODO: throw something here
// throw // throw
@ -128,15 +168,13 @@ namespace libtorrent
} }
entry& info = dict["info"]; entry& info = dict["info"];
info["name"] = m_files.name();
info["name"] = m_name;
if (m_private) info["private"] = 1; if (m_private) info["private"] = 1;
if (!m_multifile) if (!m_multifile)
{ {
info["length"] = m_files.front().second; info["length"] = m_files.at(0).size;
} }
else else
{ {
@ -144,19 +182,19 @@ namespace libtorrent
{ {
entry& files = info["files"]; 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) i != m_files.end(); ++i)
{ {
files.list().push_back(entry()); files.list().push_back(entry());
entry& file_e = files.list().back(); entry& file_e = files.list().back();
file_e["length"] = i->second; file_e["length"] = i->size;
entry& path_e = file_e["path"]; entry& path_e = file_e["path"];
TORRENT_ASSERT(i->first.has_branch_path()); TORRENT_ASSERT(i->path.has_branch_path());
TORRENT_ASSERT(*i->first.begin() == m_name); TORRENT_ASSERT(*i->path.begin() == m_files.name());
for (fs::path::iterator j = boost::next(i->first.begin()); for (fs::path::iterator j = boost::next(i->path.begin());
j != i->first.end(); ++j) j != i->path.end(); ++j)
{ {
path_e.list().push_back(entry(*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"]; entry& pieces = info["pieces"];
std::string& p = pieces.string(); 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) void create_torrent::add_tracker(std::string const& url, int tier)
{ {
m_urls.push_back(announce_entry(url, 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)); , 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) void create_torrent::set_hash(int index, sha1_hash const& h)
{ {
TORRENT_ASSERT(index >= 0); TORRENT_ASSERT(index >= 0);
@ -240,46 +237,6 @@ namespace libtorrent
m_piece_hash[index] = h; 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) void create_torrent::add_node(std::pair<std::string, int> const& node)
{ {
m_nodes.push_back(node); m_nodes.push_back(node);
@ -299,5 +256,6 @@ namespace libtorrent
{ {
m_created_by = str; m_created_by = str;
} }
} }

View file

@ -1049,6 +1049,13 @@ namespace libtorrent
ret = 0; ret = 0;
break; 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 #ifndef BOOST_NO_EXCEPTIONS
} catch (std::exception& e) } catch (std::exception& e)

View file

@ -115,6 +115,16 @@ namespace libtorrent
return e.file_ptr; 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) void file_pool::release(void* st)
{ {
boost::mutex::scoped_lock l(m_mutex); 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]; torrent_entry& v = m_map[m.info_hash];
peer_entry e; 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(); e.added = time_now();
std::set<peer_entry>::iterator i = v.peers.find(e); std::set<peer_entry>::iterator i = v.peers.find(e);
if (i != v.peers.end()) v.peers.erase(i++); if (i != v.peers.end()) v.peers.erase(i++);

View file

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

View file

@ -64,7 +64,9 @@ namespace libtorrent
{ {
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
#if BOOST_VERSION >= 103500 #if BOOST_VERSION >= 103500
using boost::system::error_code; typedef boost::system::error_code ec_t;
#else
typedef error_code ec_t;
#endif #endif
struct mapped_file_pool struct mapped_file_pool
@ -85,7 +87,7 @@ namespace libtorrent
#ifndef NDEBUG #ifndef NDEBUG
if (file_size > 0) if (file_size > 0)
{ {
error_code ec; ec_t ec;
fs::file_status st = fs::status(path, ec); fs::file_status st = fs::status(path, ec);
TORRENT_ASSERT(!fs::exists(st)); TORRENT_ASSERT(!fs::exists(st));
} }
@ -207,7 +209,7 @@ namespace libtorrent
#if BOOST_VERSION < 103500 #if BOOST_VERSION < 103500
fs::system_error_type ec; fs::system_error_type ec;
#else #else
error_code ec; ec_t ec;
#endif #endif
fs::file_status st = fs::status(p, ec); fs::file_status st = fs::status(p, ec);
@ -260,8 +262,8 @@ namespace libtorrent
struct mapped_storage: storage_interface struct mapped_storage: storage_interface
{ {
mapped_storage(boost::intrusive_ptr<torrent_info const> const& info, fs::path save_path) mapped_storage(file_storage const& fs, fs::path save_path)
: m_info(info) : m_files(fs)
, m_save_path(save_path) , m_save_path(save_path)
{} {}
@ -270,9 +272,9 @@ namespace libtorrent
int read(char* buf, int slot, int offset, int size) int read(char* buf, int slot, int offset, int size)
{ {
TORRENT_ASSERT(buf != 0); 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 >= 0);
TORRENT_ASSERT(offset < m_info->piece_size(slot)); TORRENT_ASSERT(offset < m_files.piece_size(slot));
TORRENT_ASSERT(size > 0); TORRENT_ASSERT(size > 0);
size_type result = -1; size_type result = -1;
@ -281,17 +283,17 @@ namespace libtorrent
#ifndef NDEBUG #ifndef NDEBUG
std::vector<file_slice> slices std::vector<file_slice> slices
= m_info->map_block(slot, offset, size, true); = files().map_block(slot, offset, size);
TORRENT_ASSERT(!slices.empty()); TORRENT_ASSERT(!slices.empty());
#endif #endif
size_type start = slot * (size_type)m_info->piece_length() + offset; size_type start = slot * (size_type)m_files.piece_length() + offset;
TORRENT_ASSERT(start + size <= m_info->total_size()); TORRENT_ASSERT(start + size <= m_files.total_size());
// find the file iterator and file offset // find the file iterator and file offset
size_type file_offset = start; size_type file_offset = start;
std::vector<file_entry>::const_iterator file_iter; 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) if (file_offset < file_iter->size)
break; break;
@ -331,7 +333,7 @@ namespace libtorrent
TORRENT_ASSERT(int(slices.size()) > counter); TORRENT_ASSERT(int(slices.size()) > counter);
size_type slice_size = slices[counter].size; size_type slice_size = slices[counter].size;
TORRENT_ASSERT(slice_size == read_bytes); 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); == file_iter->path);
#endif #endif
@ -351,7 +353,7 @@ namespace libtorrent
{ {
++file_iter; ++file_iter;
// skip empty files // 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; ++file_iter;
#ifndef NDEBUG #ifndef NDEBUG
@ -388,24 +390,24 @@ namespace libtorrent
int write(const char* buf, int slot, int offset, int size) int write(const char* buf, int slot, int offset, int size)
{ {
TORRENT_ASSERT(buf != 0); 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 >= 0);
TORRENT_ASSERT(offset < m_info->piece_size(slot)); TORRENT_ASSERT(offset < m_files.piece_size(slot));
TORRENT_ASSERT(size > 0); TORRENT_ASSERT(size > 0);
#ifndef NDEBUG #ifndef NDEBUG
std::vector<file_slice> slices std::vector<file_slice> slices
= m_info->map_block(slot, offset, size, true); = files().map_block(slot, offset, size);
TORRENT_ASSERT(!slices.empty()); TORRENT_ASSERT(!slices.empty());
#endif #endif
size_type start = slot * (size_type)m_info->piece_length() + offset; size_type start = slot * (size_type)m_files.piece_length() + offset;
TORRENT_ASSERT(start + size <= m_info->total_size()); TORRENT_ASSERT(start + size <= m_files.total_size());
// find the file iterator and file offset // find the file iterator and file offset
size_type file_offset = start; size_type file_offset = start;
std::vector<file_entry>::const_iterator file_iter; 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) if (file_offset < file_iter->size)
break; break;
@ -447,7 +449,7 @@ namespace libtorrent
TORRENT_ASSERT(int(slices.size()) > counter); TORRENT_ASSERT(int(slices.size()) > counter);
size_type slice_size = slices[counter].size; size_type slice_size = slices[counter].size;
TORRENT_ASSERT(slice_size == write_bytes); 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); == file_iter->path);
#endif #endif
@ -466,7 +468,7 @@ namespace libtorrent
if (left_to_write > 0) if (left_to_write > 0)
{ {
++file_iter; ++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; ++file_iter;
#ifndef NDEBUG #ifndef NDEBUG
// empty files are not returned by map_block, so if // empty files are not returned by map_block, so if
@ -531,11 +533,11 @@ namespace libtorrent
m_pool.release(this); m_pool.release(this);
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400 #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
old_path = safe_convert((m_save_path / m_info->name()).string()); old_path = safe_convert((m_save_path / files().name()).string());
new_path = safe_convert((save_path / m_info->name()).string()); new_path = safe_convert((save_path / files().name()).string());
#else #else
old_path = m_save_path / m_info->name(); old_path = m_save_path / files().name();
new_path = save_path / m_info->name(); new_path = save_path / files().name();
#endif #endif
try try
@ -602,7 +604,7 @@ namespace libtorrent
} }
entry::list_type const& slots = slots_ent->list(); 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() && std::find_if(slots.begin(), slots.end()
, boost::bind<bool>(std::less<int>() , boost::bind<bool>(std::less<int>()
, boost::bind((size_type const& (entry::*)() const) , boost::bind((size_type const& (entry::*)() const)
@ -615,11 +617,11 @@ namespace libtorrent
if (seed) 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: " 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>(file_sizes.size()) + " actual: "
+ boost::lexical_cast<std::string>(m_info->num_files(true)) + ")"; + boost::lexical_cast<std::string>(files().num_files()) + ")";
return false; return false;
} }
@ -627,8 +629,8 @@ namespace libtorrent
fs = file_sizes.begin(); fs = file_sizes.begin();
// the resume data says we have the entire torrent // the resume data says we have the entire torrent
// make sure the file sizes are the right ones // make sure the file sizes are the right ones
for (torrent_info::file_iterator i = m_info->begin_files(true) for (file_storage::iterator i = files().begin()
, end(m_info->end_files(true)); i != end; ++i, ++fs) , end(files().end()); i != end; ++i, ++fs)
{ {
if (i->size != fs->first) if (i->size != fs->first)
{ {
@ -641,7 +643,7 @@ namespace libtorrent
return true; 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); , !full_allocation_mode, &error);
} }
@ -653,7 +655,7 @@ namespace libtorrent
return true; return true;
} }
std::vector<std::pair<size_type, std::time_t> > file_sizes 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(); entry::list_type& fl = rd["file sizes"].list();
for (std::vector<std::pair<size_type, std::time_t> >::iterator i 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) bool move_slot(int src_slot, int dst_slot)
{ {
// TODO: this can be optimized by mapping both slots and do a straight memcpy // 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); m_scratch_buffer.resize(piece_size);
size_type ret1 = read(&m_scratch_buffer[0], src_slot, 0, 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); 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 // 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 // the size of the target slot is the size of the piece
int piece_size = m_info->piece_length(); int piece_size = m_files.piece_length();
int piece1_size = m_info->piece_size(slot2); int piece1_size = m_files.piece_size(slot2);
int piece2_size = m_info->piece_size(slot1); int piece2_size = m_files.piece_size(slot1);
m_scratch_buffer.resize(piece_size * 2); m_scratch_buffer.resize(piece_size * 2);
size_type ret1 = read(&m_scratch_buffer[0], slot1, 0, piece1_size); 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); 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 // 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 // the size of the target slot is the size of the piece
int piece_size = m_info->piece_length(); int piece_size = m_files.piece_length();
int piece1_size = m_info->piece_size(slot2); int piece1_size = m_files.piece_size(slot2);
int piece2_size = m_info->piece_size(slot3); int piece2_size = m_files.piece_size(slot3);
int piece3_size = m_info->piece_size(slot1); int piece3_size = m_files.piece_size(slot1);
m_scratch_buffer.resize(piece_size * 2); m_scratch_buffer.resize(piece_size * 2);
size_type ret1 = read(&m_scratch_buffer[0], slot1, 0, piece1_size); 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); size_type ret2 = read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size);
@ -743,6 +745,39 @@ namespace libtorrent
#endif #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() bool release_files()
{ {
m_pool.release(this); m_pool.release(this);
@ -762,8 +797,8 @@ namespace libtorrent
// delete the files from disk // delete the files from disk
std::set<std::string> directories; std::set<std::string> directories;
typedef std::set<std::string>::iterator iter_t; typedef std::set<std::string>::iterator iter_t;
for (torrent_info::file_iterator i = m_info->begin_files(true) for (file_storage::iterator i = m_files.begin()
, end(m_info->end_files(true)); i != end; ++i) , end(m_files.end()); i != end; ++i)
{ {
std::string p = (m_save_path / i->path).string(); std::string p = (m_save_path / i->path).string();
fs::path bp = i->path.branch_path(); fs::path bp = i->path.branch_path();
@ -802,7 +837,10 @@ namespace libtorrent
private: 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; fs::path m_save_path;
// temporary storage for moving pieces // temporary storage for moving pieces
@ -811,10 +849,10 @@ namespace libtorrent
static mapped_file_pool m_pool; 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) , 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; mapped_file_pool mapped_storage::m_pool;

View file

@ -32,7 +32,9 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/pch.hpp" #include "libtorrent/pch.hpp"
#include <boost/version.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#if BOOST_VERSION < 103500 #if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp> #include <asio/ip/host_name.hpp>
#else #else

View file

@ -326,7 +326,7 @@ namespace libtorrent
TORRENT_ASSERT(t); TORRENT_ASSERT(t);
bool interested = false; 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) for (int j = 0; j != (int)we_have.size(); ++j)
{ {
if (!we_have[j] if (!we_have[j]
@ -579,7 +579,7 @@ namespace libtorrent
m_statistics.add_stat(downloaded, uploaded); 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; return m_have_piece;
} }
@ -749,7 +749,7 @@ namespace libtorrent
// if we don't have valid metadata yet, // if we don't have valid metadata yet,
// leave the vector unallocated // leave the vector unallocated
TORRENT_ASSERT(m_num_pieces == 0); 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()); TORRENT_ASSERT(!m_torrent.expired());
} }
@ -1082,7 +1082,7 @@ namespace libtorrent
} }
else else
{ {
m_have_piece[index] = true; m_have_piece.set_bit(index);
// only update the piece_picker if // only update the piece_picker if
// we have the metadata and if // we have the metadata and if
@ -1127,7 +1127,7 @@ namespace libtorrent
// --------- BITFIELD ---------- // --------- BITFIELD ----------
// ----------------------------- // -----------------------------
void peer_connection::incoming_bitfield(std::vector<bool> const& bitfield) void peer_connection::incoming_bitfield(bitfield const& bits)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
@ -1138,7 +1138,7 @@ namespace libtorrent
for (extension_list_t::iterator i = m_extensions.begin() for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i) , end(m_extensions.end()); i != end; ++i)
{ {
if ((*i)->on_bitfield(bitfield)) return; if ((*i)->on_bitfield(bits)) return;
} }
#endif #endif
@ -1147,9 +1147,9 @@ namespace libtorrent
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() << " <== BITFIELD "; (*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"; else (*m_logger) << "0";
} }
(*m_logger) << "\n"; (*m_logger) << "\n";
@ -1158,10 +1158,10 @@ namespace libtorrent
// if we don't have the metedata, we cannot // if we don't have the metedata, we cannot
// verify the bitfield size // verify the bitfield size
if (t->valid_metadata() if (t->valid_metadata()
&& (bitfield.size() / 8) != (m_have_piece.size() / 8)) && (bits.size() / 8) != (m_have_piece.size() / 8))
{ {
std::stringstream msg; 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. expected: " << (m_have_piece.size() / 8)
<< " bytes"; << " bytes";
disconnect(msg.str().c_str(), 2); disconnect(msg.str().c_str(), 2);
@ -1174,15 +1174,15 @@ namespace libtorrent
// (since it doesn't exist yet) // (since it doesn't exist yet)
if (!t->ready_for_connections()) if (!t->ready_for_connections())
{ {
m_have_piece = bitfield; m_have_piece = bits;
m_num_pieces = std::count(bitfield.begin(), bitfield.end(), true); m_num_pieces = bits.count();
if (m_peer_info) m_peer_info->seed = (m_num_pieces == int(bitfield.size())); if (m_peer_info) m_peer_info->seed = (m_num_pieces == int(bits.size()));
return; return;
} }
TORRENT_ASSERT(t->valid_metadata()); 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())) if (num_pieces == int(m_have_piece.size()))
{ {
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
@ -1197,7 +1197,7 @@ namespace libtorrent
return; return;
} }
std::fill(m_have_piece.begin(), m_have_piece.end(), true); m_have_piece.set_all();
m_num_pieces = num_pieces; m_num_pieces = num_pieces;
t->peer_has_all(); t->peer_has_all();
if (!t->is_finished()) if (!t->is_finished())
@ -1211,11 +1211,11 @@ namespace libtorrent
bool interesting = false; bool interesting = false;
if (!t->is_seed()) if (!t->is_seed())
{ {
t->peer_has(bitfield); t->peer_has(bits);
for (int i = 0; i < (int)m_have_piece.size(); ++i) 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 (have && !m_have_piece[i])
{ {
if (!t->have_piece(i) && t->picker().piece_priority(i) != 0) 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; m_num_pieces = num_pieces;
if (interesting) t->get_policy().peer_is_interesting(*this); if (interesting) t->get_policy().peer_is_interesting(*this);
@ -1764,7 +1764,7 @@ namespace libtorrent
} }
TORRENT_ASSERT(!m_have_piece.empty()); 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(); m_num_pieces = m_have_piece.size();
t->peer_has_all(); t->peer_has_all();

View file

@ -42,6 +42,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/piece_picker.hpp" #include "libtorrent/piece_picker.hpp"
#include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/bitfield.hpp"
#ifndef NDEBUG #ifndef NDEBUG
#include "libtorrent/peer_connection.hpp" #include "libtorrent/peer_connection.hpp"
@ -122,16 +123,17 @@ namespace libtorrent
} }
// pieces is a bitmask with the pieces we have // 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; TORRENT_PIECE_PICKER_INVARIANT_CHECK;
#ifndef NDEBUG #ifndef NDEBUG
m_files_checked_called = true; m_files_checked_called = true;
#endif #endif
for (std::vector<bool>::const_iterator i = pieces.begin(); int index = 0;
i != pieces.end(); ++i) 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]; piece_pos& p = m_piece_map[index];
if (*i) we_have(index); if (*i) we_have(index);
else TORRENT_ASSERT(p.index == 0); else TORRENT_ASSERT(p.index == 0);
@ -214,15 +216,15 @@ namespace libtorrent
#ifndef NDEBUG #ifndef NDEBUG
void piece_picker::verify_pick(std::vector<piece_block> const& picked 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() for (std::vector<piece_block>::const_iterator i = picked.begin()
, end(picked.end()); i != end; ++i) , end(picked.end()); i != end; ++i)
{ {
TORRENT_ASSERT(i->piece_index >= 0); TORRENT_ASSERT(i->piece_index >= 0);
TORRENT_ASSERT(i->piece_index < int(bitfield.size())); TORRENT_ASSERT(i->piece_index < int(bits.size()));
TORRENT_ASSERT(bitfield[i->piece_index]); TORRENT_ASSERT(bits[i->piece_index]);
TORRENT_ASSERT(!m_piece_map[i->piece_index].have()); TORRENT_ASSERT(!m_piece_map[i->piece_index].have());
} }
} }
@ -887,14 +889,14 @@ namespace libtorrent
if (prev_priority >= 0) update(prev_priority, p.index); 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_PIECE_PICKER_INVARIANT_CHECK;
TORRENT_ASSERT(bitmask.size() == m_piece_map.size()); TORRENT_ASSERT(bitmask.size() == m_piece_map.size());
int index = 0; int index = 0;
bool updated = false; 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) , end(bitmask.end()); i != end; ++i, ++index)
{ {
if (*i) if (*i)
@ -907,14 +909,14 @@ namespace libtorrent
if (updated && m_sequential_download == -1) m_dirty = true; 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_PIECE_PICKER_INVARIANT_CHECK;
TORRENT_ASSERT(bitmask.size() == m_piece_map.size()); TORRENT_ASSERT(bitmask.size() == m_piece_map.size());
int index = 0; int index = 0;
bool updated = false; 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) , end(bitmask.end()); i != end; ++i, ++index)
{ {
if (*i) if (*i)
@ -1156,7 +1158,7 @@ namespace libtorrent
// to pick blocks from the same pieces as fast peers, and vice // to pick blocks from the same pieces as fast peers, and vice
// versa. Downloading pieces are marked as being fast, medium // versa. Downloading pieces are marked as being fast, medium
// or slow once they're started. // 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 , std::vector<piece_block>& interesting_blocks
, int num_blocks, int prefer_whole_pieces , int num_blocks, int prefer_whole_pieces
, void* peer, piece_state_t speed, bool rarest_first , void* peer, piece_state_t speed, bool rarest_first
@ -1279,7 +1281,7 @@ namespace libtorrent
, backup_blocks.begin(), backup_blocks.end()); , 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())); TORRENT_ASSERT(piece >= 0 && piece < int(m_piece_map.size()));
return bitmask[piece] return bitmask[piece]
@ -1326,7 +1328,7 @@ namespace libtorrent
} }
int piece_picker::add_blocks(std::vector<int> const& piece_list 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 , std::vector<piece_block>& interesting_blocks
, int num_blocks, int prefer_whole_pieces , int num_blocks, int prefer_whole_pieces
, void* peer, std::vector<int> const& ignore) const , void* peer, std::vector<int> const& ignore) const
@ -1388,7 +1390,7 @@ namespace libtorrent
return num_blocks; 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>& interesting_blocks
, std::vector<piece_block>& backup_blocks , std::vector<piece_block>& backup_blocks
, int num_blocks, int prefer_whole_pieces , 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::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); if (whole_pieces == 0) return std::make_pair(piece, piece + 1);

View file

@ -150,18 +150,7 @@ namespace
tcp::endpoint const& m_ep; tcp::endpoint const& m_ep;
}; };
struct match_peer_id #ifndef NDEBUG
{
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;
};
struct match_peer_connection struct match_peer_connection
{ {
match_peer_connection(peer_connection const& c) match_peer_connection(peer_connection const& c)
@ -177,7 +166,7 @@ namespace
peer_connection const& m_conn; peer_connection const& m_conn;
}; };
#endif
} }
@ -244,7 +233,7 @@ namespace libtorrent
busy_pieces.reserve(num_requests); busy_pieces.reserve(num_requests);
std::vector<int> const& suggested = c.suggested_pieces(); 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()) if (c.has_peer_choked())
{ {
@ -254,10 +243,10 @@ namespace libtorrent
std::vector<int> const& allowed_fast = c.allowed_fast(); std::vector<int> const& allowed_fast = c.allowed_fast();
// build a bitmask with only the allowed pieces in it // 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() for (std::vector<int>::const_iterator i = allowed_fast.begin()
, end(allowed_fast.end()); i != end; ++i) , 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 p.pick_pieces(mask, interesting_pieces
, num_requests, prefer_whole_pieces, c.peer_info_struct() , 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 // the last argument is if we should prefer whole pieces
// for this peer. If we're downloading one piece in 20 seconds // for this peer. If we're downloading one piece in 20 seconds
// then use this mode. // 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() , num_requests, prefer_whole_pieces, c.peer_info_struct()
, state, rarest_first, c.on_parole(), suggested); , 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(); 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); 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 (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() 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 < if (now - pe.connected <
seconds(m_round_robin->second.failcount * min_reconnect_time)) seconds(pe.failcount * min_reconnect_time))
continue; continue;
candidate = m_round_robin; candidate = current;
} }
#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING #if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING
@ -484,45 +509,6 @@ namespace libtorrent
if (m_torrent->is_paused()) return; 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 // upload shift
// ------------------------ // ------------------------
@ -658,6 +644,12 @@ namespace libtorrent
error_code ec; error_code ec;
TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint(ec) || 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); peer p(c.remote(), peer::not_connectable, 0);
i = m_peers.insert(std::make_pair(c.remote().address(), p)); i = m_peers.insert(std::make_pair(c.remote().address(), p));
#ifndef TORRENT_DISABLE_GEO_IP #ifndef TORRENT_DISABLE_GEO_IP
@ -750,7 +742,7 @@ namespace libtorrent
if (ses.m_alerts.should_post(alert::info)) if (ses.m_alerts.should_post(alert::info))
{ {
ses.m_alerts.post_alert(peer_blocked_alert(remote.address() 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; return 0;
} }
@ -776,11 +768,14 @@ namespace libtorrent
if (ses.m_alerts.should_post(alert::info)) if (ses.m_alerts.should_post(alert::info))
{ {
ses.m_alerts.post_alert(peer_blocked_alert(remote.address() 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; return 0;
} }
if (m_peers.size() >= m_torrent->settings().max_peerlist_size)
return 0;
// we don't have any info about this peer. // we don't have any info about this peer.
// add a new entry // add a new entry
i = m_peers.insert(std::make_pair(remote.address() i = m_peers.insert(std::make_pair(remote.address()

View file

@ -169,7 +169,6 @@ namespace aux {
, m_auto_scrape_time_scaler(180) , m_auto_scrape_time_scaler(180)
, m_incoming_connection(false) , m_incoming_connection(false)
, m_last_tick(time_now()) , m_last_tick(time_now())
, m_torrent_sequence(0)
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
, m_dht_same_port(true) , m_dht_same_port(true)
, m_external_udp_port(0) , m_external_udp_port(0)
@ -1043,7 +1042,7 @@ namespace aux {
else else
++uncongested_torrents; ++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; ++num_paused_auto_managed;
if (!least_recently_scraped->second->is_auto_managed() if (!least_recently_scraped->second->is_auto_managed()
@ -1308,7 +1307,7 @@ namespace aux {
{ {
torrent* t = i->second.get(); torrent* t = i->second.get();
TORRENT_ASSERT(t); TORRENT_ASSERT(t);
if (t->is_auto_managed()) if (t->is_auto_managed() && !t->has_error())
{ {
// this torrent is auto managed, add it to // this torrent is auto managed, add it to
// the list (depending on if it's a seed or not) // the list (depending on if it's a seed or not)
@ -1661,7 +1660,7 @@ namespace aux {
{ {
TORRENT_ASSERT(!params.save_path.empty()); 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 #ifndef BOOST_NO_EXCEPTIONS
throw std::runtime_error("no files in torrent"); throw std::runtime_error("no files in torrent");
@ -1703,6 +1702,14 @@ namespace aux {
#endif #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 // create the torrent and the data associated with
// the checker thread and store it before starting // the checker thread and store it before starting
// the thread // the thread
@ -1711,17 +1718,16 @@ namespace aux {
torrent_ptr.reset(new torrent(*this, params.ti, params.save_path torrent_ptr.reset(new torrent(*this, params.ti, params.save_path
, m_listen_interface, params.storage_mode, 16 * 1024 , m_listen_interface, params.storage_mode, 16 * 1024
, params.storage, params.paused, params.resume_data , params.storage, params.paused, params.resume_data
, m_torrent_sequence, params.auto_managed)); , queue_pos, params.auto_managed));
} }
else else
{ {
torrent_ptr.reset(new torrent(*this, params.tracker_url, *ih, params.name torrent_ptr.reset(new torrent(*this, params.tracker_url, *ih, params.name
, params.save_path, m_listen_interface, params.storage_mode, 16 * 1024 , params.save_path, m_listen_interface, params.storage_mode, 16 * 1024
, params.storage, params.paused, params.resume_data , params.storage, params.paused, params.resume_data
, m_torrent_sequence, params.auto_managed)); , queue_pos, params.auto_managed));
} }
torrent_ptr->start(); torrent_ptr->start();
++m_torrent_sequence;
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin() for (extension_list_t::iterator i = m_extensions.begin()
@ -1745,6 +1751,11 @@ namespace aux {
m_torrents.insert(std::make_pair(*ih, torrent_ptr)); 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); return torrent_handle(torrent_ptr);
} }
@ -1816,6 +1827,7 @@ namespace aux {
#ifndef NDEBUG #ifndef NDEBUG
sha1_hash i_hash = t.torrent_file().info_hash(); sha1_hash i_hash = t.torrent_file().info_hash();
#endif #endif
i->second->set_queue_position(-1);
m_torrents.erase(i); m_torrents.erase(i);
TORRENT_ASSERT(m_torrents.find(i_hash) == m_torrents.end()); TORRENT_ASSERT(m_torrents.find(i_hash) == m_torrents.end());
return; return;
@ -2440,6 +2452,22 @@ namespace aux {
#ifndef NDEBUG #ifndef NDEBUG
void session_impl::check_invariant() const 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_connections > 0);
TORRENT_ASSERT(m_max_uploads > 0); TORRENT_ASSERT(m_max_uploads > 0);
TORRENT_ASSERT(m_allowed_upload_slots >= m_max_uploads); 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( 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); p = complete(p);
std::vector<std::pair<size_type, std::time_t> > sizes; std::vector<std::pair<size_type, std::time_t> > sizes;
for (torrent_info::file_iterator i = t.begin_files(true); for (file_storage::iterator i = s.begin()
i != t.end_files(true); ++i) , end(s.end());i != end; ++i)
{ {
size_type size = 0; size_type size = 0;
std::time_t time = 0; std::time_t time = 0;
@ -289,13 +289,13 @@ namespace libtorrent
// pieces, so any older version of the resume data will // pieces, so any older version of the resume data will
// still be a correct subset of the actual data on disk. // still be a correct subset of the actual data on disk.
bool match_filesizes( bool match_filesizes(
torrent_info const& t file_storage const& fs
, fs::path p , fs::path p
, std::vector<std::pair<size_type, std::time_t> > const& sizes , std::vector<std::pair<size_type, std::time_t> > const& sizes
, bool compact_mode , bool compact_mode
, std::string* error) , 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"; if (error) *error = "mismatching number of files";
return false; return false;
@ -304,8 +304,8 @@ namespace libtorrent
std::vector<std::pair<size_type, std::time_t> >::const_iterator s std::vector<std::pair<size_type, std::time_t> >::const_iterator s
= sizes.begin(); = sizes.begin();
for (torrent_info::file_iterator i = t.begin_files(true); for (file_storage::iterator i = fs.begin()
i != t.end_files(true); ++i, ++s) , end(fs.end());i != end; ++i, ++s)
{ {
size_type size = 0; size_type size = 0;
std::time_t time = 0; std::time_t time = 0;
@ -354,15 +354,16 @@ namespace libtorrent
class storage : public storage_interface, boost::noncopyable class storage : public storage_interface, boost::noncopyable
{ {
public: public:
storage(boost::intrusive_ptr<torrent_info const> info, fs::path const& path, file_pool& fp) storage(file_storage const& fs, fs::path const& path, file_pool& fp)
: m_info(info) : m_files(fs)
, m_files(fp) , 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); m_save_path = fs::complete(path);
TORRENT_ASSERT(m_save_path.is_complete()); TORRENT_ASSERT(m_save_path.is_complete());
} }
bool rename_file(int index, std::string const& new_filename);
bool release_files(); bool release_files();
bool delete_files(); bool delete_files();
bool initialize(bool allocate_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); int read_impl(char* buf, int slot, int offset, int size, bool fill_zero);
~storage() ~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; fs::path m_save_path;
// the file pool is typically stored in // the file pool is typically stored in
// the session, to make all storage // the session, to make all storage
// instances use the same pool // instances use the same pool
file_pool& m_files; file_pool& m_pool;
// temporary storage for moving pieces // temporary storage for moving pieces
buffer m_scratch_buffer; buffer m_scratch_buffer;
@ -399,7 +404,7 @@ namespace libtorrent
hasher whole; hasher whole;
int slot_size1 = piece_size; int slot_size1 = piece_size;
m_scratch_buffer.resize(slot_size1); 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) if (ph.offset > 0)
partial.update(&m_scratch_buffer[0], ph.offset); partial.update(&m_scratch_buffer[0], ph.offset);
whole.update(&m_scratch_buffer[0], slot_size1); whole.update(&m_scratch_buffer[0], slot_size1);
@ -426,8 +431,8 @@ namespace libtorrent
{ {
// first, create all missing directories // first, create all missing directories
fs::path last_path; fs::path last_path;
for (torrent_info::file_iterator file_iter = m_info->begin_files(true), for (file_storage::iterator file_iter = files().begin(),
end_iter = m_info->end_files(true); file_iter != end_iter; ++file_iter) end_iter = files().end(); file_iter != end_iter; ++file_iter)
{ {
fs::path dir = (m_save_path / file_iter->path).branch_path(); fs::path dir = (m_save_path / file_iter->path).branch_path();
@ -475,7 +480,7 @@ namespace libtorrent
if (allocate_files) if (allocate_files)
{ {
std::string error; 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 , m_save_path / file_iter->path, file::in | file::out
, error); , error);
if (f && f->error().empty()) if (f && f->error().empty())
@ -491,13 +496,46 @@ namespace libtorrent
#endif #endif
} }
// close files that were opened in write mode // 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; return false;
} }
bool storage::release_files() bool storage::release_files()
{ {
m_files.release(this); m_pool.release(this);
buffer().swap(m_scratch_buffer); buffer().swap(m_scratch_buffer);
return false; return false;
} }
@ -505,7 +543,7 @@ namespace libtorrent
bool storage::delete_files() bool storage::delete_files()
{ {
// make sure we don't have the files open // make sure we don't have the files open
m_files.release(this); m_pool.release(this);
buffer().swap(m_scratch_buffer); buffer().swap(m_scratch_buffer);
int result = 0; int result = 0;
@ -515,8 +553,8 @@ namespace libtorrent
// delete the files from disk // delete the files from disk
std::set<std::string> directories; std::set<std::string> directories;
typedef std::set<std::string>::iterator iter_t; typedef std::set<std::string>::iterator iter_t;
for (torrent_info::file_iterator i = m_info->begin_files(true) for (file_storage::iterator i = files().begin()
, end(m_info->end_files(true)); i != end; ++i) , end(files().end()); i != end; ++i)
{ {
std::string p = (m_save_path / i->path).string(); std::string p = (m_save_path / i->path).string();
fs::path bp = i->path.branch_path(); fs::path bp = i->path.branch_path();
@ -584,7 +622,7 @@ namespace libtorrent
TORRENT_ASSERT(rd.type() == entry::dictionary_t); TORRENT_ASSERT(rd.type() == entry::dictionary_t);
std::vector<std::pair<size_type, std::time_t> > file_sizes 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(); entry::list_type& fl = rd["file sizes"].list();
for (std::vector<std::pair<size_type, std::time_t> >::iterator i 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(); 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() && std::find_if(slots.begin(), slots.end()
, boost::bind<bool>(std::less<int>() , boost::bind<bool>(std::less<int>()
, boost::bind((size_type const& (entry::*)() const) , boost::bind((size_type const& (entry::*)() const)
@ -655,11 +693,11 @@ namespace libtorrent
if (seed) 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: " 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>(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; return false;
} }
@ -667,8 +705,8 @@ namespace libtorrent
fs = file_sizes.begin(); fs = file_sizes.begin();
// the resume data says we have the entire torrent // the resume data says we have the entire torrent
// make sure the file sizes are the right ones // make sure the file sizes are the right ones
for (torrent_info::file_iterator i = m_info->begin_files(true) for (file_storage::iterator i = files().begin()
, end(m_info->end_files(true)); i != end; ++i, ++fs) , end(files().end()); i != end; ++i, ++fs)
{ {
if (i->size != fs->first) 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); , !full_allocation_mode, &error);
} }
@ -716,14 +754,14 @@ namespace libtorrent
return false; return false;
#endif #endif
m_files.release(this); m_pool.release(this);
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400 #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
old_path = safe_convert((m_save_path / m_info->name()).string()); old_path = safe_convert((m_save_path / files().name()).string());
new_path = safe_convert((save_path / m_info->name()).string()); new_path = safe_convert((save_path / files().name()).string());
#else #else
old_path = m_save_path / m_info->name(); old_path = m_save_path / files().name();
new_path = save_path / m_info->name(); new_path = save_path / files().name();
#endif #endif
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
@ -740,16 +778,20 @@ namespace libtorrent
return true; return true;
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
} }
catch (std::exception&) {} catch (std::exception& e)
return false; {
set_error((m_save_path / files().name()).string(), e.what());
return true;
}
#endif #endif
return false;
} }
#ifndef NDEBUG #ifndef NDEBUG
/* /*
void storage::shuffle() void storage::shuffle()
{ {
int num_pieces = m_info->num_pieces(); int num_pieces = files().num_pieces();
std::vector<int> pieces(num_pieces); std::vector<int> pieces(num_pieces);
for (std::vector<int>::iterator i = pieces.begin(); for (std::vector<int>::iterator i = pieces.begin();
@ -766,7 +808,7 @@ namespace libtorrent
{ {
const int slot_index = targets[i]; const int slot_index = targets[i];
const int piece_index = pieces[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); std::vector<char> buf(slot_size);
read(&buf[0], piece_index, 0, slot_size); read(&buf[0], piece_index, 0, slot_size);
write(&buf[0], slot_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) 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); m_scratch_buffer.resize(piece_size);
int ret1 = read_impl(&m_scratch_buffer[0], src_slot, 0, piece_size, true); 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); 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) bool storage::swap_slots(int slot1, int slot2)
{ {
// the size of the target slot is the size of the piece // the size of the target slot is the size of the piece
int piece_size = m_info->piece_length(); int piece_size = m_files.piece_length();
int piece1_size = m_info->piece_size(slot2); int piece1_size = m_files.piece_size(slot2);
int piece2_size = m_info->piece_size(slot1); int piece2_size = m_files.piece_size(slot1);
m_scratch_buffer.resize(piece_size * 2); m_scratch_buffer.resize(piece_size * 2);
int ret1 = read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true); 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); 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) bool storage::swap_slots3(int slot1, int slot2, int slot3)
{ {
// the size of the target slot is the size of the piece // the size of the target slot is the size of the piece
int piece_size = m_info->piece_length(); int piece_size = m_files.piece_length();
int piece1_size = m_info->piece_size(slot2); int piece1_size = m_files.piece_size(slot2);
int piece2_size = m_info->piece_size(slot3); int piece2_size = m_files.piece_size(slot3);
int piece3_size = m_info->piece_size(slot1); int piece3_size = m_files.piece_size(slot1);
m_scratch_buffer.resize(piece_size * 2); m_scratch_buffer.resize(piece_size * 2);
int ret1 = read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true); 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); int ret2 = read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true);
@ -835,25 +877,25 @@ namespace libtorrent
, bool fill_zero) , bool fill_zero)
{ {
TORRENT_ASSERT(buf != 0); 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 >= 0);
TORRENT_ASSERT(offset < m_info->piece_size(slot)); TORRENT_ASSERT(offset < m_files.piece_size(slot));
TORRENT_ASSERT(size > 0); TORRENT_ASSERT(size > 0);
#ifndef NDEBUG #ifndef NDEBUG
std::vector<file_slice> slices std::vector<file_slice> slices
= m_info->map_block(slot, offset, size, true); = files().map_block(slot, offset, size);
TORRENT_ASSERT(!slices.empty()); TORRENT_ASSERT(!slices.empty());
#endif #endif
size_type start = slot * (size_type)m_info->piece_length() + offset; size_type start = slot * (size_type)m_files.piece_length() + offset;
TORRENT_ASSERT(start + size <= m_info->total_size()); TORRENT_ASSERT(start + size <= m_files.total_size());
// find the file iterator and file offset // find the file iterator and file offset
size_type file_offset = start; size_type file_offset = start;
std::vector<file_entry>::const_iterator file_iter; 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) if (file_offset < file_iter->size)
break; break;
@ -864,7 +906,7 @@ namespace libtorrent
int buf_pos = 0; int buf_pos = 0;
std::string error; 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 this, m_save_path / file_iter->path, file::in
, error)); , error));
if (!in) if (!in)
@ -899,7 +941,7 @@ namespace libtorrent
#endif #endif
int left_to_read = size; 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) if (offset + left_to_read > slot_size)
left_to_read = slot_size - offset; left_to_read = slot_size - offset;
@ -924,7 +966,7 @@ namespace libtorrent
TORRENT_ASSERT(int(slices.size()) > counter); TORRENT_ASSERT(int(slices.size()) > counter);
size_type slice_size = slices[counter].size; size_type slice_size = slices[counter].size;
TORRENT_ASSERT(slice_size == read_bytes); 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); == file_iter->path);
#endif #endif
@ -961,7 +1003,7 @@ namespace libtorrent
file_offset = 0; file_offset = 0;
std::string error; std::string error;
in = m_files.open_file( in = m_pool.open_file(
this, path, file::in, error); this, path, file::in, error);
if (!in) if (!in)
{ {
@ -997,35 +1039,35 @@ namespace libtorrent
{ {
TORRENT_ASSERT(buf != 0); TORRENT_ASSERT(buf != 0);
TORRENT_ASSERT(slot >= 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(offset >= 0);
TORRENT_ASSERT(size > 0); TORRENT_ASSERT(size > 0);
#ifndef NDEBUG #ifndef NDEBUG
std::vector<file_slice> slices std::vector<file_slice> slices
= m_info->map_block(slot, offset, size, true); = files().map_block(slot, offset, size);
TORRENT_ASSERT(!slices.empty()); TORRENT_ASSERT(!slices.empty());
#endif #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 // find the file iterator and file offset
size_type file_offset = start; size_type file_offset = start;
std::vector<file_entry>::const_iterator file_iter; 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) if (file_offset < file_iter->size)
break; break;
file_offset -= file_iter->size; file_offset -= file_iter->size;
++file_iter; ++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); fs::path p(m_save_path / file_iter->path);
std::string error; 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); this, p, file::out | file::in, error);
if (!out) if (!out)
@ -1050,7 +1092,7 @@ namespace libtorrent
} }
int left_to_write = size; 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) if (offset + left_to_write > slot_size)
left_to_write = slot_size - offset; left_to_write = slot_size - offset;
@ -1074,7 +1116,7 @@ namespace libtorrent
{ {
TORRENT_ASSERT(int(slices.size()) > counter); TORRENT_ASSERT(int(slices.size()) > counter);
TORRENT_ASSERT(slices[counter].size == write_bytes); 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); == file_iter->path);
TORRENT_ASSERT(buf_pos >= 0); TORRENT_ASSERT(buf_pos >= 0);
@ -1101,11 +1143,11 @@ namespace libtorrent
#endif #endif
++file_iter; ++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; fs::path p = m_save_path / file_iter->path;
file_offset = 0; file_offset = 0;
std::string error; std::string error;
out = m_files.open_file( out = m_pool.open_file(
this, p, file::out | file::in, error); this, p, file::out | file::in, error);
if (!out) if (!out)
@ -1131,25 +1173,26 @@ namespace libtorrent
return size; 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) , 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::piece_manager( piece_manager::piece_manager(
boost::shared_ptr<void> const& torrent 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 , fs::path const& save_path
, file_pool& fp , file_pool& fp
, disk_io_thread& io , disk_io_thread& io
, storage_constructor_type sc , storage_constructor_type sc
, storage_mode_t sm) , 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_storage_mode(sm)
, m_info(ti)
, m_save_path(complete(save_path)) , m_save_path(complete(save_path))
, m_state(state_none) , m_state(state_none)
, m_current_slot(0) , m_current_slot(0)
@ -1213,6 +1256,17 @@ namespace libtorrent
m_io_thread.add_job(j, handler); 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( void piece_manager::async_check_files(
boost::function<void(int, disk_io_job const&)> const& handler) boost::function<void(int, disk_io_job const&)> const& handler)
{ {
@ -1241,6 +1295,8 @@ namespace libtorrent
m_io_thread.add_job(j, handler); m_io_thread.add_job(j, handler);
#ifndef NDEBUG #ifndef NDEBUG
boost::recursive_mutex::scoped_lock l(m_mutex); 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); TORRENT_ASSERT(slot_for(r.piece) >= 0);
#endif #endif
} }
@ -1295,7 +1351,7 @@ namespace libtorrent
int slot = slot_for(piece); int slot = slot_for(piece);
TORRENT_ASSERT(slot != has_no_slot); 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) bool piece_manager::move_storage_impl(fs::path const& save_path)
@ -1373,7 +1429,7 @@ namespace libtorrent
TORRENT_ASSERT(buf); TORRENT_ASSERT(buf);
TORRENT_ASSERT(offset >= 0); TORRENT_ASSERT(offset >= 0);
TORRENT_ASSERT(size > 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 slot = allocate_slot_for_piece(piece_index);
int ret = m_storage->write(buf, slot, offset, size); int ret = m_storage->write(buf, slot, offset, size);
@ -1455,9 +1511,9 @@ namespace libtorrent
{ {
// INVARIANT_CHECK; // INVARIANT_CHECK;
const int piece_size = static_cast<int>(m_info->piece_length()); const int piece_size = static_cast<int>(m_files.piece_length());
const int last_piece_size = static_cast<int>(m_info->piece_size( const int last_piece_size = static_cast<int>(m_files.piece_size(
m_info->num_pieces() - 1)); m_files.num_pieces() - 1));
TORRENT_ASSERT((int)piece_data.size() >= last_piece_size); TORRENT_ASSERT((int)piece_data.size() >= last_piece_size);
@ -1579,8 +1635,8 @@ namespace libtorrent
int piece_manager::check_no_fastresume(std::string& error) int piece_manager::check_no_fastresume(std::string& error)
{ {
torrent_info::file_iterator i = m_info->begin_files(true); file_storage::iterator i = m_files.begin();
torrent_info::file_iterator end = m_info->end_files(true); file_storage::iterator end = m_files.end();
for (; i != end; ++i) for (; i != end; ++i)
{ {
@ -1612,9 +1668,9 @@ namespace libtorrent
{ {
m_state = state_full_check; m_state = state_full_check;
m_piece_to_slot.clear(); 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.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) if (m_storage_mode == storage_mode_compact)
{ {
m_unallocated_slots.clear(); m_unallocated_slots.clear();
@ -1629,12 +1685,12 @@ namespace libtorrent
// in compact mode without checking, we need to // in compact mode without checking, we need to
// populate the unallocated list // populate the unallocated list
TORRENT_ASSERT(m_unallocated_slots.empty()); 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_unallocated_slots.push_back(i);
m_piece_to_slot.clear(); 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.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); return check_init_storage(error);
@ -1675,7 +1731,7 @@ namespace libtorrent
INVARIANT_CHECK; 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 we don't have any resume data, return
if (rd.type() == entry::undefined_t) return check_no_fastresume(error); if (rd.type() == entry::undefined_t) return check_no_fastresume(error);
@ -1686,38 +1742,11 @@ namespace libtorrent
return check_no_fastresume(error); return check_no_fastresume(error);
} }
entry const* file_format = rd.find_key("file-format"); int block_size = (std::min)(16 * 1024, m_files.piece_length());
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());
entry const* blocks_per_piece_ent = rd.find_key("blocks per piece"); entry const* blocks_per_piece_ent = rd.find_key("blocks per piece");
if (blocks_per_piece_ent != 0 if (blocks_per_piece_ent != 0
&& blocks_per_piece_ent->type() == entry::int_t && 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"; error = "invalid 'blocks per piece' entry";
return check_no_fastresume(error); return check_no_fastresume(error);
@ -1746,17 +1775,17 @@ namespace libtorrent
return check_no_fastresume(error); 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: " error = "file has more slots than torrent (slots: "
+ boost::lexical_cast<std::string>(slots->list().size()) + " size: " + 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); return check_no_fastresume(error);
} }
if (storage_mode == storage_mode_compact) 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_slot_to_piece.resize(num_pieces, unallocated);
m_piece_to_slot.resize(num_pieces, has_no_slot); m_piece_to_slot.resize(num_pieces, has_no_slot);
int slot = 0; int slot = 0;
@ -1877,7 +1906,7 @@ namespace libtorrent
// is finished // is finished
int piece_manager::check_files(int& current_slot, int& have_piece, std::string& error) 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; current_slot = m_current_slot;
have_piece = -1; have_piece = -1;
@ -1894,9 +1923,9 @@ namespace libtorrent
if (other_piece >= 0) if (other_piece >= 0)
{ {
if (m_scratch_buffer2.empty()) 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) if (m_storage->read(&m_scratch_buffer2[0], piece, 0, piece_size)
!= piece_size) != piece_size)
{ {
@ -1910,7 +1939,7 @@ namespace libtorrent
// the slot where this piece belongs is // the slot where this piece belongs is
// free. Just move the piece there. // 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) if (m_storage->write(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size)
{ {
error = m_storage->error(); error = m_storage->error();
@ -1926,19 +1955,19 @@ namespace libtorrent
return need_full_check; 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] == m_current_slot
|| m_slot_to_piece[m_current_slot] < 0)) || m_slot_to_piece[m_current_slot] < 0))
{ {
++m_current_slot; ++m_current_slot;
} }
if (m_current_slot == m_info->num_pieces()) if (m_current_slot == m_files.num_pieces())
{ {
return check_init_storage(error); 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]; int piece = m_slot_to_piece[m_current_slot];
TORRENT_ASSERT(piece >= 0); TORRENT_ASSERT(piece >= 0);
@ -1949,9 +1978,9 @@ namespace libtorrent
// where this one goes. Store it in the scratch // where this one goes. Store it in the scratch
// buffer until next iteration. // buffer until next iteration.
if (m_scratch_buffer.empty()) 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) if (m_storage->read(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size)
{ {
error = m_storage->error(); error = m_storage->error();
@ -1975,7 +2004,7 @@ namespace libtorrent
TORRENT_ASSERT(m_state == state_full_check); TORRENT_ASSERT(m_state == state_full_check);
bool skip = check_one_piece(have_piece); 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) if (skip)
{ {
@ -1984,9 +2013,9 @@ namespace libtorrent
// completely. We should skip all pieces belonging to that file. // completely. We should skip all pieces belonging to that file.
// find the file that failed, and skip all the pieces in that file // find the file that failed, and skip all the pieces in that file
size_type file_offset = 0; size_type file_offset = 0;
size_type current_offset = size_type(m_current_slot) * m_info->piece_length(); size_type current_offset = size_type(m_current_slot) * m_files.piece_length();
for (torrent_info::file_iterator i = m_info->begin_files(true); for (file_storage::iterator i = m_files.begin()
i != m_info->end_files(true); ++i) , end(m_files.end()); i != end; ++i)
{ {
file_offset += i->size; file_offset += i->size;
if (file_offset > current_offset) break; if (file_offset > current_offset) break;
@ -1994,8 +2023,8 @@ namespace libtorrent
TORRENT_ASSERT(file_offset > current_offset); TORRENT_ASSERT(file_offset > current_offset);
int skip_blocks = static_cast<int>( int skip_blocks = static_cast<int>(
(file_offset - current_offset + m_info->piece_length() - 1) (file_offset - current_offset + m_files.piece_length() - 1)
/ m_info->piece_length()); / m_files.piece_length());
if (m_storage_mode == storage_mode_compact) 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 // current slot will increase by one at the end of the for-loop too
m_current_slot += skip_blocks - 1; 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; ++m_current_slot;
current_slot = 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 // clear the memory we've been using
std::vector<char>().swap(m_piece_data); std::vector<char>().swap(m_piece_data);
@ -2059,19 +2088,19 @@ namespace libtorrent
// DO THE FULL CHECK // DO THE FULL CHECK
// ------------------------ // ------------------------
TORRENT_ASSERT(int(m_piece_to_slot.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_info->num_pieces()); TORRENT_ASSERT(int(m_slot_to_piece.size()) == m_files.num_pieces());
TORRENT_ASSERT(have_piece == -1); TORRENT_ASSERT(have_piece == -1);
// initialization for the full check // initialization for the full check
if (m_hash_to_piece.empty()) 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_hash_to_piece.insert(std::make_pair(m_info->hash_for_piece(i), i));
} }
m_piece_data.resize(int(m_info->piece_length())); m_piece_data.resize(int(m_files.piece_length()));
int piece_size = m_info->piece_size(m_current_slot); int piece_size = m_files.piece_size(m_current_slot);
int num_read = m_storage->read(&m_piece_data[0] int num_read = m_storage->read(&m_piece_data[0]
, m_current_slot, 0, piece_size); , m_current_slot, 0, piece_size);
@ -2348,7 +2377,7 @@ namespace libtorrent
// special case to make sure we don't use the last slot // special case to make sure we don't use the last slot
// when we shouldn't, since it's smaller than ordinary slots // 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) if (m_free_slots.size() == 1)
allocate_slots(1); allocate_slots(1);
@ -2481,14 +2510,14 @@ namespace libtorrent
{ {
boost::recursive_mutex::scoped_lock lock(m_mutex); 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() if (m_unallocated_slots.empty()
&& m_free_slots.empty() && m_free_slots.empty()
&& m_state == state_finished) && m_state == state_finished)
{ {
TORRENT_ASSERT(m_storage_mode != storage_mode_compact 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) if (m_storage_mode != storage_mode_compact)
@ -2508,8 +2537,8 @@ namespace libtorrent
{ {
if (m_piece_to_slot.empty()) return; if (m_piece_to_slot.empty()) return;
TORRENT_ASSERT((int)m_piece_to_slot.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_info->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(); for (std::vector<int>::const_iterator i = m_free_slots.begin();
i != m_free_slots.end(); ++i) i != m_free_slots.end(); ++i)
@ -2531,7 +2560,7 @@ namespace libtorrent
== m_unallocated_slots.end()); == 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 // Check domain of piece_to_slot's elements
if (m_piece_to_slot[i] != has_no_slot) if (m_piece_to_slot[i] != has_no_slot)
@ -2620,7 +2649,7 @@ namespace libtorrent
s << "index\tslot\tpiece\n"; 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 << i << "\t" << m_slot_to_piece[i] << "\t";
s << m_piece_to_slot[i] << "\n"; s << m_piece_to_slot[i] << "\n";

View file

@ -424,8 +424,34 @@ namespace libtorrent
m_state = torrent_status::queued_for_checking; 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 m_storage->async_check_fastresume(&m_resume_data
, bind(&torrent::on_resume_data_checked , bind(&torrent::on_resume_data_checked
, shared_from_this(), _1, _2)); , shared_from_this(), _1, _2));
@ -447,9 +473,9 @@ namespace libtorrent
" ]\n"; " ]\n";
#endif #endif
} }
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false); m_have_pieces.clear_all();
m_num_pieces = 0; m_num_pieces = 0;
auto_managed(false); m_error = j.str;
pause(); pause();
return; return;
} }
@ -523,7 +549,7 @@ namespace libtorrent
// or the resume_data was accepted // or the resume_data was accepted
m_num_pieces = 0; m_num_pieces = 0;
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false); m_have_pieces.clear_all();
if (!fastresume_rejected) if (!fastresume_rejected)
{ {
TORRENT_ASSERT(m_resume_data.type() == entry::dictionary_t); TORRENT_ASSERT(m_resume_data.type() == entry::dictionary_t);
@ -531,14 +557,14 @@ namespace libtorrent
// parse have bitmask // parse have bitmask
entry const* pieces = m_resume_data.find_key("pieces"); entry const* pieces = m_resume_data.find_key("pieces");
if (pieces && pieces->type() == entry::string_t 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(); std::string const& pieces_str = pieces->string();
for (int i = 0, end(pieces_str.size()); i < end; ++i) for (int i = 0, end(pieces_str.size()); i < end; ++i)
{ {
bool have = pieces_str[i] & 1; if ((pieces_str[i] & 1) == 0) continue;
m_have_pieces[i] = have; m_have_pieces.set_bit(i);
m_num_pieces += have; ++m_num_pieces;
} }
} }
@ -563,7 +589,7 @@ namespace libtorrent
if (m_have_pieces[piece_index]) if (m_have_pieces[piece_index])
{ {
m_have_pieces[piece_index] = false; m_have_pieces.clear_bit(piece_index);
--m_num_pieces; --m_num_pieces;
} }
@ -593,7 +619,7 @@ namespace libtorrent
} }
int index = 0; 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) , end(m_have_pieces.end()); i != end; ++i, ++index)
{ {
if (*i) m_picker->we_have(index); if (*i) m_picker->we_have(index);
@ -635,9 +661,9 @@ namespace libtorrent
" ]\n"; " ]\n";
#endif #endif
} }
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false); m_have_pieces.clear_all();
m_num_pieces = 0; m_num_pieces = 0;
auto_managed(false); m_error = j.str;
pause(); pause();
m_ses.done_checking(shared_from_this()); m_ses.done_checking(shared_from_this());
return; return;
@ -647,7 +673,7 @@ namespace libtorrent
if (j.offset >= 0 && !m_have_pieces[j.offset]) 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; ++m_num_pieces;
TORRENT_ASSERT(m_picker); TORRENT_ASSERT(m_picker);
m_picker->we_have(j.offset); m_picker->we_have(j.offset);
@ -1169,7 +1195,6 @@ namespace libtorrent
?"disk failed":"failed") << " ]\n"; ?"disk failed":"failed") << " ]\n";
#endif #endif
bool was_seed = is_seed();
bool was_finished = m_picker->num_filtered() + num_pieces() bool was_finished = m_picker->num_filtered() + num_pieces()
== torrent_file().num_pieces(); == torrent_file().num_pieces();
@ -1186,17 +1211,6 @@ namespace libtorrent
TORRENT_ASSERT(valid_metadata()); TORRENT_ASSERT(valid_metadata());
// if we just became a seed, picker is now invalid, since it // if we just became a seed, picker is now invalid, since it
// is deallocated by the torrent once it starts seeding // 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) else if (passed_hash_check == -2)
{ {
@ -1210,10 +1224,17 @@ namespace libtorrent
m_policy.piece_finished(index, passed_hash_check == 0); 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); 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) void torrent::on_torrent_paused(int ret, disk_io_job const& j)
{ {
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
@ -1452,7 +1488,7 @@ namespace libtorrent
if (!m_have_pieces[index]) if (!m_have_pieces[index])
m_num_pieces++; 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) TORRENT_ASSERT(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0)
== m_num_pieces); == m_num_pieces);
@ -1486,11 +1522,6 @@ namespace libtorrent
#endif #endif
} }
#endif #endif
if (is_seed())
{
m_state = torrent_status::seeding;
m_picker.reset();
}
} }
std::string torrent::tracker_login() const std::string torrent::tracker_login() const
@ -1619,7 +1650,7 @@ namespace libtorrent
for (int i = 0; i < int(files.size()); ++i) for (int i = 0; i < int(files.size()); ++i)
{ {
size_type start = position; 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; if (size == 0) continue;
position += size; position += size;
// mark all pieces of the file with this file's priority // 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) for (int i = 0; i < (int)bitmask.size(); ++i)
{ {
size_type start = position; 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? // is the file selected for download?
if (!bitmask[i]) if (!bitmask[i])
{ {
@ -1872,9 +1903,8 @@ namespace libtorrent
{ {
if (m_picker.get()) if (m_picker.get())
{ {
const std::vector<bool>& pieces = p->get_bitfield(); bitfield const& pieces = p->get_bitfield();
TORRENT_ASSERT(std::count(pieces.begin(), pieces.end(), true) TORRENT_ASSERT(pieces.count() < int(pieces.size()));
< int(pieces.size()));
m_picker->dec_refcount(pieces); m_picker->dec_refcount(pieces);
} }
} }
@ -2956,6 +2986,12 @@ namespace libtorrent
} }
m_state = torrent_status::finished; 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 // disconnect all seeds
// TODO: should disconnect all peers that have the pieces we have // TODO: should disconnect all peers that have the pieces we have
@ -2990,6 +3026,7 @@ namespace libtorrent
INVARIANT_CHECK; INVARIANT_CHECK;
m_state = torrent_status::downloading; m_state = torrent_status::downloading;
set_queue_position((std::numeric_limits<int>::max)());
} }
// called when torrent is complete (all pieces downloaded) // called when torrent is complete (all pieces downloaded)
@ -2997,6 +3034,8 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
m_picker.reset();
// make the next tracker request // make the next tracker request
// be a completed-event // be a completed-event
m_event = tracker_request::completed; m_event = tracker_request::completed;
@ -3095,11 +3134,7 @@ namespace libtorrent
} }
#endif #endif
if (is_seed()) if (is_seed()) finished();
{
m_state = torrent_status::seeding;
m_picker.reset();
}
if (!m_connections_initialized) if (!m_connections_initialized)
{ {
@ -3149,6 +3184,20 @@ namespace libtorrent
return m_save_path; 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) void torrent::move_storage(fs::path const& save_path)
{ {
INVARIANT_CHECK; 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) void torrent::set_max_uploads(int limit)
{ {
@ -3564,6 +3662,7 @@ namespace libtorrent
m_paused = false; m_paused = false;
m_started = time_now(); m_started = time_now();
m_error.clear();
// tell the tracker that we're back // tell the tracker that we're back
m_event = tracker_request::started; m_event = tracker_request::started;
@ -3750,6 +3849,7 @@ namespace libtorrent
{ {
alerts().post_alert(file_error_alert(j.error_file, get_handle(), j.str)); alerts().post_alert(file_error_alert(j.error_file, get_handle(), j.str));
} }
m_error = j.str;
pause(); pause();
} }
f(ret); f(ret);
@ -3769,8 +3869,8 @@ namespace libtorrent
for (int i = 0; i < m_torrent_file->num_files(); ++i) for (int i = 0; i < m_torrent_file->num_files(); ++i)
{ {
peer_request ret = m_torrent_file->map_file(i, 0, 0); peer_request ret = m_torrent_file->files().map_file(i, 0, 0);
size_type size = m_torrent_file->file_at(i).size; size_type size = m_torrent_file->files().at(i).size;
// zero sized files are considered // zero sized files are considered
// 100% done all the time // 100% done all the time
@ -3792,7 +3892,7 @@ namespace libtorrent
} }
TORRENT_ASSERT(size == 0); 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; torrent_status st;
st.error = m_error;
if (m_last_scrape == min_time()) if (m_last_scrape == min_time())
{ {
st.last_scrape = -1; st.last_scrape = -1;
@ -3902,20 +4004,22 @@ namespace libtorrent
st.total_wanted = m_torrent_file->total_size(); st.total_wanted = m_torrent_file->total_size();
TORRENT_ASSERT(st.total_wanted >= 0); 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 if (m_picker.get() && (m_picker->num_filtered() > 0
|| m_picker->num_have_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(); + m_picker->num_have_filtered();
int last_piece_index = m_torrent_file->num_pieces() - 1; int last_piece_index = m_torrent_file->num_pieces() - 1;
if (m_picker->piece_priority(last_piece_index) == 0) if (m_picker->piece_priority(last_piece_index) == 0)
{ {
st.total_wanted -= m_torrent_file->piece_size(last_piece_index); 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); TORRENT_ASSERT(st.total_wanted >= st.total_wanted_done);

View file

@ -215,6 +215,12 @@ namespace libtorrent
TORRENT_FORWARD(move_storage(save_path)); 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( void torrent_handle::add_extension(
boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext
, void* userdata) , void* userdata)
@ -277,6 +283,36 @@ namespace libtorrent
TORRENT_FORWARD(auto_managed(m)); 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 void torrent_handle::set_tracker_login(std::string const& name
, std::string const& password) const , 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. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -153,11 +153,7 @@ namespace
// save the original encoding and replace the // save the original encoding and replace the
// commonly used path with the correctly // commonly used path with the correctly
// encoded string // encoded string
if (!valid_encoding) if (!valid_encoding) target.path = tmp_path;
{
target.orig_path.reset(new fs::path(target.path));
target.path = tmp_path;
}
} }
bool extract_single_file(lazy_entry const& dict, file_entry& target bool extract_single_file(lazy_entry const& dict, file_entry& target
@ -194,40 +190,26 @@ namespace
return true; 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) , std::string const& root_dir)
{ {
size_type offset = 0;
if (list.type() != lazy_entry::list_t) return false; if (list.type() != lazy_entry::list_t) return false;
for (int i = 0, end(list.list_size()); i < end; ++i) for (int i = 0, end(list.list_size()); i < end; ++i)
{ {
target.push_back(file_entry()); file_entry e;
if (!extract_single_file(*list.list_at(i), target.back(), root_dir)) if (!extract_single_file(*list.list_at(i), e, root_dir))
return false; return false;
target.back().offset = offset; target.add_file(e);
offset += target.back().size;
} }
return true; 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 namespace libtorrent
{ {
// standard constructor that parses a torrent file // standard constructor that parses a torrent file
torrent_info::torrent_info(entry const& 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_multifile(false)
, m_private(false) , m_private(false)
, m_info_section_size(0) , m_info_section_size(0)
@ -249,8 +231,7 @@ namespace libtorrent
} }
torrent_info::torrent_info(lazy_entry const& torrent_file) 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_multifile(false)
, m_private(false) , m_private(false)
, m_info_section_size(0) , m_info_section_size(0)
@ -266,8 +247,7 @@ namespace libtorrent
} }
torrent_info::torrent_info(char const* buffer, int size) 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_multifile(false)
, m_private(false) , m_private(false)
, m_info_section_size(0) , m_info_section_size(0)
@ -289,36 +269,16 @@ namespace libtorrent
// just the necessary to use it with piece manager // just the necessary to use it with piece manager
// used for torrents with no metadata // used for torrents with no metadata
torrent_info::torrent_info(sha1_hash const& info_hash) torrent_info::torrent_info(sha1_hash const& info_hash)
: m_piece_length(0) : m_info_hash(info_hash)
, m_total_size(0)
, m_num_pieces(0)
, m_info_hash(info_hash)
, m_name()
, m_creation_date(pt::second_clock::universal_time()) , m_creation_date(pt::second_clock::universal_time())
, m_multifile(false) , m_multifile(false)
, m_private(false) , m_private(false)
, m_info_section_size(0) , m_info_section_size(0)
, m_piece_hashes(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) 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_multifile(false)
, m_private(false) , m_private(false)
{ {
@ -349,11 +309,8 @@ namespace libtorrent
m_urls.swap(ti.m_urls); m_urls.swap(ti.m_urls);
m_url_seeds.swap(ti.m_url_seeds); m_url_seeds.swap(ti.m_url_seeds);
m_files.swap(ti.m_files); m_files.swap(ti.m_files);
m_files.swap(ti.m_remapped_files);
m_nodes.swap(ti.m_nodes); m_nodes.swap(ti.m_nodes);
swap(m_num_pieces, ti.m_num_pieces);
swap(m_info_hash, ti.m_info_hash); swap(m_info_hash, ti.m_info_hash);
m_name.swap(ti.m_name);
swap(m_creation_date, ti.m_creation_date); swap(m_creation_date, ti.m_creation_date);
m_comment.swap(ti.m_comment); m_comment.swap(ti.m_comment);
m_created_by.swap(ti.m_created_by); m_created_by.swap(ti.m_created_by);
@ -387,27 +344,27 @@ namespace libtorrent
TORRENT_ASSERT(section.first[m_info_section_size-1] == 'e'); TORRENT_ASSERT(section.first[m_info_section_size-1] == 'e');
// extract piece length // extract piece length
m_piece_length = info.dict_find_int_value("piece length", -1); int piece_length = info.dict_find_int_value("piece length", -1);
if (m_piece_length <= 0) if (piece_length <= 0)
{ {
error = "invalid or missing 'piece length' entry in torrent file"; error = "invalid or missing 'piece length' entry in torrent file";
return false; return false;
} }
m_files.set_piece_length(piece_length);
// extract file name (or the directory name if it's a multifile libtorrent) // extract file name (or the directory name if it's a multifile libtorrent)
m_name = info.dict_find_string_value("name.utf-8"); std::string name = info.dict_find_string_value("name.utf-8");
if (m_name.empty()) m_name = info.dict_find_string_value("name"); if (name.empty()) name = info.dict_find_string_value("name");
if (name.empty())
if (m_name.empty())
{ {
error = "invalid name in torrent file"; error = "missing name in torrent file";
return false; return false;
} }
fs::path tmp = m_name; fs::path tmp = name;
if (tmp.is_complete()) if (tmp.is_complete())
{ {
m_name = tmp.leaf(); name = tmp.leaf();
} }
else if (tmp.has_branch_path()) else if (tmp.has_branch_path())
{ {
@ -418,9 +375,9 @@ namespace libtorrent
if (*i == "." || *i == "..") continue; if (*i == "." || *i == "..") continue;
p /= *i; 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)"; error = "invalid 'name' of torrent (possible exploit attempt)";
return false; return false;
@ -433,7 +390,7 @@ namespace libtorrent
// if there's no list of files, there has to be a length // if there's no list of files, there has to be a length
// field. // field.
file_entry e; file_entry e;
e.path = m_name; e.path = name;
e.offset = 0; e.offset = 0;
e.size = info.dict_find_int_value("length", -1); e.size = info.dict_find_int_value("length", -1);
if (e.size < 0) if (e.size < 0)
@ -441,29 +398,26 @@ namespace libtorrent
error = "invalid length of torrent"; error = "invalid length of torrent";
return false; return false;
} }
m_files.push_back(e); m_files.add_file(e);
m_multifile = false; m_multifile = false;
} }
else else
{ {
if (!extract_files(*i, m_files, m_name)) if (!extract_files(*i, m_files, name))
{ {
error = "failed to parse files from torrent file"; error = "failed to parse files from torrent file";
return false; return false;
} }
m_multifile = true; m_multifile = true;
} }
m_files.set_name(name);
// 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;
// extract sha-1 hashes for all pieces // extract sha-1 hashes for all pieces
// we want this division to round upwards, that's why we have the // we want this division to round upwards, that's why we have the
// extra addition // 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"); lazy_entry const* pieces = info.dict_find("pieces");
if (pieces == 0 || pieces->type() != lazy_entry::string_t) if (pieces == 0 || pieces->type() != lazy_entry::string_t)
@ -472,7 +426,7 @@ namespace libtorrent
return false; 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"; error = "incorrect number of piece hashes in torrent file";
return false; return false;
@ -630,122 +584,11 @@ namespace libtorrent
os << "number of pieces: " << num_pieces() << "\n"; os << "number of pieces: " << num_pieces() << "\n";
os << "piece length: " << piece_length() << "\n"; os << "piece length: " << piece_length() << "\n";
os << "files:\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"; os << " " << std::setw(11) << i->size << " " << i->path.string() << "\n";
} }
// ------- end deprecation ------- // ------- 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); TORRENT_ASSERT(t);
// this is always a seed // this is always a seed
incoming_bitfield(std::vector<bool>( incoming_have_all();
t->torrent_file().num_pieces(), true));
// it is always possible to request pieces // it is always possible to request pieces
incoming_unchoke(); incoming_unchoke();
@ -229,7 +229,7 @@ namespace libtorrent
request += "\r\nProxy-Connection: keep-alive"; request += "\r\nProxy-Connection: keep-alive";
} }
request += "\r\nRange: bytes="; 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); * info.piece_length() + r.start);
request += "-"; request += "-";
request += boost::lexical_cast<std::string>(r.piece request += boost::lexical_cast<std::string>(r.piece
@ -242,7 +242,7 @@ namespace libtorrent
} }
else 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); , r.length);
for (std::vector<file_slice>::iterator i = files.begin(); for (std::vector<file_slice>::iterator i = files.begin();
@ -254,13 +254,13 @@ namespace libtorrent
if (using_proxy) if (using_proxy)
{ {
request += m_url; 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()); request += escape_path(path.c_str(), path.length());
} }
else else
{ {
std::string path = m_path; 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 += escape_path(path.c_str(), path.length());
} }
request += " HTTP/1.1\r\n"; request += " HTTP/1.1\r\n";
@ -426,7 +426,7 @@ namespace libtorrent
int file_index = m_file_requests.front(); int file_index = m_file_requests.front();
torrent_info const& info = t->torrent_file(); 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()); path = escape_path(path.c_str(), path.length());
size_t i = location.rfind(path); size_t i = location.rfind(path);
if (i == std::string::npos) if (i == std::string::npos)
@ -511,7 +511,7 @@ namespace libtorrent
} }
int file_index = m_file_requests.front(); 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)); , int(range_end - range_start));
peer_request front_request = m_requests.front(); peer_request front_request = m_requests.front();