forked from premiere/premiere-libtorrent
separated file_storage from torrent_info and create_torrent
This commit is contained in:
parent
cf37d8544d
commit
3910fe78de
1
Jamfile
1
Jamfile
|
@ -262,6 +262,7 @@ SOURCES =
|
|||
create_torrent
|
||||
disk_buffer_holder
|
||||
entry
|
||||
file_storage
|
||||
lazy_bdecode
|
||||
escape_string
|
||||
gzip
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
=================
|
||||
creating torrents
|
||||
=================
|
||||
|
||||
:Author: Arvid Norberg, arvid@rasterbar.com
|
||||
|
||||
.. contents:: Table of contents
|
||||
:depth: 2
|
||||
:backlinks: none
|
||||
|
||||
overview
|
||||
========
|
||||
|
||||
This section describes the functions and classes that are used
|
||||
to create torrent files. It is a layered API with low level classes
|
||||
and higher level convenience functions. A torrent is created in 4
|
||||
steps:
|
||||
|
||||
1. first the files that will be part of the torrent are determined.
|
||||
2. the torrent properties are set, such as tracker url, web seeds,
|
||||
DHT nodes etc.
|
||||
3. Read through all the files in the torrent, SHA-1 all the data
|
||||
and set the piece hashes.
|
||||
4. The torrent is bencoded into a file or buffer.
|
||||
|
||||
If there are a lot of files and or deep directoy hierarchies to
|
||||
traverse, step one can be time consuming.
|
||||
|
||||
Typically step 3 is by far the most time consuming step, since it
|
||||
requires to read all the bytes from all the files in the torrent.
|
||||
|
||||
All of these classes and functions are declared by including
|
||||
``libtorrent/create_torrent.hpp``.
|
||||
|
||||
high level example
|
||||
==================
|
||||
|
||||
::
|
||||
|
||||
file_storage fs;
|
||||
|
||||
// recursively adds files in directories
|
||||
add_files(fs, "./my_torrent");
|
||||
|
||||
create_torrent t(fs);
|
||||
t.add_tracker("http://my.tracker.com/announce");
|
||||
t.set_creator("libtorrent example");
|
||||
|
||||
// reads the files and calculates the hashes
|
||||
set_piece_hashes(t, ".");
|
||||
|
||||
ofstream out("my_torrent.torrent", std::ios_base::binary);
|
||||
bencode(std::ostream_iterator<char>(out), t.generate());
|
||||
|
||||
add_files
|
||||
=========
|
||||
|
||||
::
|
||||
|
||||
template <class Pred>
|
||||
void add_files(file_storage& fs, boost::filesystem::path const& path, Pred p);
|
||||
|
||||
void add_files(file_storage& fs, boost::filesystem::path const& path);
|
||||
|
||||
Adds the file specified by ``path`` to the ``file_storage`` object. In case ``path``
|
||||
refers to a diretory, files will be added recursively from the directory.
|
||||
|
||||
If specified, the predicate ``p`` is called once for every file and directory that
|
||||
is encountered. files for which ``p`` returns true are added, and directories for
|
||||
which ``p`` returns true are traversed. ``p`` must have the following signature::
|
||||
|
||||
bool Pred(boost::filesystem::path const& p);
|
||||
|
||||
The path that is passed in to the predicate is the full path of the file or
|
||||
directory. If no predicate is specified, all files are added, and all directories
|
||||
are traveresed.
|
||||
|
||||
The ".." directory is never traversed.
|
||||
|
||||
set_piece_hashes()
|
||||
==================
|
||||
|
||||
::
|
||||
|
||||
template <class Fun>
|
||||
void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p, Fun f);
|
||||
|
||||
void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p);
|
||||
|
||||
This function will assume that the files added to the torrent file exists at path
|
||||
``p``, read those files and hash the content and set the hashes in the ``create_torrent``
|
||||
object. The optional function ``f`` is called in between every hash that is set. ``f``
|
||||
must have the following signature::
|
||||
|
||||
void Fun(int);
|
||||
|
||||
file_storage
|
||||
============
|
||||
|
||||
The ``file_storage`` class represents a file list and the piece
|
||||
size. Everything necessary to interpret a regular bittorrent storage
|
||||
file structure. Its synopsis::
|
||||
|
||||
class file_storage
|
||||
{
|
||||
public:
|
||||
|
||||
bool is_valid() const;
|
||||
|
||||
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;
|
||||
iterator end() const;
|
||||
reverse_iterator rbegin();
|
||||
reverse_iterator rend() const;
|
||||
int num_files() const;
|
||||
|
||||
file_entry const& at(int index) const;
|
||||
|
||||
size_type total_size() const;
|
||||
void set_num_pieces(int n);
|
||||
int num_pieces() const;
|
||||
void set_piece_length(int l);
|
||||
int piece_length() const;
|
||||
int piece_size(int index) const;
|
||||
|
||||
void set_name(std::string const& n);
|
||||
const std::string& name() const;
|
||||
|
||||
void swap(file_storage& ti);
|
||||
}
|
||||
|
||||
|
||||
create_torrent
|
||||
==============
|
||||
|
||||
The ``create_torrent`` class has the following synopsis::
|
||||
|
||||
|
||||
struct create_torrent
|
||||
{
|
||||
create_torrent(file_storage& fs, int piece_size);
|
||||
create_torrent(file_storage& fs);
|
||||
|
||||
entry generate() const;
|
||||
|
||||
file_storage const& files() const;
|
||||
|
||||
void set_comment(char const* str);
|
||||
void set_creator(char const* str);
|
||||
void set_hash(int index, sha1_hash const& h);
|
||||
void add_url_seed(std::string const& url);
|
||||
void add_node(std::pair<std::string, int> const& node);
|
||||
void add_tracker(std::string const& url, int tier = 0);
|
||||
|
||||
int num_pieces() const;
|
||||
int piece_length() const;
|
||||
int piece_size(int i) const;
|
||||
};
|
||||
|
||||
create_torrent()
|
||||
----------------
|
||||
|
||||
::
|
||||
|
||||
create_torrent(file_storage& fs, int piece_size);
|
||||
create_torrent(file_storage& fs);
|
||||
|
||||
The contrstructor that does not take a piece_size will calculate
|
||||
a piece size such that the torrent file is roughly 40 kB.
|
||||
|
||||
generate()
|
||||
----------
|
||||
|
||||
::
|
||||
|
||||
entry generate() const;
|
||||
|
||||
This function will generate the .torrent file as a bencode tree. In order to
|
||||
generate the flat file, use the bencode() function.
|
||||
|
||||
It may be useful to add custom entries to the torrent file before bencoding it
|
||||
and saving it to disk.
|
||||
|
||||
|
1309
docs/manual.html
1309
docs/manual.html
File diff suppressed because it is too large
Load Diff
107
docs/manual.rst
107
docs/manual.rst
|
@ -33,6 +33,10 @@ The basic usage is as follows:
|
|||
|
||||
Each class and function is described in this manual.
|
||||
|
||||
For a description on how to create torrent files, see make_torrent_.
|
||||
|
||||
.. _make_torrent: make_torrent.html
|
||||
|
||||
network primitives
|
||||
==================
|
||||
|
||||
|
@ -221,8 +225,7 @@ add_torrent()
|
|||
::
|
||||
|
||||
typedef storage_interface* (&storage_constructor_type)(
|
||||
boost::intrusive_ptr<torrent_info const>, fs::path const&
|
||||
, file_pool&);
|
||||
file_storage const&, fs::path const&, file_pool&);
|
||||
|
||||
struct add_torrent_params
|
||||
{
|
||||
|
@ -1090,6 +1093,10 @@ key is found, the return a pointer to it.
|
|||
torrent_info
|
||||
============
|
||||
|
||||
In previous versions of libtorrent, this class was also used for creating
|
||||
torrent files. This functionality has been moved to ``create_torrent``, see
|
||||
make_torrent_.
|
||||
|
||||
The ``torrent_info`` has the following synopsis::
|
||||
|
||||
class torrent_info
|
||||
|
@ -1102,27 +1109,25 @@ The ``torrent_info`` has the following synopsis::
|
|||
torrent_info(char const* filename);
|
||||
|
||||
void add_tracker(std::string const& url, int tier = 0);
|
||||
std::vector<announce_entry> const& trackers() const;
|
||||
|
||||
typedef std::vector<file_entry>::const_iterator file_iterator;
|
||||
typedef std::vector<file_entry>::const_reverse_iterator
|
||||
reverse_file_iterator;
|
||||
file_storage const& files() const;
|
||||
|
||||
bool remap_files(std::vector<file_entry> const& map);
|
||||
typedef file_storage::iterator file_iterator;
|
||||
typedef file_storage::reverse_iterator reverse_file_iterator;
|
||||
|
||||
file_iterator begin_files(bool storage = false) const;
|
||||
file_iterator end_files(bool storage = false) const;
|
||||
reverse_file_iterator rbegin_files(bool storage = false) const;
|
||||
reverse_file_iterator rend_files(bool storage = false) const;
|
||||
file_iterator begin_files() const;
|
||||
file_iterator end_files() const;
|
||||
reverse_file_iterator rbegin_files() const;
|
||||
reverse_file_iterator rend_files() const;
|
||||
|
||||
int num_files(bool storage = false) const;
|
||||
file_entry const& file_at(int index, bool storage = false) const;
|
||||
int num_files() const;
|
||||
file_entry const& file_at(int index) const;
|
||||
|
||||
std::vector<file_slice> map_block(int piece, size_type offset
|
||||
, int size, bool storage = false) const;
|
||||
, int size) const;
|
||||
peer_request map_file(int file_index, size_type file_offset
|
||||
, int size, bool storage = false) const;
|
||||
|
||||
std::vector<announce_entry> const& trackers() const;
|
||||
, int size) const;
|
||||
|
||||
bool priv() const;
|
||||
|
||||
|
@ -1188,52 +1193,37 @@ add_tracker()
|
|||
``add_tracker()`` adds a tracker to the announce-list. The ``tier`` determines the order in
|
||||
which the trackers are to be tried. For more information see `trackers()`_.
|
||||
|
||||
|
||||
remap_files()
|
||||
-------------
|
||||
files()
|
||||
-------
|
||||
|
||||
::
|
||||
|
||||
bool remap_files(std::vector<file_entry> const& map);
|
||||
file_storage const& file() const;
|
||||
|
||||
This call will create a new mapping of the data in this torrent to other files. The
|
||||
``torrent_info`` maintains 2 views of the file storage. One that is true to the torrent
|
||||
file, and one that represents what is actually saved on disk. This call will change
|
||||
what the files on disk are called.
|
||||
|
||||
The each entry in the vector ``map`` is a ``file_entry``. The only fields in this struct
|
||||
that are used in this case are ``path``, ``size`` and ``file_base``.
|
||||
|
||||
The return value indicates if the remap was successful or not. True means success and
|
||||
false means failure. The sum of all the files passed in through ``map`` has to be exactly
|
||||
the same as the total_size of the torrent. If the number of bytes that are mapped do not
|
||||
match, false will be returned (this is the only case this function may fail).
|
||||
|
||||
Changing this mapping for an existing torrent will not move or rename files. If some files
|
||||
should be renamed, this can be done before the torrent is added.
|
||||
The ``file_storage`` object contains the information on how to map the pieces to
|
||||
files. It is separated from the ``torrent_info`` object because when creating torrents
|
||||
a storage object needs to be created without having a torrent file. When renaming files
|
||||
in a storage, the storage needs to make its own copy of the ``file_storage`` in order
|
||||
to make its mapping differ from the one in the torrent file.
|
||||
|
||||
For more information on the ``file_storage`` object, see the separate document on how
|
||||
to create torrents.
|
||||
|
||||
begin_files() end_files() rbegin_files() rend_files()
|
||||
-----------------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
file_iterator begin_files(bool storage = false) const;
|
||||
file_iterator end_files(bool storage = false) const;
|
||||
reverse_file_iterator rbegin_files(bool storage = false) const;
|
||||
reverse_file_iterator rend_files(bool storage = false) const;
|
||||
file_iterator begin_files() const;
|
||||
file_iterator end_files() const;
|
||||
reverse_file_iterator rbegin_files() const;
|
||||
reverse_file_iterator rend_files() const;
|
||||
|
||||
This class will need some explanation. First of all, to get a list of all files
|
||||
in the torrent, you can use ``begin_files()``, ``end_files()``,
|
||||
``rbegin_files()`` and ``rend_files()``. These will give you standard vector
|
||||
iterators with the type ``file_entry``.
|
||||
|
||||
The ``storage`` parameter specifies which view of the files you want. The default
|
||||
is false, which means you will see the content of the torrent file. If set to
|
||||
true, you will see the file that the storage class uses to save the files to
|
||||
disk. Typically these views are the same, but in case the files have been
|
||||
remapped, they may differ. For more info, see `remap_files()`_.
|
||||
|
||||
::
|
||||
|
||||
struct file_entry
|
||||
|
@ -1274,27 +1264,20 @@ num_files() file_at()
|
|||
|
||||
::
|
||||
|
||||
int num_files(bool storage = false) const;
|
||||
file_entry const& file_at(int index, bool storage = false) const;
|
||||
int num_files() const;
|
||||
file_entry const& file_at(int index) const;
|
||||
|
||||
If you need index-access to files you can use the ``num_files()`` and ``file_at()``
|
||||
to access files using indices.
|
||||
|
||||
|
||||
The ``storage`` parameter specifies which view of the files you want. The default
|
||||
is false, which means you will see the content of the torrent file. If set to
|
||||
true, you will see the file that the storage class uses to save the files to
|
||||
disk. Typically these views are the same, but in case the files have been
|
||||
remapped, they may differ. For more info, see `remap_files()`_.
|
||||
|
||||
|
||||
map_block()
|
||||
-----------
|
||||
|
||||
::
|
||||
|
||||
std::vector<file_slice> map_block(int piece, size_type offset
|
||||
, int size, bool storage = false) const;
|
||||
, int size) const;
|
||||
|
||||
This function will map a piece index, a byte offset within that piece and
|
||||
a size (in bytes) into the corresponding files with offsets where that data
|
||||
|
@ -1316,12 +1299,6 @@ as argument. The ``offset`` is the byte offset in the file where the range
|
|||
starts, and ``size`` is the number of bytes this range is. The size + offset
|
||||
will never be greater than the file size.
|
||||
|
||||
The ``storage`` parameter specifies which view of the files you want. The default
|
||||
is false, which means you will see the content of the torrent file. If set to
|
||||
true, you will see the file that the storage class uses to save the files to
|
||||
disk. Typically these views are the same, but in case the files have been
|
||||
remapped, they may differ. For more info, see `remap_files()`_.
|
||||
|
||||
|
||||
map_file()
|
||||
----------
|
||||
|
@ -1329,7 +1306,7 @@ map_file()
|
|||
::
|
||||
|
||||
peer_request map_file(int file_index, size_type file_offset
|
||||
, int size, bool storage = false) const;
|
||||
, int size) const;
|
||||
|
||||
This function will map a range in a specific file into a range in the torrent.
|
||||
The ``file_offset`` parameter is the offset in the file, given in bytes, where
|
||||
|
@ -1366,12 +1343,6 @@ vector of those urls. If you're creating a torrent file, ``add_url_seed()``
|
|||
adds one url to the list of url-seeds. Currently, the only transport protocol
|
||||
supported for the url is http.
|
||||
|
||||
The ``storage`` parameter specifies which view of the files you want. The default
|
||||
is false, which means you will see the content of the torrent file. If set to
|
||||
true, you will see the file that the storage class uses to save the files to
|
||||
disk. Typically these views are the same, but in case the files have been
|
||||
remapped, they may differ. For more info, see `remap_files()`_.
|
||||
|
||||
See `HTTP seeding`_ for more information.
|
||||
|
||||
|
||||
|
|
|
@ -41,38 +41,38 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/file.hpp"
|
||||
#include "libtorrent/storage.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/file_pool.hpp"
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
using namespace boost::filesystem;
|
||||
using namespace libtorrent;
|
||||
|
||||
void add_files(create_torrent& t, path const& p, path const& l)
|
||||
// do not include files and folders whose
|
||||
// name starts with a .
|
||||
bool file_filter(boost::filesystem::path const& filename)
|
||||
{
|
||||
if (l.leaf()[0] == '.') return;
|
||||
path f(p / l);
|
||||
if (is_directory(f))
|
||||
{
|
||||
for (directory_iterator i(f), end; i != end; ++i)
|
||||
add_files(t, p, l / i->leaf());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "adding \"" << l.string() << "\"\n";
|
||||
t.add_file(l, file_size(f));
|
||||
}
|
||||
if (filename.leaf()[0] == '.') return false;
|
||||
std::cerr << filename << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
void print_progress(int i, int num)
|
||||
{
|
||||
std::cerr << "\r" << (i+1) << "/" << num;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
using namespace libtorrent;
|
||||
using namespace boost::filesystem;
|
||||
|
||||
int piece_size = 256 * 1024;
|
||||
char const* creator_str = "libtorrent";
|
||||
|
||||
path::default_name_check(no_check);
|
||||
|
||||
if (argc != 4 && argc != 5)
|
||||
|
@ -87,40 +87,20 @@ int main(int argc, char* argv[])
|
|||
try
|
||||
{
|
||||
#endif
|
||||
create_torrent t;
|
||||
file_storage fs;
|
||||
file_pool fp;
|
||||
path full_path = complete(path(argv[3]));
|
||||
|
||||
int piece_size = 256 * 1024;
|
||||
char const* creator_str = "libtorrent";
|
||||
add_files(fs, full_path, file_filter);
|
||||
|
||||
add_files(t, full_path.branch_path(), full_path.leaf());
|
||||
t.set_piece_size(piece_size);
|
||||
create_torrent t(fs, piece_size);
|
||||
t.add_tracker(argv[2]);
|
||||
|
||||
std::vector<char> tmp;
|
||||
bencode(std::back_inserter(tmp), t.generate());
|
||||
boost::intrusive_ptr<torrent_info> info(new torrent_info(&tmp[0], tmp.size()));
|
||||
|
||||
file_pool fp;
|
||||
boost::scoped_ptr<storage_interface> st(
|
||||
default_storage_constructor(info, full_path.branch_path(), fp));
|
||||
|
||||
// calculate the hash for all pieces
|
||||
int num = t.num_pieces();
|
||||
std::vector<char> buf(piece_size);
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
st->read(&buf[0], i, 0, t.piece_size(i));
|
||||
hasher h(&buf[0], t.piece_size(i));
|
||||
t.set_hash(i, h.final());
|
||||
std::cerr << "\r" << (i+1) << "/" << num;
|
||||
}
|
||||
set_piece_hashes(t, full_path.branch_path()
|
||||
, boost::bind(&print_progress, _1, t.num_pieces()));
|
||||
std::cerr << std::endl;
|
||||
|
||||
t.set_creator(creator_str);
|
||||
|
||||
if (argc == 5)
|
||||
t.add_url_seed(argv[4]);
|
||||
if (argc == 5) t.add_url_seed(argv[4]);
|
||||
|
||||
// create the torrent and print it to out
|
||||
ofstream out(complete(path(argv[1])), std::ios_base::binary);
|
||||
|
|
|
@ -20,6 +20,7 @@ libtorrent/escape_string.hpp \
|
|||
libtorrent/extensions.hpp \
|
||||
libtorrent/file.hpp \
|
||||
libtorrent/file_pool.hpp \
|
||||
libtorrent/file_storage.hpp \
|
||||
libtorrent/fingerprint.hpp \
|
||||
libtorrent/GeoIP.h \
|
||||
libtorrent/gzip.hpp \
|
||||
|
|
|
@ -53,6 +53,21 @@ namespace libtorrent
|
|||
torrent_handle handle;
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT file_renamed_alert: torrent_alert
|
||||
{
|
||||
file_renamed_alert(torrent_handle const& h
|
||||
, std::string const& name_
|
||||
, std::string const& msg)
|
||||
: torrent_alert(h, alert::warning, msg)
|
||||
, name(name_)
|
||||
{}
|
||||
|
||||
virtual std::auto_ptr<alert> clone() const
|
||||
{ return std::auto_ptr<alert>(new file_renamed_alert(*this)); }
|
||||
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT tracker_alert: torrent_alert
|
||||
{
|
||||
tracker_alert(torrent_handle const& h
|
||||
|
|
|
@ -35,6 +35,12 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/peer_id.hpp"
|
||||
#include "libtorrent/file_storage.hpp"
|
||||
#include "libtorrent/file_pool.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/storage.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
@ -44,8 +50,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#endif
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
|
@ -56,26 +64,29 @@ namespace libtorrent
|
|||
namespace fs = boost::filesystem;
|
||||
namespace pt = boost::posix_time;
|
||||
|
||||
struct create_torrent
|
||||
struct TORRENT_EXPORT create_torrent
|
||||
{
|
||||
create_torrent();
|
||||
create_torrent(file_storage& fs, int piece_size);
|
||||
create_torrent(file_storage& fs);
|
||||
entry generate() const;
|
||||
|
||||
file_storage const& files() const { return m_files; }
|
||||
|
||||
void set_comment(char const* str);
|
||||
void set_creator(char const* str);
|
||||
void set_piece_size(int size);
|
||||
void set_hash(int index, sha1_hash const& h);
|
||||
void add_file(fs::path file, size_type size);
|
||||
void add_url_seed(std::string const& url);
|
||||
void add_node(std::pair<std::string, int> const& node);
|
||||
void add_tracker(std::string const& url, int tier = 0);
|
||||
|
||||
int num_pieces() const { return m_num_pieces; }
|
||||
int piece_length() const { return m_piece_length; }
|
||||
int piece_size(int i) const;
|
||||
int num_pieces() const { return m_files.num_pieces(); }
|
||||
int piece_length() const { return m_files.piece_length(); }
|
||||
int piece_size(int i) const { return m_files.piece_size(i); }
|
||||
|
||||
private:
|
||||
|
||||
file_storage& m_files;
|
||||
|
||||
// the urls to the trackers
|
||||
typedef std::pair<std::string, int> announce_entry;
|
||||
std::vector<announce_entry> m_urls;
|
||||
|
@ -84,32 +95,15 @@ namespace libtorrent
|
|||
|
||||
std::vector<sha1_hash> m_piece_hash;
|
||||
|
||||
// the length of one piece
|
||||
// if this is 0, the torrent_info is
|
||||
// in an uninitialized state
|
||||
int m_piece_length;
|
||||
|
||||
typedef std::pair<fs::path, size_type> file_entry;
|
||||
// the list of files that this torrent consists of
|
||||
std::vector<file_entry> m_files;
|
||||
|
||||
// dht nodes to add to the routing table/bootstrap from
|
||||
typedef std::vector<std::pair<std::string, int> > nodes_t;
|
||||
nodes_t m_nodes;
|
||||
|
||||
// the sum of all filesizes
|
||||
size_type m_total_size;
|
||||
|
||||
// the number of pieces in the torrent
|
||||
int m_num_pieces;
|
||||
|
||||
// the hash that identifies this torrent
|
||||
// is mutable because it's calculated
|
||||
// lazily
|
||||
mutable sha1_hash m_info_hash;
|
||||
|
||||
std::string m_name;
|
||||
|
||||
// if a creation date is found in the torrent file
|
||||
// this will be set to that, otherwise it'll be
|
||||
// 1970, Jan 1
|
||||
|
@ -134,6 +128,72 @@ namespace libtorrent
|
|||
// be announced on the dht
|
||||
bool m_private;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline bool default_pred(boost::filesystem::path const&) { return true; }
|
||||
|
||||
inline void nop(int i) {}
|
||||
|
||||
template <class Pred>
|
||||
void add_files_impl(file_storage& fs, boost::filesystem::path const& p
|
||||
, boost::filesystem::path const& l, Pred pred)
|
||||
{
|
||||
using boost::filesystem::path;
|
||||
using boost::filesystem::directory_iterator;
|
||||
std::string const& leaf = l.leaf();
|
||||
if (leaf == ".." || leaf == ".") return;
|
||||
if (!pred(l)) return;
|
||||
path f(p / l);
|
||||
if (is_directory(f))
|
||||
{
|
||||
for (directory_iterator i(f), end; i != end; ++i)
|
||||
add_files_impl(fs, p, l / i->leaf(), pred);
|
||||
}
|
||||
else
|
||||
{
|
||||
fs.add_file(l, file_size(f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Pred>
|
||||
void add_files(file_storage& fs, boost::filesystem::path const& file, Pred p)
|
||||
{
|
||||
detail::add_files_impl(fs, complete(file).branch_path(), file.leaf(), p);
|
||||
}
|
||||
|
||||
inline void add_files(file_storage& fs, boost::filesystem::path const& file)
|
||||
{
|
||||
detail::add_files_impl(fs, complete(file).branch_path(), file.leaf(), detail::default_pred);
|
||||
}
|
||||
|
||||
template <class Fun>
|
||||
void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p, Fun f)
|
||||
{
|
||||
file_pool fp;
|
||||
boost::scoped_ptr<storage_interface> st(
|
||||
default_storage_constructor(const_cast<file_storage&>(t.files()), p, fp));
|
||||
|
||||
// calculate the hash for all pieces
|
||||
int num = t.num_pieces();
|
||||
std::vector<char> buf(t.piece_length());
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
// read hits the disk and will block. Progress should
|
||||
// be updated in between reads
|
||||
st->read(&buf[0], i, 0, t.piece_size(i));
|
||||
hasher h(&buf[0], t.piece_size(i));
|
||||
t.set_hash(i, h.final());
|
||||
f(i);
|
||||
}
|
||||
}
|
||||
|
||||
inline void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p)
|
||||
{
|
||||
set_piece_hashes(t, p, detail::nop);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -82,6 +82,7 @@ namespace libtorrent
|
|||
, check_fastresume
|
||||
, check_files
|
||||
, save_resume_data
|
||||
, rename_file
|
||||
};
|
||||
|
||||
action_t action;
|
||||
|
@ -91,7 +92,7 @@ namespace libtorrent
|
|||
boost::intrusive_ptr<piece_manager> storage;
|
||||
// arguments used for read and write
|
||||
int piece, offset;
|
||||
// used for move_storage. On errors, this is set
|
||||
// used for move_storage and rename_file. On errors, this is set
|
||||
// to the error message
|
||||
std::string str;
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ namespace libtorrent
|
|||
boost::shared_ptr<file> open_file(void* st, fs::path const& p
|
||||
, file::open_mode m, std::string& error);
|
||||
void release(void* st);
|
||||
void release(fs::path const& p);
|
||||
void resize(int size);
|
||||
|
||||
private:
|
||||
|
|
|
@ -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
|
||||
|
|
@ -87,11 +87,11 @@ namespace libtorrent
|
|||
#endif
|
||||
|
||||
TORRENT_EXPORT std::vector<std::pair<size_type, std::time_t> > get_filesizes(
|
||||
torrent_info const& t
|
||||
file_storage const& t
|
||||
, fs::path p);
|
||||
|
||||
TORRENT_EXPORT bool match_filesizes(
|
||||
torrent_info const& t
|
||||
file_storage const& t
|
||||
, fs::path p
|
||||
, std::vector<std::pair<size_type, std::time_t> > const& sizes
|
||||
, bool compact_mode
|
||||
|
@ -157,6 +157,9 @@ namespace libtorrent
|
|||
// non-zero return value indicates an error
|
||||
virtual bool release_files() = 0;
|
||||
|
||||
// this will rename the file specified by index.
|
||||
virtual bool rename_file(int index, std::string const& new_filename) = 0;
|
||||
|
||||
// this will close all open files and delete them
|
||||
// non-zero return value indicates an error
|
||||
virtual bool delete_files() = 0;
|
||||
|
@ -178,16 +181,12 @@ namespace libtorrent
|
|||
};
|
||||
|
||||
typedef storage_interface* (&storage_constructor_type)(
|
||||
boost::intrusive_ptr<torrent_info const>, fs::path const&
|
||||
, file_pool&);
|
||||
file_storage const&, fs::path const&, file_pool&);
|
||||
|
||||
TORRENT_EXPORT storage_interface* default_storage_constructor(
|
||||
boost::intrusive_ptr<torrent_info const> ti
|
||||
, fs::path const& path, file_pool& fp);
|
||||
|
||||
file_storage const&, fs::path const&, file_pool&);
|
||||
TORRENT_EXPORT storage_interface* mapped_storage_constructor(
|
||||
boost::intrusive_ptr<torrent_info const> ti
|
||||
, fs::path const& path, file_pool& fp);
|
||||
file_storage const&, fs::path const&, file_pool&);
|
||||
|
||||
struct disk_io_thread;
|
||||
|
||||
|
@ -201,7 +200,7 @@ namespace libtorrent
|
|||
|
||||
piece_manager(
|
||||
boost::shared_ptr<void> const& torrent
|
||||
, boost::intrusive_ptr<torrent_info const> ti
|
||||
, boost::intrusive_ptr<torrent_info const> info
|
||||
, fs::path const& path
|
||||
, file_pool& fp
|
||||
, disk_io_thread& io
|
||||
|
@ -210,8 +209,7 @@ namespace libtorrent
|
|||
|
||||
~piece_manager();
|
||||
|
||||
torrent_info const* info() const { return m_info.get(); }
|
||||
|
||||
boost::intrusive_ptr<torrent_info const> info() const { return m_info; }
|
||||
void write_resume_data(entry& rd) const;
|
||||
|
||||
void async_check_fastresume(entry const* resume_data
|
||||
|
@ -219,6 +217,9 @@ namespace libtorrent
|
|||
|
||||
void async_check_files(boost::function<void(int, disk_io_job const&)> const& handler);
|
||||
|
||||
void async_rename_file(int index, std::string const& name
|
||||
, boost::function<void(int, disk_io_job const&)> const& handler);
|
||||
|
||||
void async_read(
|
||||
peer_request const& r
|
||||
, boost::function<void(int, disk_io_job const&)> const& handler
|
||||
|
@ -316,6 +317,8 @@ namespace libtorrent
|
|||
|
||||
int release_files_impl() { return m_storage->release_files(); }
|
||||
int delete_files_impl() { return m_storage->delete_files(); }
|
||||
int rename_file_impl(int index, std::string const& new_filename)
|
||||
{ return m_storage->rename_file(index, new_filename); }
|
||||
|
||||
bool move_storage_impl(fs::path const& save_path);
|
||||
|
||||
|
@ -326,12 +329,13 @@ namespace libtorrent
|
|||
void debug_log() const;
|
||||
#endif
|
||||
#endif
|
||||
boost::intrusive_ptr<torrent_info const> m_info;
|
||||
file_storage const& m_files;
|
||||
|
||||
boost::scoped_ptr<storage_interface> m_storage;
|
||||
|
||||
storage_mode_t m_storage_mode;
|
||||
|
||||
boost::intrusive_ptr<torrent_info const> m_info;
|
||||
|
||||
// slots that haven't had any file storage allocated
|
||||
std::vector<int> m_unallocated_slots;
|
||||
// slots that have file storage, but isn't assigned to a piece
|
||||
|
|
|
@ -565,8 +565,14 @@ namespace libtorrent
|
|||
int max_uploads() const { return m_max_uploads; }
|
||||
void set_max_connections(int limit);
|
||||
int max_connections() const { return m_max_connections; }
|
||||
|
||||
void move_storage(fs::path const& save_path);
|
||||
|
||||
// renames the file with the given index to the new name
|
||||
// the name may include a directory path
|
||||
// returns false on failure
|
||||
bool rename_file(int index, std::string const& name);
|
||||
|
||||
// unless this returns true, new connections must wait
|
||||
// with their initialization.
|
||||
bool ready_for_connections() const
|
||||
|
@ -590,6 +596,7 @@ namespace libtorrent
|
|||
void on_torrent_paused(int ret, disk_io_job const& j);
|
||||
void on_storage_moved(int ret, disk_io_job const& j);
|
||||
void on_save_resume_data(int ret, disk_io_job const& j);
|
||||
void on_file_renamed(int ret, disk_io_job const& j);
|
||||
|
||||
void on_piece_verified(int ret, disk_io_job const& j
|
||||
, boost::function<void(int)> f);
|
||||
|
|
|
@ -442,6 +442,7 @@ namespace libtorrent
|
|||
|
||||
// post condition: save_path() == save_path if true is returned
|
||||
void move_storage(fs::path const& save_path) const;
|
||||
void rename_file(int index, fs::path const& new_name) const;
|
||||
|
||||
sha1_hash info_hash() const;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2003, Arvid Norberg
|
||||
Copyright (c) 2003-2008, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -30,9 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_TORRENT_INFO_HPP_INCLUDE
|
||||
#define TORRENT_TORRENT_INFO_HPP_INCLUDE
|
||||
|
||||
#ifndef TORRENT_TORRENT_INFO_HPP_INCLUDED
|
||||
#define TORRENT_TORRENT_INFO_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -44,7 +43,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/shared_array.hpp>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -56,44 +54,17 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/socket.hpp"
|
||||
#include "libtorrent/peer_id.hpp"
|
||||
#include "libtorrent/size_type.hpp"
|
||||
#include "libtorrent/peer_request.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
#include "libtorrent/intrusive_ptr_base.hpp"
|
||||
#include "libtorrent/assert.hpp"
|
||||
#include "libtorrent/file_storage.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
namespace pt = boost::posix_time;
|
||||
namespace gr = boost::gregorian;
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
struct TORRENT_EXPORT file_entry
|
||||
{
|
||||
file_entry(): offset(0), size(0), file_base(0) {}
|
||||
|
||||
fs::path path;
|
||||
size_type offset; // the offset of this file inside the torrent
|
||||
size_type size; // the size of this file
|
||||
// the offset in the file where the storage starts.
|
||||
// This is always 0 unless parts of the torrent is
|
||||
// compressed into a single file, such as a so-called part file.
|
||||
size_type file_base;
|
||||
// if the path was incorrectly encoded, this is
|
||||
// the original corrupt encoded string. It is
|
||||
// preserved in order to be able to reproduce
|
||||
// the correct info-hash
|
||||
boost::shared_ptr<const fs::path> orig_path;
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT file_slice
|
||||
{
|
||||
int file_index;
|
||||
size_type offset;
|
||||
size_type size;
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT announce_entry
|
||||
{
|
||||
announce_entry(std::string const& u): url(u), tier(0) {}
|
||||
|
@ -101,10 +72,12 @@ namespace libtorrent
|
|||
int tier;
|
||||
};
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
struct TORRENT_EXPORT invalid_torrent_file: std::exception
|
||||
{
|
||||
virtual const char* what() const throw() { return "invalid torrent file"; }
|
||||
};
|
||||
#endif
|
||||
|
||||
class TORRENT_EXPORT torrent_info : public intrusive_ptr_base<torrent_info>
|
||||
{
|
||||
|
@ -116,86 +89,36 @@ namespace libtorrent
|
|||
torrent_info(char const* filename);
|
||||
~torrent_info();
|
||||
|
||||
file_storage const& files() const { return m_files; }
|
||||
|
||||
void add_tracker(std::string const& url, int tier = 0);
|
||||
|
||||
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<announce_entry> const& trackers() const { return m_urls; }
|
||||
|
||||
std::vector<std::string> const& url_seeds() const
|
||||
{ return m_url_seeds; }
|
||||
void add_url_seed(std::string const& url)
|
||||
{ m_url_seeds.push_back(url); }
|
||||
|
||||
typedef std::vector<file_entry>::const_iterator file_iterator;
|
||||
typedef std::vector<file_entry>::const_reverse_iterator reverse_file_iterator;
|
||||
|
||||
// list the files in the torrent file
|
||||
file_iterator begin_files(bool storage = false) const
|
||||
{
|
||||
if (!storage || m_remapped_files.empty())
|
||||
return m_files.begin();
|
||||
else
|
||||
return m_remapped_files.begin();
|
||||
}
|
||||
|
||||
file_iterator end_files(bool storage = false) const
|
||||
{
|
||||
if (!storage || m_remapped_files.empty())
|
||||
return m_files.end();
|
||||
else
|
||||
return m_remapped_files.end();
|
||||
}
|
||||
|
||||
reverse_file_iterator rbegin_files(bool storage = false) const
|
||||
{
|
||||
if (!storage || m_remapped_files.empty())
|
||||
return m_files.rbegin();
|
||||
else
|
||||
return m_remapped_files.rbegin();
|
||||
}
|
||||
|
||||
reverse_file_iterator rend_files(bool storage = false) const
|
||||
{
|
||||
if (!storage || m_remapped_files.empty())
|
||||
return m_files.rend();
|
||||
else
|
||||
return m_remapped_files.rend();
|
||||
}
|
||||
|
||||
int num_files(bool storage = false) const
|
||||
{
|
||||
TORRENT_ASSERT(m_piece_length > 0);
|
||||
if (!storage || m_remapped_files.empty())
|
||||
return int(m_files.size());
|
||||
else
|
||||
return int(m_remapped_files.size());
|
||||
}
|
||||
|
||||
file_entry const& file_at(int index, bool storage = false) const
|
||||
{
|
||||
if (!storage || m_remapped_files.empty())
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0 && index < (int)m_files.size());
|
||||
return m_files[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0 && index < (int)m_remapped_files.size());
|
||||
return m_remapped_files[index];
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<announce_entry> const& trackers() const { return m_urls; }
|
||||
|
||||
size_type total_size() const { TORRENT_ASSERT(m_piece_length > 0); return m_total_size; }
|
||||
int piece_length() const { TORRENT_ASSERT(m_piece_length > 0); return m_piece_length; }
|
||||
int num_pieces() const { TORRENT_ASSERT(m_piece_length > 0); return m_num_pieces; }
|
||||
size_type total_size() const { return m_files.total_size(); }
|
||||
int piece_length() const { return m_files.piece_length(); }
|
||||
int num_pieces() const { return m_files.num_pieces(); }
|
||||
const sha1_hash& info_hash() const { return m_info_hash; }
|
||||
const std::string& name() const { TORRENT_ASSERT(m_piece_length > 0); return m_name; }
|
||||
const std::string& name() const { return m_files.name(); }
|
||||
|
||||
typedef file_storage::iterator file_iterator;
|
||||
typedef file_storage::reverse_iterator reverse_file_iterator;
|
||||
|
||||
file_iterator begin_files() const { return m_files.begin(); }
|
||||
file_iterator end_files() const { return m_files.end(); }
|
||||
reverse_file_iterator rbegin_files() const { return m_files.rbegin(); }
|
||||
reverse_file_iterator rend_files() const { return m_files.rend(); }
|
||||
int num_files() const { return m_files.num_files(); }
|
||||
file_entry const& file_at(int index) const { return m_files.at(index); }
|
||||
|
||||
std::vector<file_slice> map_block(int piece, size_type offset, int size) const
|
||||
{ return m_files.map_block(piece, offset, size); }
|
||||
peer_request map_file(int file, size_type offset, int size) const
|
||||
{ return m_files.map_file(file, offset, size); }
|
||||
|
||||
// ------- start deprecation -------
|
||||
// these functions will be removed in a future version
|
||||
|
@ -203,21 +126,19 @@ namespace libtorrent
|
|||
void print(std::ostream& os) const TORRENT_DEPRECATED;
|
||||
// ------- end deprecation -------
|
||||
|
||||
bool is_valid() const { return m_piece_length > 0; }
|
||||
bool is_valid() const { return m_files.is_valid(); }
|
||||
|
||||
bool priv() const { return m_private; }
|
||||
|
||||
int piece_size(int index) const;
|
||||
int piece_size(int index) const { return m_files.piece_size(index); }
|
||||
|
||||
sha1_hash hash_for_piece(int index) const
|
||||
{
|
||||
return sha1_hash(hash_for_piece_ptr(index));
|
||||
}
|
||||
{ return sha1_hash(hash_for_piece_ptr(index)); }
|
||||
|
||||
char const* hash_for_piece_ptr(int index) const
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0);
|
||||
TORRENT_ASSERT(index < m_num_pieces);
|
||||
TORRENT_ASSERT(index < m_files.num_pieces());
|
||||
TORRENT_ASSERT(m_piece_hashes);
|
||||
TORRENT_ASSERT(m_piece_hashes >= m_info_section.get());
|
||||
TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size);
|
||||
|
@ -261,41 +182,18 @@ namespace libtorrent
|
|||
|
||||
bool parse_torrent_file(lazy_entry const& libtorrent, std::string& error);
|
||||
|
||||
file_storage m_files;
|
||||
|
||||
// the urls to the trackers
|
||||
std::vector<announce_entry> m_urls;
|
||||
|
||||
std::vector<std::string> m_url_seeds;
|
||||
|
||||
// the length of one piece
|
||||
// if this is 0, the torrent_info is
|
||||
// in an uninitialized state
|
||||
int m_piece_length;
|
||||
|
||||
// the list of files that this torrent consists of
|
||||
std::vector<file_entry> m_files;
|
||||
|
||||
// this vector is typically empty. If it is not
|
||||
// empty, it means the user has re-mapped the
|
||||
// files in this torrent to different names
|
||||
// on disk. This is only used when reading and
|
||||
// writing the disk.
|
||||
std::vector<file_entry> m_remapped_files;
|
||||
|
||||
nodes_t m_nodes;
|
||||
|
||||
// the sum of all filesizes
|
||||
size_type m_total_size;
|
||||
|
||||
// the number of pieces in the torrent
|
||||
int m_num_pieces;
|
||||
|
||||
// the hash that identifies this torrent
|
||||
// is mutable because it's calculated
|
||||
// lazily
|
||||
sha1_hash m_info_hash;
|
||||
|
||||
std::string m_name;
|
||||
|
||||
// if a creation date is found in the torrent file
|
||||
// this will be set to that, otherwise it'll be
|
||||
// 1970, Jan 1
|
||||
|
|
|
@ -24,7 +24,7 @@ logger.cpp file_pool.cpp ut_pex.cpp lsd.cpp upnp.cpp instantiate_connection.cpp
|
|||
socks5_stream.cpp socks4_stream.cpp http_stream.cpp connection_queue.cpp \
|
||||
disk_io_thread.cpp ut_metadata.cpp magnet_uri.cpp udp_socket.cpp smart_ban.cpp \
|
||||
http_parser.cpp gzip.cpp disk_buffer_holder.cpp create_torrent.cpp GeoIP.c \
|
||||
parse_url.cpp $(kademlia_sources)
|
||||
parse_url.cpp file_storage.cpp $(kademlia_sources)
|
||||
|
||||
noinst_HEADERS = \
|
||||
$(top_srcdir)/include/libtorrent/alert.hpp \
|
||||
|
@ -51,6 +51,7 @@ $(top_srcdir)/include/libtorrent/extensions/logger.hpp \
|
|||
$(top_srcdir)/include/libtorrent/extensions/ut_pex.hpp \
|
||||
$(top_srcdir)/include/libtorrent/file.hpp \
|
||||
$(top_srcdir)/include/libtorrent/file_pool.hpp \
|
||||
$(top_srcdir)/include/libtorrent/file_storage.hpp \
|
||||
$(top_srcdir)/include/libtorrent/fingerprint.hpp \
|
||||
$(top_srcdir)/include/libtorrent/gzip.hpp \
|
||||
$(top_srcdir)/include/libtorrent/hasher.hpp \
|
||||
|
|
|
@ -31,7 +31,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/file_pool.hpp"
|
||||
#include "libtorrent/storage.hpp"
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/date_time/gregorian/gregorian.hpp>
|
||||
|
@ -41,22 +42,61 @@ namespace gr = boost::gregorian;
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
create_torrent::create_torrent()
|
||||
: m_piece_length(0)
|
||||
, m_total_size(0)
|
||||
, m_num_pieces(0)
|
||||
, m_info_hash()
|
||||
, m_name()
|
||||
create_torrent::create_torrent(file_storage& fs, int size)
|
||||
: m_files(fs)
|
||||
, m_creation_date(pt::second_clock::universal_time())
|
||||
, m_multifile(false)
|
||||
, m_multifile(fs.num_files() > 1)
|
||||
, m_private(false)
|
||||
{}
|
||||
{
|
||||
TORRENT_ASSERT(fs.num_files() > 0);
|
||||
if (!m_multifile && m_files.at(0).path.has_branch_path()) m_multifile = true;
|
||||
|
||||
// make sure the size is an even power of 2
|
||||
#ifndef NDEBUG
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
if (size & (1 << i))
|
||||
{
|
||||
TORRENT_ASSERT((size & ~(1 << i)) == 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
m_files.set_piece_length(size);
|
||||
m_files.set_num_pieces(static_cast<int>(
|
||||
(m_files.total_size() + m_files.piece_length() - 1) / m_files.piece_length()));
|
||||
m_piece_hash.resize(m_files.num_pieces());
|
||||
}
|
||||
|
||||
create_torrent::create_torrent(file_storage& fs)
|
||||
: m_files(fs)
|
||||
, m_creation_date(pt::second_clock::universal_time())
|
||||
, m_multifile(fs.num_files() > 1)
|
||||
, m_private(false)
|
||||
{
|
||||
TORRENT_ASSERT(fs.num_files() > 0);
|
||||
if (!m_multifile && m_files.at(0).path.has_branch_path()) m_multifile = true;
|
||||
|
||||
const int target_size = 40 * 1024;
|
||||
int size = fs.total_size() / (target_size / 20);
|
||||
|
||||
for (int i = 4*1024*1024; i > 16*1024; i /= 2)
|
||||
{
|
||||
if (size < i) continue;
|
||||
size = i;
|
||||
break;
|
||||
}
|
||||
|
||||
m_files.set_piece_length(size);
|
||||
m_files.set_num_pieces(static_cast<int>(
|
||||
(m_files.total_size() + m_files.piece_length() - 1) / m_files.piece_length()));
|
||||
m_piece_hash.resize(m_files.num_pieces());
|
||||
}
|
||||
entry create_torrent::generate() const
|
||||
{
|
||||
TORRENT_ASSERT(m_piece_length > 0);
|
||||
TORRENT_ASSERT(m_files.piece_length() > 0);
|
||||
|
||||
if (m_files.empty())
|
||||
if (m_files.num_files() == 0)
|
||||
{
|
||||
// TODO: throw something here
|
||||
// throw
|
||||
|
@ -128,15 +168,13 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
entry& info = dict["info"];
|
||||
|
||||
info["name"] = m_name;
|
||||
|
||||
info["name"] = m_files.name();
|
||||
|
||||
if (m_private) info["private"] = 1;
|
||||
|
||||
if (!m_multifile)
|
||||
{
|
||||
info["length"] = m_files.front().second;
|
||||
info["length"] = m_files.at(0).size;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -144,19 +182,19 @@ namespace libtorrent
|
|||
{
|
||||
entry& files = info["files"];
|
||||
|
||||
for (std::vector<file_entry>::const_iterator i = m_files.begin();
|
||||
for (file_storage::iterator i = m_files.begin();
|
||||
i != m_files.end(); ++i)
|
||||
{
|
||||
files.list().push_back(entry());
|
||||
entry& file_e = files.list().back();
|
||||
file_e["length"] = i->second;
|
||||
file_e["length"] = i->size;
|
||||
entry& path_e = file_e["path"];
|
||||
|
||||
TORRENT_ASSERT(i->first.has_branch_path());
|
||||
TORRENT_ASSERT(*i->first.begin() == m_name);
|
||||
TORRENT_ASSERT(i->path.has_branch_path());
|
||||
TORRENT_ASSERT(*i->path.begin() == m_files.name());
|
||||
|
||||
for (fs::path::iterator j = boost::next(i->first.begin());
|
||||
j != i->first.end(); ++j)
|
||||
for (fs::path::iterator j = boost::next(i->path.begin());
|
||||
j != i->path.end(); ++j)
|
||||
{
|
||||
path_e.list().push_back(entry(*j));
|
||||
}
|
||||
|
@ -164,7 +202,7 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
info["piece length"] = m_piece_length;
|
||||
info["piece length"] = m_files.piece_length();
|
||||
entry& pieces = info["pieces"];
|
||||
|
||||
std::string& p = pieces.string();
|
||||
|
@ -183,21 +221,6 @@ namespace libtorrent
|
|||
|
||||
}
|
||||
|
||||
int create_torrent::piece_size(int index) const
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0 && index < num_pieces());
|
||||
if (index == num_pieces()-1)
|
||||
{
|
||||
int size = int(m_total_size
|
||||
- (num_pieces() - 1) * piece_length());
|
||||
TORRENT_ASSERT(size > 0);
|
||||
TORRENT_ASSERT(size <= piece_length());
|
||||
return int(size);
|
||||
}
|
||||
else
|
||||
return piece_length();
|
||||
}
|
||||
|
||||
void create_torrent::add_tracker(std::string const& url, int tier)
|
||||
{
|
||||
m_urls.push_back(announce_entry(url, tier));
|
||||
|
@ -207,32 +230,6 @@ namespace libtorrent
|
|||
, bind(&announce_entry::second, _1) < bind(&announce_entry::second, _2));
|
||||
}
|
||||
|
||||
void create_torrent::set_piece_size(int size)
|
||||
{
|
||||
// make sure the size is an even power of 2
|
||||
#ifndef NDEBUG
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
if (size & (1 << i))
|
||||
{
|
||||
TORRENT_ASSERT((size & ~(1 << i)) == 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
m_piece_length = size;
|
||||
|
||||
m_num_pieces = static_cast<int>(
|
||||
(m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
int old_num_pieces = static_cast<int>(m_piece_hash.size());
|
||||
|
||||
m_piece_hash.resize(m_num_pieces);
|
||||
for (int i = old_num_pieces; i < m_num_pieces; ++i)
|
||||
{
|
||||
m_piece_hash[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
void create_torrent::set_hash(int index, sha1_hash const& h)
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0);
|
||||
|
@ -240,46 +237,6 @@ namespace libtorrent
|
|||
m_piece_hash[index] = h;
|
||||
}
|
||||
|
||||
void create_torrent::add_file(fs::path file, size_type size)
|
||||
{
|
||||
// TORRENT_ASSERT(file.begin() != file.end());
|
||||
|
||||
if (!file.has_branch_path())
|
||||
{
|
||||
// you have already added at least one file with a
|
||||
// path to the file (branch_path), which means that
|
||||
// all the other files need to be in the same top
|
||||
// directory as the first file.
|
||||
TORRENT_ASSERT(m_files.empty());
|
||||
TORRENT_ASSERT(!m_multifile);
|
||||
m_name = file.string();
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (!m_files.empty())
|
||||
TORRENT_ASSERT(m_name == *file.begin());
|
||||
#endif
|
||||
m_multifile = true;
|
||||
m_name = *file.begin();
|
||||
}
|
||||
|
||||
m_files.push_back(file_entry(file, size));
|
||||
|
||||
m_total_size += size;
|
||||
|
||||
if (m_piece_length == 0)
|
||||
m_piece_length = 256 * 1024;
|
||||
|
||||
m_num_pieces = int((m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
int old_num_pieces = int(m_piece_hash.size());
|
||||
|
||||
m_piece_hash.resize(m_num_pieces);
|
||||
if (m_num_pieces > old_num_pieces)
|
||||
std::for_each(m_piece_hash.begin() + old_num_pieces
|
||||
, m_piece_hash.end(), boost::bind(&sha1_hash::clear, _1));
|
||||
}
|
||||
|
||||
void create_torrent::add_node(std::pair<std::string, int> const& node)
|
||||
{
|
||||
m_nodes.push_back(node);
|
||||
|
@ -299,5 +256,6 @@ namespace libtorrent
|
|||
{
|
||||
m_created_by = str;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1049,6 +1049,13 @@ namespace libtorrent
|
|||
ret = 0;
|
||||
break;
|
||||
}
|
||||
case disk_io_job::rename_file:
|
||||
{
|
||||
#ifdef TORRENT_DISK_STATS
|
||||
m_log << log_time() << " rename file" << std::endl;
|
||||
#endif
|
||||
ret = j.storage->rename_file_impl(j.piece, j.str);
|
||||
}
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
} catch (std::exception& e)
|
||||
|
|
|
@ -115,6 +115,16 @@ namespace libtorrent
|
|||
return e.file_ptr;
|
||||
}
|
||||
|
||||
void file_pool::release(fs::path const& p)
|
||||
{
|
||||
boost::mutex::scoped_lock l(m_mutex);
|
||||
|
||||
typedef nth_index<file_set, 0>::type path_view;
|
||||
path_view& pt = get<0>(m_files);
|
||||
path_view::iterator i = pt.find(p);
|
||||
if (i != pt.end()) pt.erase(i);
|
||||
}
|
||||
|
||||
void file_pool::release(void* st)
|
||||
{
|
||||
boost::mutex::scoped_lock l(m_mutex);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -262,8 +262,8 @@ namespace libtorrent
|
|||
|
||||
struct mapped_storage: storage_interface
|
||||
{
|
||||
mapped_storage(boost::intrusive_ptr<torrent_info const> const& info, fs::path save_path)
|
||||
: m_info(info)
|
||||
mapped_storage(file_storage const& fs, fs::path save_path)
|
||||
: m_files(fs)
|
||||
, m_save_path(save_path)
|
||||
{}
|
||||
|
||||
|
@ -272,9 +272,9 @@ namespace libtorrent
|
|||
int read(char* buf, int slot, int offset, int size)
|
||||
{
|
||||
TORRENT_ASSERT(buf != 0);
|
||||
TORRENT_ASSERT(slot >= 0 && slot < m_info->num_pieces());
|
||||
TORRENT_ASSERT(slot >= 0 && slot < m_files.num_pieces());
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(offset < m_info->piece_size(slot));
|
||||
TORRENT_ASSERT(offset < m_files.piece_size(slot));
|
||||
TORRENT_ASSERT(size > 0);
|
||||
|
||||
size_type result = -1;
|
||||
|
@ -283,17 +283,17 @@ namespace libtorrent
|
|||
|
||||
#ifndef NDEBUG
|
||||
std::vector<file_slice> slices
|
||||
= m_info->map_block(slot, offset, size, true);
|
||||
= files().map_block(slot, offset, size);
|
||||
TORRENT_ASSERT(!slices.empty());
|
||||
#endif
|
||||
size_type start = slot * (size_type)m_info->piece_length() + offset;
|
||||
TORRENT_ASSERT(start + size <= m_info->total_size());
|
||||
size_type start = slot * (size_type)m_files.piece_length() + offset;
|
||||
TORRENT_ASSERT(start + size <= m_files.total_size());
|
||||
|
||||
// find the file iterator and file offset
|
||||
size_type file_offset = start;
|
||||
std::vector<file_entry>::const_iterator file_iter;
|
||||
|
||||
for (file_iter = m_info->begin_files(true);;)
|
||||
for (file_iter = files().begin();;)
|
||||
{
|
||||
if (file_offset < file_iter->size)
|
||||
break;
|
||||
|
@ -333,7 +333,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(int(slices.size()) > counter);
|
||||
size_type slice_size = slices[counter].size;
|
||||
TORRENT_ASSERT(slice_size == read_bytes);
|
||||
TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path
|
||||
TORRENT_ASSERT(files().at(slices[counter].file_index).path
|
||||
== file_iter->path);
|
||||
#endif
|
||||
|
||||
|
@ -353,7 +353,7 @@ namespace libtorrent
|
|||
{
|
||||
++file_iter;
|
||||
// skip empty files
|
||||
while (file_iter != m_info->end_files(true) && file_iter->size == 0)
|
||||
while (file_iter != files().end() && file_iter->size == 0)
|
||||
++file_iter;
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
@ -390,24 +390,24 @@ namespace libtorrent
|
|||
int write(const char* buf, int slot, int offset, int size)
|
||||
{
|
||||
TORRENT_ASSERT(buf != 0);
|
||||
TORRENT_ASSERT(slot >= 0 && slot < m_info->num_pieces());
|
||||
TORRENT_ASSERT(slot >= 0 && slot < m_files.num_pieces());
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(offset < m_info->piece_size(slot));
|
||||
TORRENT_ASSERT(offset < m_files.piece_size(slot));
|
||||
TORRENT_ASSERT(size > 0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::vector<file_slice> slices
|
||||
= m_info->map_block(slot, offset, size, true);
|
||||
= files().map_block(slot, offset, size);
|
||||
TORRENT_ASSERT(!slices.empty());
|
||||
#endif
|
||||
size_type start = slot * (size_type)m_info->piece_length() + offset;
|
||||
TORRENT_ASSERT(start + size <= m_info->total_size());
|
||||
size_type start = slot * (size_type)m_files.piece_length() + offset;
|
||||
TORRENT_ASSERT(start + size <= m_files.total_size());
|
||||
|
||||
// find the file iterator and file offset
|
||||
size_type file_offset = start;
|
||||
std::vector<file_entry>::const_iterator file_iter;
|
||||
|
||||
for (file_iter = m_info->begin_files(true);;)
|
||||
for (file_iter = files().begin();;)
|
||||
{
|
||||
if (file_offset < file_iter->size)
|
||||
break;
|
||||
|
@ -449,7 +449,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(int(slices.size()) > counter);
|
||||
size_type slice_size = slices[counter].size;
|
||||
TORRENT_ASSERT(slice_size == write_bytes);
|
||||
TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path
|
||||
TORRENT_ASSERT(files().at(slices[counter].file_index).path
|
||||
== file_iter->path);
|
||||
#endif
|
||||
|
||||
|
@ -468,7 +468,7 @@ namespace libtorrent
|
|||
if (left_to_write > 0)
|
||||
{
|
||||
++file_iter;
|
||||
while (file_iter != m_info->end_files(true) && file_iter->size == 0)
|
||||
while (file_iter != files().end() && file_iter->size == 0)
|
||||
++file_iter;
|
||||
#ifndef NDEBUG
|
||||
// empty files are not returned by map_block, so if
|
||||
|
@ -533,11 +533,11 @@ namespace libtorrent
|
|||
m_pool.release(this);
|
||||
|
||||
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
|
||||
old_path = safe_convert((m_save_path / m_info->name()).string());
|
||||
new_path = safe_convert((save_path / m_info->name()).string());
|
||||
old_path = safe_convert((m_save_path / files().name()).string());
|
||||
new_path = safe_convert((save_path / files().name()).string());
|
||||
#else
|
||||
old_path = m_save_path / m_info->name();
|
||||
new_path = save_path / m_info->name();
|
||||
old_path = m_save_path / files().name();
|
||||
new_path = save_path / files().name();
|
||||
#endif
|
||||
|
||||
try
|
||||
|
@ -604,7 +604,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
entry::list_type const& slots = slots_ent->list();
|
||||
bool seed = int(slots.size()) == m_info->num_pieces()
|
||||
bool seed = int(slots.size()) == files().num_pieces()
|
||||
&& std::find_if(slots.begin(), slots.end()
|
||||
, boost::bind<bool>(std::less<int>()
|
||||
, boost::bind((size_type const& (entry::*)() const)
|
||||
|
@ -617,11 +617,11 @@ namespace libtorrent
|
|||
|
||||
if (seed)
|
||||
{
|
||||
if (m_info->num_files(true) != (int)file_sizes.size())
|
||||
if (files().num_files() != (int)file_sizes.size())
|
||||
{
|
||||
error = "the number of files does not match the torrent (num: "
|
||||
+ boost::lexical_cast<std::string>(file_sizes.size()) + " actual: "
|
||||
+ boost::lexical_cast<std::string>(m_info->num_files(true)) + ")";
|
||||
+ boost::lexical_cast<std::string>(files().num_files()) + ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -629,8 +629,8 @@ namespace libtorrent
|
|||
fs = file_sizes.begin();
|
||||
// the resume data says we have the entire torrent
|
||||
// make sure the file sizes are the right ones
|
||||
for (torrent_info::file_iterator i = m_info->begin_files(true)
|
||||
, end(m_info->end_files(true)); i != end; ++i, ++fs)
|
||||
for (file_storage::iterator i = files().begin()
|
||||
, end(files().end()); i != end; ++i, ++fs)
|
||||
{
|
||||
if (i->size != fs->first)
|
||||
{
|
||||
|
@ -643,7 +643,7 @@ namespace libtorrent
|
|||
return true;
|
||||
}
|
||||
|
||||
return match_filesizes(*m_info, m_save_path, file_sizes
|
||||
return match_filesizes(files(), m_save_path, file_sizes
|
||||
, !full_allocation_mode, &error);
|
||||
}
|
||||
|
||||
|
@ -655,7 +655,7 @@ namespace libtorrent
|
|||
return true;
|
||||
}
|
||||
std::vector<std::pair<size_type, std::time_t> > file_sizes
|
||||
= get_filesizes(*m_info, m_save_path);
|
||||
= get_filesizes(m_files, m_save_path);
|
||||
|
||||
entry::list_type& fl = rd["file sizes"].list();
|
||||
for (std::vector<std::pair<size_type, std::time_t> >::iterator i
|
||||
|
@ -672,7 +672,7 @@ namespace libtorrent
|
|||
bool move_slot(int src_slot, int dst_slot)
|
||||
{
|
||||
// TODO: this can be optimized by mapping both slots and do a straight memcpy
|
||||
int piece_size = m_info->piece_size(dst_slot);
|
||||
int piece_size = m_files.piece_size(dst_slot);
|
||||
m_scratch_buffer.resize(piece_size);
|
||||
size_type ret1 = read(&m_scratch_buffer[0], src_slot, 0, piece_size);
|
||||
size_type ret2 = write(&m_scratch_buffer[0], dst_slot, 0, piece_size);
|
||||
|
@ -683,9 +683,9 @@ namespace libtorrent
|
|||
{
|
||||
// TODO: this can be optimized by mapping both slots and do a straight memcpy
|
||||
// the size of the target slot is the size of the piece
|
||||
int piece_size = m_info->piece_length();
|
||||
int piece1_size = m_info->piece_size(slot2);
|
||||
int piece2_size = m_info->piece_size(slot1);
|
||||
int piece_size = m_files.piece_length();
|
||||
int piece1_size = m_files.piece_size(slot2);
|
||||
int piece2_size = m_files.piece_size(slot1);
|
||||
m_scratch_buffer.resize(piece_size * 2);
|
||||
size_type ret1 = read(&m_scratch_buffer[0], slot1, 0, piece1_size);
|
||||
size_type ret2 = read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size);
|
||||
|
@ -699,10 +699,10 @@ namespace libtorrent
|
|||
{
|
||||
// TODO: this can be optimized by mapping both slots and do a straight memcpy
|
||||
// the size of the target slot is the size of the piece
|
||||
int piece_size = m_info->piece_length();
|
||||
int piece1_size = m_info->piece_size(slot2);
|
||||
int piece2_size = m_info->piece_size(slot3);
|
||||
int piece3_size = m_info->piece_size(slot1);
|
||||
int piece_size = m_files.piece_length();
|
||||
int piece1_size = m_files.piece_size(slot2);
|
||||
int piece2_size = m_files.piece_size(slot3);
|
||||
int piece3_size = m_files.piece_size(slot1);
|
||||
m_scratch_buffer.resize(piece_size * 2);
|
||||
size_type ret1 = read(&m_scratch_buffer[0], slot1, 0, piece1_size);
|
||||
size_type ret2 = read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size);
|
||||
|
@ -745,6 +745,39 @@ namespace libtorrent
|
|||
#endif
|
||||
}
|
||||
|
||||
bool rename_file(int index, std::string const& new_filename)
|
||||
{
|
||||
if (index < 0 || index >= m_files.num_files()) return true;
|
||||
fs::path old_name = m_save_path / files().at(index).path;
|
||||
m_pool.release(this);
|
||||
|
||||
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
|
||||
fs::wpath old_path = safe_convert(old_name);
|
||||
fs::wpath new_path = safe_convert(m_save_path / new_filename);
|
||||
#else
|
||||
fs::path const& old_path = old_name;
|
||||
fs::path new_path = m_save_path / new_filename;
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
rename(old_path, new_path);
|
||||
if (!m_mapped_files)
|
||||
{ m_mapped_files.reset(new file_storage(m_files)); }
|
||||
m_mapped_files->rename_file(index, new_filename);
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
set_error(old_name.string(), e.what());
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool release_files()
|
||||
{
|
||||
m_pool.release(this);
|
||||
|
@ -764,8 +797,8 @@ namespace libtorrent
|
|||
// delete the files from disk
|
||||
std::set<std::string> directories;
|
||||
typedef std::set<std::string>::iterator iter_t;
|
||||
for (torrent_info::file_iterator i = m_info->begin_files(true)
|
||||
, end(m_info->end_files(true)); i != end; ++i)
|
||||
for (file_storage::iterator i = m_files.begin()
|
||||
, end(m_files.end()); i != end; ++i)
|
||||
{
|
||||
std::string p = (m_save_path / i->path).string();
|
||||
fs::path bp = i->path.branch_path();
|
||||
|
@ -804,7 +837,10 @@ namespace libtorrent
|
|||
|
||||
private:
|
||||
|
||||
boost::intrusive_ptr<torrent_info const> m_info;
|
||||
file_storage const& files() const { return m_mapped_files?*m_mapped_files:m_files; }
|
||||
|
||||
boost::scoped_ptr<file_storage> m_mapped_files;
|
||||
file_storage const& m_files;
|
||||
fs::path m_save_path;
|
||||
|
||||
// temporary storage for moving pieces
|
||||
|
@ -813,10 +849,10 @@ namespace libtorrent
|
|||
static mapped_file_pool m_pool;
|
||||
};
|
||||
|
||||
storage_interface* mapped_storage_constructor(boost::intrusive_ptr<torrent_info const> ti
|
||||
storage_interface* mapped_storage_constructor(file_storage const& fs
|
||||
, fs::path const& path, file_pool& fp)
|
||||
{
|
||||
return new mapped_storage(ti, path);
|
||||
return new mapped_storage(fs, path);
|
||||
}
|
||||
|
||||
mapped_file_pool mapped_storage::m_pool;
|
||||
|
|
|
@ -1661,7 +1661,7 @@ namespace aux {
|
|||
{
|
||||
TORRENT_ASSERT(!params.save_path.empty());
|
||||
|
||||
if (params.ti && params.ti->num_files() == 0)
|
||||
if (params.ti && params.ti->files().num_files() == 0)
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
throw std::runtime_error("no files in torrent");
|
||||
|
|
323
src/storage.cpp
323
src/storage.cpp
|
@ -251,12 +251,12 @@ namespace libtorrent
|
|||
{
|
||||
|
||||
std::vector<std::pair<size_type, std::time_t> > get_filesizes(
|
||||
torrent_info const& t, fs::path p)
|
||||
file_storage const& s, fs::path p)
|
||||
{
|
||||
p = complete(p);
|
||||
std::vector<std::pair<size_type, std::time_t> > sizes;
|
||||
for (torrent_info::file_iterator i = t.begin_files(true);
|
||||
i != t.end_files(true); ++i)
|
||||
for (file_storage::iterator i = s.begin()
|
||||
, end(s.end());i != end; ++i)
|
||||
{
|
||||
size_type size = 0;
|
||||
std::time_t time = 0;
|
||||
|
@ -289,13 +289,13 @@ namespace libtorrent
|
|||
// pieces, so any older version of the resume data will
|
||||
// still be a correct subset of the actual data on disk.
|
||||
bool match_filesizes(
|
||||
torrent_info const& t
|
||||
file_storage const& fs
|
||||
, fs::path p
|
||||
, std::vector<std::pair<size_type, std::time_t> > const& sizes
|
||||
, bool compact_mode
|
||||
, std::string* error)
|
||||
{
|
||||
if ((int)sizes.size() != t.num_files(true))
|
||||
if ((int)sizes.size() != fs.num_files())
|
||||
{
|
||||
if (error) *error = "mismatching number of files";
|
||||
return false;
|
||||
|
@ -304,8 +304,8 @@ namespace libtorrent
|
|||
|
||||
std::vector<std::pair<size_type, std::time_t> >::const_iterator s
|
||||
= sizes.begin();
|
||||
for (torrent_info::file_iterator i = t.begin_files(true);
|
||||
i != t.end_files(true); ++i, ++s)
|
||||
for (file_storage::iterator i = fs.begin()
|
||||
, end(fs.end());i != end; ++i, ++s)
|
||||
{
|
||||
size_type size = 0;
|
||||
std::time_t time = 0;
|
||||
|
@ -354,15 +354,16 @@ namespace libtorrent
|
|||
class storage : public storage_interface, boost::noncopyable
|
||||
{
|
||||
public:
|
||||
storage(boost::intrusive_ptr<torrent_info const> info, fs::path const& path, file_pool& fp)
|
||||
: m_info(info)
|
||||
, m_files(fp)
|
||||
storage(file_storage const& fs, fs::path const& path, file_pool& fp)
|
||||
: m_files(fs)
|
||||
, m_pool(fp)
|
||||
{
|
||||
TORRENT_ASSERT(info->begin_files(true) != info->end_files(true));
|
||||
TORRENT_ASSERT(m_files.begin() != m_files.end());
|
||||
m_save_path = fs::complete(path);
|
||||
TORRENT_ASSERT(m_save_path.is_complete());
|
||||
}
|
||||
|
||||
bool rename_file(int index, std::string const& new_filename);
|
||||
bool release_files();
|
||||
bool delete_files();
|
||||
bool initialize(bool allocate_files);
|
||||
|
@ -379,14 +380,18 @@ namespace libtorrent
|
|||
int read_impl(char* buf, int slot, int offset, int size, bool fill_zero);
|
||||
|
||||
~storage()
|
||||
{ m_files.release(this); }
|
||||
{ m_pool.release(this); }
|
||||
|
||||
file_storage const& files() const { return m_mapped_files?*m_mapped_files:m_files; }
|
||||
|
||||
boost::scoped_ptr<file_storage> m_mapped_files;
|
||||
file_storage const& m_files;
|
||||
|
||||
boost::intrusive_ptr<torrent_info const> m_info;
|
||||
fs::path m_save_path;
|
||||
// the file pool is typically stored in
|
||||
// the session, to make all storage
|
||||
// instances use the same pool
|
||||
file_pool& m_files;
|
||||
file_pool& m_pool;
|
||||
|
||||
// temporary storage for moving pieces
|
||||
buffer m_scratch_buffer;
|
||||
|
@ -399,7 +404,7 @@ namespace libtorrent
|
|||
hasher whole;
|
||||
int slot_size1 = piece_size;
|
||||
m_scratch_buffer.resize(slot_size1);
|
||||
int read_result = read_impl(&m_scratch_buffer[0], slot, 0, slot_size1, true);
|
||||
read_impl(&m_scratch_buffer[0], slot, 0, slot_size1, true);
|
||||
if (ph.offset > 0)
|
||||
partial.update(&m_scratch_buffer[0], ph.offset);
|
||||
whole.update(&m_scratch_buffer[0], slot_size1);
|
||||
|
@ -426,8 +431,8 @@ namespace libtorrent
|
|||
{
|
||||
// first, create all missing directories
|
||||
fs::path last_path;
|
||||
for (torrent_info::file_iterator file_iter = m_info->begin_files(true),
|
||||
end_iter = m_info->end_files(true); file_iter != end_iter; ++file_iter)
|
||||
for (file_storage::iterator file_iter = files().begin(),
|
||||
end_iter = files().end(); file_iter != end_iter; ++file_iter)
|
||||
{
|
||||
fs::path dir = (m_save_path / file_iter->path).branch_path();
|
||||
|
||||
|
@ -475,7 +480,7 @@ namespace libtorrent
|
|||
if (allocate_files)
|
||||
{
|
||||
std::string error;
|
||||
boost::shared_ptr<file> f = m_files.open_file(this
|
||||
boost::shared_ptr<file> f = m_pool.open_file(this
|
||||
, m_save_path / file_iter->path, file::in | file::out
|
||||
, error);
|
||||
if (f && f->error().empty())
|
||||
|
@ -491,13 +496,46 @@ namespace libtorrent
|
|||
#endif
|
||||
}
|
||||
// close files that were opened in write mode
|
||||
m_files.release(this);
|
||||
m_pool.release(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool storage::rename_file(int index, std::string const& new_filename)
|
||||
{
|
||||
if (index < 0 || index >= m_files.num_files()) return true;
|
||||
fs::path old_name = m_save_path / files().at(index).path;
|
||||
m_pool.release(old_name);
|
||||
|
||||
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
|
||||
fs::wpath old_path = safe_convert(old_name);
|
||||
fs::wpath new_path = safe_convert(m_save_path / new_filename);
|
||||
#else
|
||||
fs::path const& old_path = old_name;
|
||||
fs::path new_path = m_save_path / new_filename;
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try
|
||||
{
|
||||
#endif
|
||||
rename(old_path, new_path);
|
||||
if (!m_mapped_files)
|
||||
{ m_mapped_files.reset(new file_storage(m_files)); }
|
||||
m_mapped_files->rename_file(index, new_filename);
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
set_error(old_name.string(), e.what());
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool storage::release_files()
|
||||
{
|
||||
m_files.release(this);
|
||||
m_pool.release(this);
|
||||
buffer().swap(m_scratch_buffer);
|
||||
return false;
|
||||
}
|
||||
|
@ -505,7 +543,7 @@ namespace libtorrent
|
|||
bool storage::delete_files()
|
||||
{
|
||||
// make sure we don't have the files open
|
||||
m_files.release(this);
|
||||
m_pool.release(this);
|
||||
buffer().swap(m_scratch_buffer);
|
||||
|
||||
int result = 0;
|
||||
|
@ -515,8 +553,8 @@ namespace libtorrent
|
|||
// delete the files from disk
|
||||
std::set<std::string> directories;
|
||||
typedef std::set<std::string>::iterator iter_t;
|
||||
for (torrent_info::file_iterator i = m_info->begin_files(true)
|
||||
, end(m_info->end_files(true)); i != end; ++i)
|
||||
for (file_storage::iterator i = files().begin()
|
||||
, end(files().end()); i != end; ++i)
|
||||
{
|
||||
std::string p = (m_save_path / i->path).string();
|
||||
fs::path bp = i->path.branch_path();
|
||||
|
@ -584,7 +622,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(rd.type() == entry::dictionary_t);
|
||||
|
||||
std::vector<std::pair<size_type, std::time_t> > file_sizes
|
||||
= get_filesizes(*m_info, m_save_path);
|
||||
= get_filesizes(files(), m_save_path);
|
||||
|
||||
entry::list_type& fl = rd["file sizes"].list();
|
||||
for (std::vector<std::pair<size_type, std::time_t> >::iterator i
|
||||
|
@ -642,7 +680,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
entry::list_type const& slots = slots_ent->list();
|
||||
bool seed = int(slots.size()) == m_info->num_pieces()
|
||||
bool seed = int(slots.size()) == m_files.num_pieces()
|
||||
&& std::find_if(slots.begin(), slots.end()
|
||||
, boost::bind<bool>(std::less<int>()
|
||||
, boost::bind((size_type const& (entry::*)() const)
|
||||
|
@ -655,11 +693,11 @@ namespace libtorrent
|
|||
|
||||
if (seed)
|
||||
{
|
||||
if (m_info->num_files(true) != (int)file_sizes.size())
|
||||
if (m_files.num_files() != (int)file_sizes.size())
|
||||
{
|
||||
error = "the number of files does not match the torrent (num: "
|
||||
+ boost::lexical_cast<std::string>(file_sizes.size()) + " actual: "
|
||||
+ boost::lexical_cast<std::string>(m_info->num_files(true)) + ")";
|
||||
+ boost::lexical_cast<std::string>(m_files.num_files()) + ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -667,8 +705,8 @@ namespace libtorrent
|
|||
fs = file_sizes.begin();
|
||||
// the resume data says we have the entire torrent
|
||||
// make sure the file sizes are the right ones
|
||||
for (torrent_info::file_iterator i = m_info->begin_files(true)
|
||||
, end(m_info->end_files(true)); i != end; ++i, ++fs)
|
||||
for (file_storage::iterator i = files().begin()
|
||||
, end(files().end()); i != end; ++i, ++fs)
|
||||
{
|
||||
if (i->size != fs->first)
|
||||
{
|
||||
|
@ -680,7 +718,7 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
return match_filesizes(*m_info, m_save_path, file_sizes
|
||||
return match_filesizes(files(), m_save_path, file_sizes
|
||||
, !full_allocation_mode, &error);
|
||||
}
|
||||
|
||||
|
@ -716,14 +754,14 @@ namespace libtorrent
|
|||
return false;
|
||||
#endif
|
||||
|
||||
m_files.release(this);
|
||||
m_pool.release(this);
|
||||
|
||||
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
|
||||
old_path = safe_convert((m_save_path / m_info->name()).string());
|
||||
new_path = safe_convert((save_path / m_info->name()).string());
|
||||
old_path = safe_convert((m_save_path / files().name()).string());
|
||||
new_path = safe_convert((save_path / files().name()).string());
|
||||
#else
|
||||
old_path = m_save_path / m_info->name();
|
||||
new_path = save_path / m_info->name();
|
||||
old_path = m_save_path / files().name();
|
||||
new_path = save_path / files().name();
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
|
@ -740,16 +778,20 @@ namespace libtorrent
|
|||
return true;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch (std::exception&) {}
|
||||
return false;
|
||||
catch (std::exception& e)
|
||||
{
|
||||
set_error((m_save_path / files().name()).string(), e.what());
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
void storage::shuffle()
|
||||
{
|
||||
int num_pieces = m_info->num_pieces();
|
||||
int num_pieces = files().num_pieces();
|
||||
|
||||
std::vector<int> pieces(num_pieces);
|
||||
for (std::vector<int>::iterator i = pieces.begin();
|
||||
|
@ -766,7 +808,7 @@ namespace libtorrent
|
|||
{
|
||||
const int slot_index = targets[i];
|
||||
const int piece_index = pieces[i];
|
||||
const int slot_size =static_cast<int>(m_info->piece_size(slot_index));
|
||||
const int slot_size =static_cast<int>(m_files.piece_size(slot_index));
|
||||
std::vector<char> buf(slot_size);
|
||||
read(&buf[0], piece_index, 0, slot_size);
|
||||
write(&buf[0], slot_index, 0, slot_size);
|
||||
|
@ -777,7 +819,7 @@ namespace libtorrent
|
|||
|
||||
bool storage::move_slot(int src_slot, int dst_slot)
|
||||
{
|
||||
int piece_size = m_info->piece_size(dst_slot);
|
||||
int piece_size = m_files.piece_size(dst_slot);
|
||||
m_scratch_buffer.resize(piece_size);
|
||||
int ret1 = read_impl(&m_scratch_buffer[0], src_slot, 0, piece_size, true);
|
||||
int ret2 = write(&m_scratch_buffer[0], dst_slot, 0, piece_size);
|
||||
|
@ -787,9 +829,9 @@ namespace libtorrent
|
|||
bool storage::swap_slots(int slot1, int slot2)
|
||||
{
|
||||
// the size of the target slot is the size of the piece
|
||||
int piece_size = m_info->piece_length();
|
||||
int piece1_size = m_info->piece_size(slot2);
|
||||
int piece2_size = m_info->piece_size(slot1);
|
||||
int piece_size = m_files.piece_length();
|
||||
int piece1_size = m_files.piece_size(slot2);
|
||||
int piece2_size = m_files.piece_size(slot1);
|
||||
m_scratch_buffer.resize(piece_size * 2);
|
||||
int ret1 = read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true);
|
||||
int ret2 = read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true);
|
||||
|
@ -802,10 +844,10 @@ namespace libtorrent
|
|||
bool storage::swap_slots3(int slot1, int slot2, int slot3)
|
||||
{
|
||||
// the size of the target slot is the size of the piece
|
||||
int piece_size = m_info->piece_length();
|
||||
int piece1_size = m_info->piece_size(slot2);
|
||||
int piece2_size = m_info->piece_size(slot3);
|
||||
int piece3_size = m_info->piece_size(slot1);
|
||||
int piece_size = m_files.piece_length();
|
||||
int piece1_size = m_files.piece_size(slot2);
|
||||
int piece2_size = m_files.piece_size(slot3);
|
||||
int piece3_size = m_files.piece_size(slot1);
|
||||
m_scratch_buffer.resize(piece_size * 2);
|
||||
int ret1 = read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true);
|
||||
int ret2 = read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true);
|
||||
|
@ -835,25 +877,25 @@ namespace libtorrent
|
|||
, bool fill_zero)
|
||||
{
|
||||
TORRENT_ASSERT(buf != 0);
|
||||
TORRENT_ASSERT(slot >= 0 && slot < m_info->num_pieces());
|
||||
TORRENT_ASSERT(slot >= 0 && slot < m_files.num_pieces());
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(offset < m_info->piece_size(slot));
|
||||
TORRENT_ASSERT(offset < m_files.piece_size(slot));
|
||||
TORRENT_ASSERT(size > 0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::vector<file_slice> slices
|
||||
= m_info->map_block(slot, offset, size, true);
|
||||
= files().map_block(slot, offset, size);
|
||||
TORRENT_ASSERT(!slices.empty());
|
||||
#endif
|
||||
|
||||
size_type start = slot * (size_type)m_info->piece_length() + offset;
|
||||
TORRENT_ASSERT(start + size <= m_info->total_size());
|
||||
size_type start = slot * (size_type)m_files.piece_length() + offset;
|
||||
TORRENT_ASSERT(start + size <= m_files.total_size());
|
||||
|
||||
// find the file iterator and file offset
|
||||
size_type file_offset = start;
|
||||
std::vector<file_entry>::const_iterator file_iter;
|
||||
|
||||
for (file_iter = m_info->begin_files(true);;)
|
||||
for (file_iter = files().begin();;)
|
||||
{
|
||||
if (file_offset < file_iter->size)
|
||||
break;
|
||||
|
@ -864,7 +906,7 @@ namespace libtorrent
|
|||
|
||||
int buf_pos = 0;
|
||||
std::string error;
|
||||
boost::shared_ptr<file> in(m_files.open_file(
|
||||
boost::shared_ptr<file> in(m_pool.open_file(
|
||||
this, m_save_path / file_iter->path, file::in
|
||||
, error));
|
||||
if (!in)
|
||||
|
@ -899,7 +941,7 @@ namespace libtorrent
|
|||
#endif
|
||||
|
||||
int left_to_read = size;
|
||||
int slot_size = static_cast<int>(m_info->piece_size(slot));
|
||||
int slot_size = static_cast<int>(m_files.piece_size(slot));
|
||||
|
||||
if (offset + left_to_read > slot_size)
|
||||
left_to_read = slot_size - offset;
|
||||
|
@ -924,7 +966,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(int(slices.size()) > counter);
|
||||
size_type slice_size = slices[counter].size;
|
||||
TORRENT_ASSERT(slice_size == read_bytes);
|
||||
TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path
|
||||
TORRENT_ASSERT(files().at(slices[counter].file_index).path
|
||||
== file_iter->path);
|
||||
#endif
|
||||
|
||||
|
@ -961,7 +1003,7 @@ namespace libtorrent
|
|||
|
||||
file_offset = 0;
|
||||
std::string error;
|
||||
in = m_files.open_file(
|
||||
in = m_pool.open_file(
|
||||
this, path, file::in, error);
|
||||
if (!in)
|
||||
{
|
||||
|
@ -997,35 +1039,35 @@ namespace libtorrent
|
|||
{
|
||||
TORRENT_ASSERT(buf != 0);
|
||||
TORRENT_ASSERT(slot >= 0);
|
||||
TORRENT_ASSERT(slot < m_info->num_pieces());
|
||||
TORRENT_ASSERT(slot < m_files.num_pieces());
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(size > 0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
std::vector<file_slice> slices
|
||||
= m_info->map_block(slot, offset, size, true);
|
||||
= files().map_block(slot, offset, size);
|
||||
TORRENT_ASSERT(!slices.empty());
|
||||
#endif
|
||||
|
||||
size_type start = slot * (size_type)m_info->piece_length() + offset;
|
||||
size_type start = slot * (size_type)m_files.piece_length() + offset;
|
||||
|
||||
// find the file iterator and file offset
|
||||
size_type file_offset = start;
|
||||
std::vector<file_entry>::const_iterator file_iter;
|
||||
|
||||
for (file_iter = m_info->begin_files(true);;)
|
||||
for (file_iter = files().begin();;)
|
||||
{
|
||||
if (file_offset < file_iter->size)
|
||||
break;
|
||||
|
||||
file_offset -= file_iter->size;
|
||||
++file_iter;
|
||||
TORRENT_ASSERT(file_iter != m_info->end_files(true));
|
||||
TORRENT_ASSERT(file_iter != files().end());
|
||||
}
|
||||
|
||||
fs::path p(m_save_path / file_iter->path);
|
||||
std::string error;
|
||||
boost::shared_ptr<file> out = m_files.open_file(
|
||||
boost::shared_ptr<file> out = m_pool.open_file(
|
||||
this, p, file::out | file::in, error);
|
||||
|
||||
if (!out)
|
||||
|
@ -1050,7 +1092,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
int left_to_write = size;
|
||||
int slot_size = static_cast<int>(m_info->piece_size(slot));
|
||||
int slot_size = static_cast<int>(m_files.piece_size(slot));
|
||||
|
||||
if (offset + left_to_write > slot_size)
|
||||
left_to_write = slot_size - offset;
|
||||
|
@ -1074,7 +1116,7 @@ namespace libtorrent
|
|||
{
|
||||
TORRENT_ASSERT(int(slices.size()) > counter);
|
||||
TORRENT_ASSERT(slices[counter].size == write_bytes);
|
||||
TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path
|
||||
TORRENT_ASSERT(files().at(slices[counter].file_index).path
|
||||
== file_iter->path);
|
||||
|
||||
TORRENT_ASSERT(buf_pos >= 0);
|
||||
|
@ -1101,11 +1143,11 @@ namespace libtorrent
|
|||
#endif
|
||||
++file_iter;
|
||||
|
||||
TORRENT_ASSERT(file_iter != m_info->end_files(true));
|
||||
TORRENT_ASSERT(file_iter != files().end());
|
||||
fs::path p = m_save_path / file_iter->path;
|
||||
file_offset = 0;
|
||||
std::string error;
|
||||
out = m_files.open_file(
|
||||
out = m_pool.open_file(
|
||||
this, p, file::out | file::in, error);
|
||||
|
||||
if (!out)
|
||||
|
@ -1131,25 +1173,26 @@ namespace libtorrent
|
|||
return size;
|
||||
}
|
||||
|
||||
storage_interface* default_storage_constructor(boost::intrusive_ptr<torrent_info const> ti
|
||||
storage_interface* default_storage_constructor(file_storage const& fs
|
||||
, fs::path const& path, file_pool& fp)
|
||||
{
|
||||
return new storage(ti, path, fp);
|
||||
return new storage(fs, path, fp);
|
||||
}
|
||||
|
||||
// -- piece_manager -----------------------------------------------------
|
||||
|
||||
piece_manager::piece_manager(
|
||||
boost::shared_ptr<void> const& torrent
|
||||
, boost::intrusive_ptr<torrent_info const> ti
|
||||
, boost::intrusive_ptr<torrent_info const> info
|
||||
, fs::path const& save_path
|
||||
, file_pool& fp
|
||||
, disk_io_thread& io
|
||||
, storage_constructor_type sc
|
||||
, storage_mode_t sm)
|
||||
: m_storage(sc(ti, save_path, fp))
|
||||
: m_info(info)
|
||||
, m_files(m_info->files())
|
||||
, m_storage(sc(m_files, save_path, fp))
|
||||
, m_storage_mode(sm)
|
||||
, m_info(ti)
|
||||
, m_save_path(complete(save_path))
|
||||
, m_state(state_none)
|
||||
, m_current_slot(0)
|
||||
|
@ -1213,6 +1256,17 @@ namespace libtorrent
|
|||
m_io_thread.add_job(j, handler);
|
||||
}
|
||||
|
||||
void piece_manager::async_rename_file(int index, std::string const& name
|
||||
, boost::function<void(int, disk_io_job const&)> const& handler)
|
||||
{
|
||||
disk_io_job j;
|
||||
j.storage = this;
|
||||
j.piece = index;
|
||||
j.str = name;
|
||||
j.action = disk_io_job::rename_file;
|
||||
m_io_thread.add_job(j, handler);
|
||||
}
|
||||
|
||||
void piece_manager::async_check_files(
|
||||
boost::function<void(int, disk_io_job const&)> const& handler)
|
||||
{
|
||||
|
@ -1241,6 +1295,8 @@ namespace libtorrent
|
|||
m_io_thread.add_job(j, handler);
|
||||
#ifndef NDEBUG
|
||||
boost::recursive_mutex::scoped_lock l(m_mutex);
|
||||
// if this assert is hit, it suggests
|
||||
// that check_files was not successful
|
||||
TORRENT_ASSERT(slot_for(r.piece) >= 0);
|
||||
#endif
|
||||
}
|
||||
|
@ -1295,7 +1351,7 @@ namespace libtorrent
|
|||
|
||||
int slot = slot_for(piece);
|
||||
TORRENT_ASSERT(slot != has_no_slot);
|
||||
return m_storage->hash_for_slot(slot, ph, m_info->piece_size(piece));
|
||||
return m_storage->hash_for_slot(slot, ph, m_files.piece_size(piece));
|
||||
}
|
||||
|
||||
bool piece_manager::move_storage_impl(fs::path const& save_path)
|
||||
|
@ -1373,7 +1429,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(buf);
|
||||
TORRENT_ASSERT(offset >= 0);
|
||||
TORRENT_ASSERT(size > 0);
|
||||
TORRENT_ASSERT(piece_index >= 0 && piece_index < m_info->num_pieces());
|
||||
TORRENT_ASSERT(piece_index >= 0 && piece_index < m_files.num_pieces());
|
||||
|
||||
int slot = allocate_slot_for_piece(piece_index);
|
||||
int ret = m_storage->write(buf, slot, offset, size);
|
||||
|
@ -1455,9 +1511,9 @@ namespace libtorrent
|
|||
{
|
||||
// INVARIANT_CHECK;
|
||||
|
||||
const int piece_size = static_cast<int>(m_info->piece_length());
|
||||
const int last_piece_size = static_cast<int>(m_info->piece_size(
|
||||
m_info->num_pieces() - 1));
|
||||
const int piece_size = static_cast<int>(m_files.piece_length());
|
||||
const int last_piece_size = static_cast<int>(m_files.piece_size(
|
||||
m_files.num_pieces() - 1));
|
||||
|
||||
TORRENT_ASSERT((int)piece_data.size() >= last_piece_size);
|
||||
|
||||
|
@ -1579,8 +1635,8 @@ namespace libtorrent
|
|||
|
||||
int piece_manager::check_no_fastresume(std::string& error)
|
||||
{
|
||||
torrent_info::file_iterator i = m_info->begin_files(true);
|
||||
torrent_info::file_iterator end = m_info->end_files(true);
|
||||
file_storage::iterator i = m_files.begin();
|
||||
file_storage::iterator end = m_files.end();
|
||||
|
||||
for (; i != end; ++i)
|
||||
{
|
||||
|
@ -1612,9 +1668,9 @@ namespace libtorrent
|
|||
{
|
||||
m_state = state_full_check;
|
||||
m_piece_to_slot.clear();
|
||||
m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot);
|
||||
m_piece_to_slot.resize(m_files.num_pieces(), has_no_slot);
|
||||
m_slot_to_piece.clear();
|
||||
m_slot_to_piece.resize(m_info->num_pieces(), unallocated);
|
||||
m_slot_to_piece.resize(m_files.num_pieces(), unallocated);
|
||||
if (m_storage_mode == storage_mode_compact)
|
||||
{
|
||||
m_unallocated_slots.clear();
|
||||
|
@ -1629,12 +1685,12 @@ namespace libtorrent
|
|||
// in compact mode without checking, we need to
|
||||
// populate the unallocated list
|
||||
TORRENT_ASSERT(m_unallocated_slots.empty());
|
||||
for (int i = 0, end(m_info->num_pieces()); i < end; ++i)
|
||||
for (int i = 0, end(m_files.num_pieces()); i < end; ++i)
|
||||
m_unallocated_slots.push_back(i);
|
||||
m_piece_to_slot.clear();
|
||||
m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot);
|
||||
m_piece_to_slot.resize(m_files.num_pieces(), has_no_slot);
|
||||
m_slot_to_piece.clear();
|
||||
m_slot_to_piece.resize(m_info->num_pieces(), unallocated);
|
||||
m_slot_to_piece.resize(m_files.num_pieces(), unallocated);
|
||||
}
|
||||
|
||||
return check_init_storage(error);
|
||||
|
@ -1675,7 +1731,7 @@ namespace libtorrent
|
|||
|
||||
INVARIANT_CHECK;
|
||||
|
||||
TORRENT_ASSERT(m_info->piece_length() > 0);
|
||||
TORRENT_ASSERT(m_files.piece_length() > 0);
|
||||
|
||||
// if we don't have any resume data, return
|
||||
if (rd.type() == entry::undefined_t) return check_no_fastresume(error);
|
||||
|
@ -1686,38 +1742,11 @@ namespace libtorrent
|
|||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
entry const* file_format = rd.find_key("file-format");
|
||||
|
||||
if (file_format == 0 || file_format->type() != entry::string_t)
|
||||
{
|
||||
error = "missing file format tag";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
if (file_format->string() != "libtorrent resume file")
|
||||
{
|
||||
error = "invalid file format tag";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
entry const* info_hash = rd.find_key("info-hash");
|
||||
if (info_hash == 0 || info_hash->type() != entry::string_t)
|
||||
{
|
||||
error = "missing info-hash";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
if (sha1_hash(info_hash->string()) != m_info->info_hash())
|
||||
{
|
||||
error = "mismatching info-hash";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
int block_size = (std::min)(16 * 1024, m_info->piece_length());
|
||||
int block_size = (std::min)(16 * 1024, m_files.piece_length());
|
||||
entry const* blocks_per_piece_ent = rd.find_key("blocks per piece");
|
||||
if (blocks_per_piece_ent != 0
|
||||
&& blocks_per_piece_ent->type() == entry::int_t
|
||||
&& blocks_per_piece_ent->integer() != m_info->piece_length() / block_size)
|
||||
&& blocks_per_piece_ent->integer() != m_files.piece_length() / block_size)
|
||||
{
|
||||
error = "invalid 'blocks per piece' entry";
|
||||
return check_no_fastresume(error);
|
||||
|
@ -1746,17 +1775,17 @@ namespace libtorrent
|
|||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
if ((int)slots->list().size() > m_info->num_pieces())
|
||||
if ((int)slots->list().size() > m_files.num_pieces())
|
||||
{
|
||||
error = "file has more slots than torrent (slots: "
|
||||
+ boost::lexical_cast<std::string>(slots->list().size()) + " size: "
|
||||
+ boost::lexical_cast<std::string>(m_info->num_pieces()) + " )";
|
||||
+ boost::lexical_cast<std::string>(m_files.num_pieces()) + " )";
|
||||
return check_no_fastresume(error);
|
||||
}
|
||||
|
||||
if (storage_mode == storage_mode_compact)
|
||||
{
|
||||
int num_pieces = int(m_info->num_pieces());
|
||||
int num_pieces = int(m_files.num_pieces());
|
||||
m_slot_to_piece.resize(num_pieces, unallocated);
|
||||
m_piece_to_slot.resize(num_pieces, has_no_slot);
|
||||
int slot = 0;
|
||||
|
@ -1877,7 +1906,7 @@ namespace libtorrent
|
|||
// is finished
|
||||
int piece_manager::check_files(int& current_slot, int& have_piece, std::string& error)
|
||||
{
|
||||
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_info->num_pieces());
|
||||
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces());
|
||||
|
||||
current_slot = m_current_slot;
|
||||
have_piece = -1;
|
||||
|
@ -1894,9 +1923,9 @@ namespace libtorrent
|
|||
if (other_piece >= 0)
|
||||
{
|
||||
if (m_scratch_buffer2.empty())
|
||||
m_scratch_buffer2.resize(m_info->piece_length());
|
||||
m_scratch_buffer2.resize(m_files.piece_length());
|
||||
|
||||
int piece_size = m_info->piece_size(other_piece);
|
||||
int piece_size = m_files.piece_size(other_piece);
|
||||
if (m_storage->read(&m_scratch_buffer2[0], piece, 0, piece_size)
|
||||
!= piece_size)
|
||||
{
|
||||
|
@ -1910,7 +1939,7 @@ namespace libtorrent
|
|||
|
||||
// the slot where this piece belongs is
|
||||
// free. Just move the piece there.
|
||||
int piece_size = m_info->piece_size(piece);
|
||||
int piece_size = m_files.piece_size(piece);
|
||||
if (m_storage->write(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size)
|
||||
{
|
||||
error = m_storage->error();
|
||||
|
@ -1926,19 +1955,19 @@ namespace libtorrent
|
|||
return need_full_check;
|
||||
}
|
||||
|
||||
while (m_current_slot < m_info->num_pieces()
|
||||
while (m_current_slot < m_files.num_pieces()
|
||||
&& (m_slot_to_piece[m_current_slot] == m_current_slot
|
||||
|| m_slot_to_piece[m_current_slot] < 0))
|
||||
{
|
||||
++m_current_slot;
|
||||
}
|
||||
|
||||
if (m_current_slot == m_info->num_pieces())
|
||||
if (m_current_slot == m_files.num_pieces())
|
||||
{
|
||||
return check_init_storage(error);
|
||||
}
|
||||
|
||||
TORRENT_ASSERT(m_current_slot < m_info->num_pieces());
|
||||
TORRENT_ASSERT(m_current_slot < m_files.num_pieces());
|
||||
|
||||
int piece = m_slot_to_piece[m_current_slot];
|
||||
TORRENT_ASSERT(piece >= 0);
|
||||
|
@ -1949,9 +1978,9 @@ namespace libtorrent
|
|||
// where this one goes. Store it in the scratch
|
||||
// buffer until next iteration.
|
||||
if (m_scratch_buffer.empty())
|
||||
m_scratch_buffer.resize(m_info->piece_length());
|
||||
m_scratch_buffer.resize(m_files.piece_length());
|
||||
|
||||
int piece_size = m_info->piece_size(other_piece);
|
||||
int piece_size = m_files.piece_size(other_piece);
|
||||
if (m_storage->read(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size)
|
||||
{
|
||||
error = m_storage->error();
|
||||
|
@ -1975,7 +2004,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(m_state == state_full_check);
|
||||
|
||||
bool skip = check_one_piece(have_piece);
|
||||
TORRENT_ASSERT(m_current_slot <= m_info->num_pieces());
|
||||
TORRENT_ASSERT(m_current_slot <= m_files.num_pieces());
|
||||
|
||||
if (skip)
|
||||
{
|
||||
|
@ -1984,9 +2013,9 @@ namespace libtorrent
|
|||
// completely. We should skip all pieces belonging to that file.
|
||||
// find the file that failed, and skip all the pieces in that file
|
||||
size_type file_offset = 0;
|
||||
size_type current_offset = size_type(m_current_slot) * m_info->piece_length();
|
||||
for (torrent_info::file_iterator i = m_info->begin_files(true);
|
||||
i != m_info->end_files(true); ++i)
|
||||
size_type current_offset = size_type(m_current_slot) * m_files.piece_length();
|
||||
for (file_storage::iterator i = m_files.begin()
|
||||
, end(m_files.end()); i != end; ++i)
|
||||
{
|
||||
file_offset += i->size;
|
||||
if (file_offset > current_offset) break;
|
||||
|
@ -1994,8 +2023,8 @@ namespace libtorrent
|
|||
|
||||
TORRENT_ASSERT(file_offset > current_offset);
|
||||
int skip_blocks = static_cast<int>(
|
||||
(file_offset - current_offset + m_info->piece_length() - 1)
|
||||
/ m_info->piece_length());
|
||||
(file_offset - current_offset + m_files.piece_length() - 1)
|
||||
/ m_files.piece_length());
|
||||
|
||||
if (m_storage_mode == storage_mode_compact)
|
||||
{
|
||||
|
@ -2008,15 +2037,15 @@ namespace libtorrent
|
|||
|
||||
// current slot will increase by one at the end of the for-loop too
|
||||
m_current_slot += skip_blocks - 1;
|
||||
TORRENT_ASSERT(m_current_slot <= m_info->num_pieces());
|
||||
TORRENT_ASSERT(m_current_slot <= m_files.num_pieces());
|
||||
}
|
||||
|
||||
++m_current_slot;
|
||||
current_slot = m_current_slot;
|
||||
|
||||
if (m_current_slot >= m_info->num_pieces())
|
||||
if (m_current_slot >= m_files.num_pieces())
|
||||
{
|
||||
TORRENT_ASSERT(m_current_slot == m_info->num_pieces());
|
||||
TORRENT_ASSERT(m_current_slot == m_files.num_pieces());
|
||||
|
||||
// clear the memory we've been using
|
||||
std::vector<char>().swap(m_piece_data);
|
||||
|
@ -2059,19 +2088,19 @@ namespace libtorrent
|
|||
// DO THE FULL CHECK
|
||||
// ------------------------
|
||||
|
||||
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_info->num_pieces());
|
||||
TORRENT_ASSERT(int(m_slot_to_piece.size()) == m_info->num_pieces());
|
||||
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces());
|
||||
TORRENT_ASSERT(int(m_slot_to_piece.size()) == m_files.num_pieces());
|
||||
TORRENT_ASSERT(have_piece == -1);
|
||||
|
||||
// initialization for the full check
|
||||
if (m_hash_to_piece.empty())
|
||||
{
|
||||
for (int i = 0; i < m_info->num_pieces(); ++i)
|
||||
for (int i = 0; i < m_files.num_pieces(); ++i)
|
||||
m_hash_to_piece.insert(std::make_pair(m_info->hash_for_piece(i), i));
|
||||
}
|
||||
|
||||
m_piece_data.resize(int(m_info->piece_length()));
|
||||
int piece_size = m_info->piece_size(m_current_slot);
|
||||
m_piece_data.resize(int(m_files.piece_length()));
|
||||
int piece_size = m_files.piece_size(m_current_slot);
|
||||
int num_read = m_storage->read(&m_piece_data[0]
|
||||
, m_current_slot, 0, piece_size);
|
||||
|
||||
|
@ -2348,7 +2377,7 @@ namespace libtorrent
|
|||
|
||||
// special case to make sure we don't use the last slot
|
||||
// when we shouldn't, since it's smaller than ordinary slots
|
||||
if (*iter == m_info->num_pieces() - 1 && piece_index != *iter)
|
||||
if (*iter == m_files.num_pieces() - 1 && piece_index != *iter)
|
||||
{
|
||||
if (m_free_slots.size() == 1)
|
||||
allocate_slots(1);
|
||||
|
@ -2481,14 +2510,14 @@ namespace libtorrent
|
|||
{
|
||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||
|
||||
TORRENT_ASSERT(m_current_slot <= m_info->num_pieces());
|
||||
TORRENT_ASSERT(m_current_slot <= m_files.num_pieces());
|
||||
|
||||
if (m_unallocated_slots.empty()
|
||||
&& m_free_slots.empty()
|
||||
&& m_state == state_finished)
|
||||
{
|
||||
TORRENT_ASSERT(m_storage_mode != storage_mode_compact
|
||||
|| m_info->num_pieces() == 0);
|
||||
|| m_files.num_pieces() == 0);
|
||||
}
|
||||
|
||||
if (m_storage_mode != storage_mode_compact)
|
||||
|
@ -2508,8 +2537,8 @@ namespace libtorrent
|
|||
{
|
||||
if (m_piece_to_slot.empty()) return;
|
||||
|
||||
TORRENT_ASSERT((int)m_piece_to_slot.size() == m_info->num_pieces());
|
||||
TORRENT_ASSERT((int)m_slot_to_piece.size() == m_info->num_pieces());
|
||||
TORRENT_ASSERT((int)m_piece_to_slot.size() == m_files.num_pieces());
|
||||
TORRENT_ASSERT((int)m_slot_to_piece.size() == m_files.num_pieces());
|
||||
|
||||
for (std::vector<int>::const_iterator i = m_free_slots.begin();
|
||||
i != m_free_slots.end(); ++i)
|
||||
|
@ -2531,7 +2560,7 @@ namespace libtorrent
|
|||
== m_unallocated_slots.end());
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_info->num_pieces(); ++i)
|
||||
for (int i = 0; i < m_files.num_pieces(); ++i)
|
||||
{
|
||||
// Check domain of piece_to_slot's elements
|
||||
if (m_piece_to_slot[i] != has_no_slot)
|
||||
|
@ -2620,7 +2649,7 @@ namespace libtorrent
|
|||
|
||||
s << "index\tslot\tpiece\n";
|
||||
|
||||
for (int i = 0; i < m_info->num_pieces(); ++i)
|
||||
for (int i = 0; i < m_files.num_pieces(); ++i)
|
||||
{
|
||||
s << i << "\t" << m_slot_to_piece[i] << "\t";
|
||||
s << m_piece_to_slot[i] << "\n";
|
||||
|
|
|
@ -424,7 +424,33 @@ namespace libtorrent
|
|||
|
||||
m_state = torrent_status::queued_for_checking;
|
||||
|
||||
if (m_resume_data.type() == entry::dictionary_t) read_resume_data(m_resume_data);
|
||||
if (m_resume_data.type() == entry::dictionary_t)
|
||||
{
|
||||
char const* error = 0;
|
||||
entry const* file_format = m_resume_data.find_key("file-format");
|
||||
if (file_format->string() != "libtorrent resume file")
|
||||
error = "invalid file format tag";
|
||||
|
||||
entry const* info_hash = m_resume_data.find_key("info-hash");
|
||||
if (!error && (info_hash == 0 || info_hash->type() != entry::string_t))
|
||||
error = "missing info-hash";
|
||||
|
||||
if (!error && sha1_hash(info_hash->string()) != m_torrent_file->info_hash())
|
||||
error = "mismatching info-hash";
|
||||
|
||||
if (error && m_ses.m_alerts.should_post(alert::warning))
|
||||
{
|
||||
m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), error));
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_ses.m_logger) << "fastresume data for "
|
||||
<< torrent_file().name() << " rejected: "
|
||||
<< error << "\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
if (error) m_resume_data = entry();
|
||||
else read_resume_data(m_resume_data);
|
||||
}
|
||||
|
||||
m_storage->async_check_fastresume(&m_resume_data
|
||||
, bind(&torrent::on_resume_data_checked
|
||||
|
@ -1425,6 +1451,21 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void torrent::on_file_renamed(int ret, disk_io_job const& j)
|
||||
{
|
||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||
|
||||
if (alerts().should_post(alert::warning))
|
||||
{
|
||||
|
||||
if (ret == 0)
|
||||
alerts().post_alert(file_renamed_alert(get_handle(), j.str
|
||||
, "renamed file: " + j.str));
|
||||
else
|
||||
alerts().post_alert(file_renamed_alert(get_handle(), "", j.str));
|
||||
}
|
||||
}
|
||||
|
||||
void torrent::on_torrent_paused(int ret, disk_io_job const& j)
|
||||
{
|
||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||
|
@ -1619,7 +1660,7 @@ namespace libtorrent
|
|||
for (int i = 0; i < int(files.size()); ++i)
|
||||
{
|
||||
size_type start = position;
|
||||
size_type size = m_torrent_file->file_at(i).size;
|
||||
size_type size = m_torrent_file->files().at(i).size;
|
||||
if (size == 0) continue;
|
||||
position += size;
|
||||
// mark all pieces of the file with this file's priority
|
||||
|
@ -1750,7 +1791,7 @@ namespace libtorrent
|
|||
for (int i = 0; i < (int)bitmask.size(); ++i)
|
||||
{
|
||||
size_type start = position;
|
||||
position += m_torrent_file->file_at(i).size;
|
||||
position += m_torrent_file->files().at(i).size;
|
||||
// is the file selected for download?
|
||||
if (!bitmask[i])
|
||||
{
|
||||
|
@ -3148,6 +3189,20 @@ namespace libtorrent
|
|||
return m_save_path;
|
||||
}
|
||||
|
||||
bool torrent::rename_file(int index, std::string const& name)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
TORRENT_ASSERT(index >= 0);
|
||||
TORRENT_ASSERT(index < m_torrent_file->num_files());
|
||||
|
||||
if (!m_owning_storage.get()) return false;
|
||||
|
||||
m_owning_storage->async_rename_file(index, name
|
||||
, bind(&torrent::on_file_renamed, shared_from_this(), _1, _2));
|
||||
return true;
|
||||
}
|
||||
|
||||
void torrent::move_storage(fs::path const& save_path)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
@ -3770,8 +3825,8 @@ namespace libtorrent
|
|||
|
||||
for (int i = 0; i < m_torrent_file->num_files(); ++i)
|
||||
{
|
||||
peer_request ret = m_torrent_file->map_file(i, 0, 0);
|
||||
size_type size = m_torrent_file->file_at(i).size;
|
||||
peer_request ret = m_torrent_file->files().map_file(i, 0, 0);
|
||||
size_type size = m_torrent_file->files().at(i).size;
|
||||
|
||||
// zero sized files are considered
|
||||
// 100% done all the time
|
||||
|
@ -3793,7 +3848,7 @@ namespace libtorrent
|
|||
}
|
||||
TORRENT_ASSERT(size == 0);
|
||||
|
||||
fp[i] = static_cast<float>(done) / m_torrent_file->file_at(i).size;
|
||||
fp[i] = static_cast<float>(done) / m_torrent_file->files().at(i).size;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -215,6 +215,12 @@ namespace libtorrent
|
|||
TORRENT_FORWARD(move_storage(save_path));
|
||||
}
|
||||
|
||||
void torrent_handle::rename_file(int index, fs::path const& new_name) const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
TORRENT_FORWARD(rename_file(index, new_name.string()));
|
||||
}
|
||||
|
||||
void torrent_handle::add_extension(
|
||||
boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext
|
||||
, void* userdata)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2008, Arvid Norberg
|
||||
Copyright (c) 2003-2008, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -153,11 +153,7 @@ namespace
|
|||
// save the original encoding and replace the
|
||||
// commonly used path with the correctly
|
||||
// encoded string
|
||||
if (!valid_encoding)
|
||||
{
|
||||
target.orig_path.reset(new fs::path(target.path));
|
||||
target.path = tmp_path;
|
||||
}
|
||||
if (!valid_encoding) target.path = tmp_path;
|
||||
}
|
||||
|
||||
bool extract_single_file(lazy_entry const& dict, file_entry& target
|
||||
|
@ -194,40 +190,26 @@ namespace
|
|||
return true;
|
||||
}
|
||||
|
||||
bool extract_files(lazy_entry const& list, std::vector<file_entry>& target
|
||||
bool extract_files(lazy_entry const& list, file_storage& target
|
||||
, std::string const& root_dir)
|
||||
{
|
||||
size_type offset = 0;
|
||||
if (list.type() != lazy_entry::list_t) return false;
|
||||
for (int i = 0, end(list.list_size()); i < end; ++i)
|
||||
{
|
||||
target.push_back(file_entry());
|
||||
if (!extract_single_file(*list.list_at(i), target.back(), root_dir))
|
||||
file_entry e;
|
||||
if (!extract_single_file(*list.list_at(i), e, root_dir))
|
||||
return false;
|
||||
target.back().offset = offset;
|
||||
offset += target.back().size;
|
||||
target.add_file(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
void remove_dir(fs::path& p)
|
||||
{
|
||||
TORRENT_ASSERT(p.begin() != p.end());
|
||||
path tmp;
|
||||
for (path::iterator i = boost::next(p.begin()); i != p.end(); ++i)
|
||||
tmp /= *i;
|
||||
p = tmp;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
// standard constructor that parses a torrent file
|
||||
torrent_info::torrent_info(entry const& torrent_file)
|
||||
: m_num_pieces(0)
|
||||
, m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_info_section_size(0)
|
||||
|
@ -249,8 +231,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
torrent_info::torrent_info(lazy_entry const& torrent_file)
|
||||
: m_num_pieces(0)
|
||||
, m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_info_section_size(0)
|
||||
|
@ -266,8 +247,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
torrent_info::torrent_info(char const* buffer, int size)
|
||||
: m_num_pieces(0)
|
||||
, m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_info_section_size(0)
|
||||
|
@ -289,22 +269,16 @@ namespace libtorrent
|
|||
// just the necessary to use it with piece manager
|
||||
// used for torrents with no metadata
|
||||
torrent_info::torrent_info(sha1_hash const& info_hash)
|
||||
: m_piece_length(0)
|
||||
, m_total_size(0)
|
||||
, m_num_pieces(0)
|
||||
, m_info_hash(info_hash)
|
||||
, m_name()
|
||||
: m_info_hash(info_hash)
|
||||
, m_creation_date(pt::second_clock::universal_time())
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
, m_info_section_size(0)
|
||||
, m_piece_hashes(0)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
torrent_info::torrent_info(char const* filename)
|
||||
: m_num_pieces(0)
|
||||
, m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
: m_creation_date(pt::ptime(pt::not_a_date_time))
|
||||
, m_multifile(false)
|
||||
, m_private(false)
|
||||
{
|
||||
|
@ -335,11 +309,8 @@ namespace libtorrent
|
|||
m_urls.swap(ti.m_urls);
|
||||
m_url_seeds.swap(ti.m_url_seeds);
|
||||
m_files.swap(ti.m_files);
|
||||
m_files.swap(ti.m_remapped_files);
|
||||
m_nodes.swap(ti.m_nodes);
|
||||
swap(m_num_pieces, ti.m_num_pieces);
|
||||
swap(m_info_hash, ti.m_info_hash);
|
||||
m_name.swap(ti.m_name);
|
||||
swap(m_creation_date, ti.m_creation_date);
|
||||
m_comment.swap(ti.m_comment);
|
||||
m_created_by.swap(ti.m_created_by);
|
||||
|
@ -373,27 +344,27 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(section.first[m_info_section_size-1] == 'e');
|
||||
|
||||
// extract piece length
|
||||
m_piece_length = info.dict_find_int_value("piece length", -1);
|
||||
if (m_piece_length <= 0)
|
||||
int piece_length = info.dict_find_int_value("piece length", -1);
|
||||
if (piece_length <= 0)
|
||||
{
|
||||
error = "invalid or missing 'piece length' entry in torrent file";
|
||||
return false;
|
||||
}
|
||||
m_files.set_piece_length(piece_length);
|
||||
|
||||
// extract file name (or the directory name if it's a multifile libtorrent)
|
||||
m_name = info.dict_find_string_value("name.utf-8");
|
||||
if (m_name.empty()) m_name = info.dict_find_string_value("name");
|
||||
|
||||
if (m_name.empty())
|
||||
std::string name = info.dict_find_string_value("name.utf-8");
|
||||
if (name.empty()) name = info.dict_find_string_value("name");
|
||||
if (name.empty())
|
||||
{
|
||||
error = "invalid name in torrent file";
|
||||
error = "missing name in torrent file";
|
||||
return false;
|
||||
}
|
||||
|
||||
fs::path tmp = m_name;
|
||||
fs::path tmp = name;
|
||||
if (tmp.is_complete())
|
||||
{
|
||||
m_name = tmp.leaf();
|
||||
name = tmp.leaf();
|
||||
}
|
||||
else if (tmp.has_branch_path())
|
||||
{
|
||||
|
@ -404,9 +375,9 @@ namespace libtorrent
|
|||
if (*i == "." || *i == "..") continue;
|
||||
p /= *i;
|
||||
}
|
||||
m_name = p.string();
|
||||
name = p.string();
|
||||
}
|
||||
if (m_name == ".." || m_name == ".")
|
||||
if (name == ".." || name == ".")
|
||||
{
|
||||
error = "invalid 'name' of torrent (possible exploit attempt)";
|
||||
return false;
|
||||
|
@ -419,7 +390,7 @@ namespace libtorrent
|
|||
// if there's no list of files, there has to be a length
|
||||
// field.
|
||||
file_entry e;
|
||||
e.path = m_name;
|
||||
e.path = name;
|
||||
e.offset = 0;
|
||||
e.size = info.dict_find_int_value("length", -1);
|
||||
if (e.size < 0)
|
||||
|
@ -427,29 +398,26 @@ namespace libtorrent
|
|||
error = "invalid length of torrent";
|
||||
return false;
|
||||
}
|
||||
m_files.push_back(e);
|
||||
m_files.add_file(e);
|
||||
m_multifile = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!extract_files(*i, m_files, m_name))
|
||||
if (!extract_files(*i, m_files, name))
|
||||
{
|
||||
error = "failed to parse files from torrent file";
|
||||
return false;
|
||||
}
|
||||
m_multifile = true;
|
||||
}
|
||||
|
||||
// calculate total size of all pieces
|
||||
m_total_size = 0;
|
||||
for (std::vector<file_entry>::iterator i = m_files.begin(); i != m_files.end(); ++i)
|
||||
m_total_size += i->size;
|
||||
m_files.set_name(name);
|
||||
|
||||
// extract sha-1 hashes for all pieces
|
||||
// we want this division to round upwards, that's why we have the
|
||||
// extra addition
|
||||
|
||||
m_num_pieces = static_cast<int>((m_total_size + m_piece_length - 1) / m_piece_length);
|
||||
m_files.set_num_pieces(int((m_files.total_size() + m_files.piece_length() - 1)
|
||||
/ m_files.piece_length()));
|
||||
|
||||
lazy_entry const* pieces = info.dict_find("pieces");
|
||||
if (pieces == 0 || pieces->type() != lazy_entry::string_t)
|
||||
|
@ -458,7 +426,7 @@ namespace libtorrent
|
|||
return false;
|
||||
}
|
||||
|
||||
if (pieces->string_length() != m_num_pieces * 20)
|
||||
if (pieces->string_length() != m_files.num_pieces() * 20)
|
||||
{
|
||||
error = "incorrect number of piece hashes in torrent file";
|
||||
return false;
|
||||
|
@ -616,122 +584,11 @@ namespace libtorrent
|
|||
os << "number of pieces: " << num_pieces() << "\n";
|
||||
os << "piece length: " << piece_length() << "\n";
|
||||
os << "files:\n";
|
||||
for (file_iterator i = begin_files(); i != end_files(); ++i)
|
||||
for (file_storage::iterator i = m_files.begin(); i != m_files.end(); ++i)
|
||||
os << " " << std::setw(11) << i->size << " " << i->path.string() << "\n";
|
||||
}
|
||||
|
||||
// ------- end deprecation -------
|
||||
|
||||
int torrent_info::piece_size(int index) const
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0 && index < num_pieces());
|
||||
if (index == num_pieces()-1)
|
||||
{
|
||||
int size = int(total_size()
|
||||
- size_type(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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -242,7 +242,7 @@ namespace libtorrent
|
|||
}
|
||||
else
|
||||
{
|
||||
std::vector<file_slice> files = info.map_block(r.piece, r.start
|
||||
std::vector<file_slice> files = info.files().map_block(r.piece, r.start
|
||||
, r.length);
|
||||
|
||||
for (std::vector<file_slice>::iterator i = files.begin();
|
||||
|
@ -254,13 +254,13 @@ namespace libtorrent
|
|||
if (using_proxy)
|
||||
{
|
||||
request += m_url;
|
||||
std::string path = info.file_at(f.file_index).path.string();
|
||||
std::string path = info.files().at(f.file_index).path.string();
|
||||
request += escape_path(path.c_str(), path.length());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string path = m_path;
|
||||
path += info.file_at(f.file_index).path.string();
|
||||
path += info.files().at(f.file_index).path.string();
|
||||
request += escape_path(path.c_str(), path.length());
|
||||
}
|
||||
request += " HTTP/1.1\r\n";
|
||||
|
@ -426,7 +426,7 @@ namespace libtorrent
|
|||
int file_index = m_file_requests.front();
|
||||
|
||||
torrent_info const& info = t->torrent_file();
|
||||
std::string path = info.file_at(file_index).path.string();
|
||||
std::string path = info.files().at(file_index).path.string();
|
||||
path = escape_path(path.c_str(), path.length());
|
||||
size_t i = location.rfind(path);
|
||||
if (i == std::string::npos)
|
||||
|
@ -511,7 +511,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
int file_index = m_file_requests.front();
|
||||
peer_request in_range = info.map_file(file_index, range_start
|
||||
peer_request in_range = info.files().map_file(file_index, range_start
|
||||
, int(range_end - range_start));
|
||||
|
||||
peer_request front_request = m_requests.front();
|
||||
|
|
|
@ -170,10 +170,10 @@ boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file)
|
|||
|
||||
using namespace boost::filesystem;
|
||||
|
||||
libtorrent::create_torrent t;
|
||||
file_storage fs;
|
||||
int total_size = 2 * 1024 * 1024;
|
||||
t.add_file(path("temporary"), total_size);
|
||||
t.set_piece_size(16 * 1024);
|
||||
fs.add_file(path("temporary"), total_size);
|
||||
libtorrent::create_torrent t(fs, 16 * 1024);
|
||||
t.add_tracker(tracker_url);
|
||||
|
||||
std::vector<char> piece(16 * 1024);
|
||||
|
|
|
@ -51,9 +51,11 @@ void on_check_files(int ret, disk_io_job const& j)
|
|||
}
|
||||
|
||||
void run_storage_tests(boost::intrusive_ptr<torrent_info> info
|
||||
, file_storage& fs
|
||||
, path const& test_path
|
||||
, libtorrent::storage_mode_t storage_mode)
|
||||
{
|
||||
TORRENT_ASSERT(fs.num_files() > 0);
|
||||
create_directory(test_path / "temp_storage");
|
||||
|
||||
int num_pieces = (1 + 612 + 17 + piece_size - 1) / piece_size;
|
||||
|
@ -64,7 +66,7 @@ void run_storage_tests(boost::intrusive_ptr<torrent_info> info
|
|||
{ // avoid having two storages use the same files
|
||||
file_pool fp;
|
||||
boost::scoped_ptr<storage_interface> s(
|
||||
default_storage_constructor(info, test_path, fp));
|
||||
default_storage_constructor(fs, test_path, fp));
|
||||
|
||||
// write piece 1 (in slot 0)
|
||||
s->write(piece1, 0, 0, half);
|
||||
|
@ -100,12 +102,17 @@ void run_storage_tests(boost::intrusive_ptr<torrent_info> info
|
|||
|
||||
entry frd;
|
||||
pm->async_check_fastresume(&frd, &on_check_resume_data);
|
||||
ios.reset();
|
||||
ios.run();
|
||||
|
||||
pm->async_check_files(&on_check_files);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
ios.reset();
|
||||
ios.run_one();
|
||||
}
|
||||
|
||||
// test move_storage
|
||||
boost::function<void(int, disk_io_job const&)> none;
|
||||
TEST_CHECK(exists(test_path / "temp_storage"));
|
||||
pm->async_move_storage(test_path / "temp_storage2", none);
|
||||
|
@ -117,6 +124,15 @@ void run_storage_tests(boost::intrusive_ptr<torrent_info> info
|
|||
TEST_CHECK(!exists(test_path / "temp_storage2/temp_storage"));
|
||||
remove_all(test_path / "temp_storage2");
|
||||
|
||||
// test rename_file
|
||||
remove(test_path / "part0");
|
||||
TEST_CHECK(exists(test_path / "temp_storage/test1.tmp"));
|
||||
TEST_CHECK(!exists(test_path / "part0"));
|
||||
pm->async_rename_file(0, "part0", none);
|
||||
test_sleep(2000);
|
||||
TEST_CHECK(!exists(test_path / "temp_storage/test1.tmp"));
|
||||
TEST_CHECK(exists(test_path / "part0"));
|
||||
|
||||
peer_request r;
|
||||
r.piece = 0;
|
||||
r.start = 0;
|
||||
|
@ -128,6 +144,10 @@ void run_storage_tests(boost::intrusive_ptr<torrent_info> info
|
|||
pm->async_read(r, bind(&on_read_piece, _1, _2, piece2, piece_size));
|
||||
pm->async_release_files(none);
|
||||
|
||||
pm->async_rename_file(0, "temp_storage/test1.tmp", none);
|
||||
test_sleep(1000);
|
||||
TEST_CHECK(!exists(test_path / "part0"));
|
||||
|
||||
ios.run();
|
||||
|
||||
io.join();
|
||||
|
@ -136,13 +156,13 @@ void run_storage_tests(boost::intrusive_ptr<torrent_info> info
|
|||
|
||||
void test_remove(path const& test_path)
|
||||
{
|
||||
libtorrent::create_torrent t;
|
||||
t.set_piece_size(4);
|
||||
t.add_file("temp_storage/test1.tmp", 8);
|
||||
t.add_file("temp_storage/folder1/test2.tmp", 8);
|
||||
t.add_file("temp_storage/folder2/test3.tmp", 0);
|
||||
t.add_file("temp_storage/_folder3/test4.tmp", 0);
|
||||
t.add_file("temp_storage/_folder3/subfolder/test5.tmp", 8);
|
||||
file_storage fs;
|
||||
fs.add_file("temp_storage/test1.tmp", 8);
|
||||
fs.add_file("temp_storage/folder1/test2.tmp", 8);
|
||||
fs.add_file("temp_storage/folder2/test3.tmp", 0);
|
||||
fs.add_file("temp_storage/_folder3/test4.tmp", 0);
|
||||
fs.add_file("temp_storage/_folder3/subfolder/test5.tmp", 8);
|
||||
libtorrent::create_torrent t(fs, 4);
|
||||
|
||||
char buf[4] = {0, 0, 0, 0};
|
||||
sha1_hash h = hasher(buf, 4).final();
|
||||
|
@ -152,7 +172,7 @@ void test_remove(path const& test_path)
|
|||
|
||||
file_pool fp;
|
||||
boost::scoped_ptr<storage_interface> s(
|
||||
default_storage_constructor(info, test_path, fp));
|
||||
default_storage_constructor(fs, test_path, fp));
|
||||
|
||||
// allocate the files and create the directories
|
||||
s->initialize(true);
|
||||
|
@ -172,14 +192,15 @@ void run_test(path const& test_path)
|
|||
boost::intrusive_ptr<torrent_info> info;
|
||||
|
||||
{
|
||||
libtorrent::create_torrent t;
|
||||
t.set_piece_size(piece_size);
|
||||
t.add_file("temp_storage/test1.tmp", 17);
|
||||
t.add_file("temp_storage/test2.tmp", 612);
|
||||
t.add_file("temp_storage/test3.tmp", 0);
|
||||
t.add_file("temp_storage/test4.tmp", 0);
|
||||
t.add_file("temp_storage/test5.tmp", 1);
|
||||
remove_all(test_path / "temp_storage");
|
||||
file_storage fs;
|
||||
fs.add_file("temp_storage/test1.tmp", 17);
|
||||
fs.add_file("temp_storage/test2.tmp", 612);
|
||||
fs.add_file("temp_storage/test3.tmp", 0);
|
||||
fs.add_file("temp_storage/test4.tmp", 0);
|
||||
fs.add_file("temp_storage/test5.tmp", 1);
|
||||
|
||||
libtorrent::create_torrent t(fs, piece_size);
|
||||
t.set_hash(0, hasher(piece0, piece_size).final());
|
||||
t.set_hash(1, hasher(piece1, piece_size).final());
|
||||
t.set_hash(2, hasher(piece2, piece_size).final());
|
||||
|
@ -188,7 +209,7 @@ void run_test(path const& test_path)
|
|||
info = new torrent_info(t.generate());
|
||||
std::cerr << "=== test 1 ===" << std::endl;
|
||||
|
||||
run_storage_tests(info, test_path, storage_mode_compact);
|
||||
run_storage_tests(info, fs, test_path, storage_mode_compact);
|
||||
|
||||
// make sure the files have the correct size
|
||||
std::cerr << file_size(test_path / "temp_storage" / "test1.tmp") << std::endl;
|
||||
|
@ -200,63 +221,39 @@ void run_test(path const& test_path)
|
|||
remove_all(test_path / "temp_storage");
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
|
||||
// make sure remap_files works
|
||||
std::vector<file_entry> map;
|
||||
file_entry fe;
|
||||
fe.path = "temp_storage/test.tmp";
|
||||
fe.size = 17;
|
||||
fe.file_base = 612 + 1;
|
||||
map.push_back(fe);
|
||||
fe.path = "temp_storage/test.tmp";
|
||||
fe.size = 612 + 1;
|
||||
fe.file_base = 0;
|
||||
map.push_back(fe);
|
||||
|
||||
bool ret = info->remap_files(map);
|
||||
TEST_CHECK(ret);
|
||||
|
||||
std::cerr << "=== test 2 ===" << std::endl;
|
||||
|
||||
run_storage_tests(info, test_path, storage_mode_compact);
|
||||
|
||||
std::cerr << file_size(test_path / "temp_storage" / "test.tmp") << std::endl;
|
||||
TEST_CHECK(file_size(test_path / "temp_storage" / "test.tmp") == 17 + 612 + 1);
|
||||
|
||||
remove_all(test_path / "temp_storage");
|
||||
|
||||
// ==============================================
|
||||
|
||||
{
|
||||
libtorrent::create_torrent t;
|
||||
t.set_piece_size(piece_size);
|
||||
t.add_file("temp_storage/test1.tmp", 17 + 612 + 1);
|
||||
file_storage fs;
|
||||
fs.add_file("temp_storage/test1.tmp", 17 + 612 + 1);
|
||||
libtorrent::create_torrent t(fs, piece_size);
|
||||
TEST_CHECK(fs.begin()->path == "temp_storage/test1.tmp");
|
||||
t.set_hash(0, hasher(piece0, piece_size).final());
|
||||
t.set_hash(1, hasher(piece1, piece_size).final());
|
||||
t.set_hash(2, hasher(piece2, piece_size).final());
|
||||
|
||||
info = new torrent_info(t.generate());
|
||||
|
||||
std::cerr << "=== test 3 ===" << std::endl;
|
||||
|
||||
run_storage_tests(info, test_path, storage_mode_compact);
|
||||
run_storage_tests(info, fs, test_path, storage_mode_compact);
|
||||
|
||||
// 48 = piece_size * 3
|
||||
TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 48);
|
||||
remove_all(test_path / "temp_storage");
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
|
||||
std::cerr << "=== test 4 ===" << std::endl;
|
||||
|
||||
run_storage_tests(info, test_path, storage_mode_allocate);
|
||||
run_storage_tests(info, fs, test_path, storage_mode_allocate);
|
||||
|
||||
std::cerr << file_size(test_path / "temp_storage" / "test1.tmp") << std::endl;
|
||||
TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 17 + 612 + 1);
|
||||
|
||||
remove_all(test_path / "temp_storage");
|
||||
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
|
||||
|
|
|
@ -14,12 +14,12 @@ int test_main()
|
|||
|
||||
session ses(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48130, 48140));
|
||||
|
||||
libtorrent::create_torrent t;
|
||||
file_storage fs;
|
||||
size_type file_size = 1 * 1024 * 1024 * 1024;
|
||||
t.add_file("test_torrent/tmp1", file_size);
|
||||
t.add_file("test_torrent/tmp2", file_size);
|
||||
t.add_file("test_torrent/tmp3", file_size);
|
||||
t.set_piece_size(4 * 1024 * 1024);
|
||||
fs.add_file("test_torrent/tmp1", file_size);
|
||||
fs.add_file("test_torrent/tmp2", file_size);
|
||||
fs.add_file("test_torrent/tmp3", file_size);
|
||||
libtorrent::create_torrent t(fs, 4 * 1024 * 1024);
|
||||
t.add_tracker("http://non-existing.com/announce");
|
||||
|
||||
std::vector<char> piece(4 * 1024 * 1024);
|
||||
|
|
|
@ -15,22 +15,6 @@
|
|||
using namespace boost::filesystem;
|
||||
using namespace libtorrent;
|
||||
|
||||
void add_files(libtorrent::create_torrent& t, path const& p, path const& l)
|
||||
{
|
||||
if (l.leaf()[0] == '.') return;
|
||||
path f(p / l);
|
||||
if (is_directory(f))
|
||||
{
|
||||
for (directory_iterator i(f), end; i != end; ++i)
|
||||
add_files(t, p, l / i->leaf());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "adding \"" << l.string() << "\"\n";
|
||||
t.add_file(l, file_size(f));
|
||||
}
|
||||
}
|
||||
|
||||
// proxy: 0=none, 1=socks4, 2=socks5, 3=socks5_pw 4=http 5=http_pw
|
||||
void test_transfer(boost::intrusive_ptr<torrent_info> torrent_file, int proxy)
|
||||
{
|
||||
|
@ -87,9 +71,6 @@ int test_main()
|
|||
using namespace libtorrent;
|
||||
using namespace boost::filesystem;
|
||||
|
||||
libtorrent::create_torrent t;
|
||||
t.add_url_seed("http://127.0.0.1:8000/");
|
||||
|
||||
create_directory("test_torrent");
|
||||
char random_data[300000];
|
||||
std::srand(std::time(0));
|
||||
|
@ -102,7 +83,11 @@ int test_main()
|
|||
std::ofstream("./test_torrent/test6").write(random_data, 300000);
|
||||
std::ofstream("./test_torrent/test7").write(random_data, 300000);
|
||||
|
||||
add_files(t, complete("."), "test_torrent");
|
||||
file_storage fs;
|
||||
add_files(fs, path("test_torrent"));
|
||||
|
||||
libtorrent::create_torrent t(fs, 16 * 1024);
|
||||
t.add_url_seed("http://127.0.0.1:8000/");
|
||||
|
||||
start_web_server(8000);
|
||||
|
||||
|
@ -111,20 +96,17 @@ int test_main()
|
|||
std::vector<char> buf(t.piece_length());
|
||||
|
||||
file_pool fp;
|
||||
boost::intrusive_ptr<torrent_info> torrent_file(new torrent_info(t.generate()));
|
||||
boost::scoped_ptr<storage_interface> s(default_storage_constructor(
|
||||
torrent_file, ".", fp));
|
||||
fs, ".", fp));
|
||||
|
||||
for (int i = 0; i < num; ++i)
|
||||
{
|
||||
s->read(&buf[0], i, 0, t.piece_size(i));
|
||||
hasher h(&buf[0], t.piece_size(i));
|
||||
s->read(&buf[0], i, 0, fs.piece_size(i));
|
||||
hasher h(&buf[0], fs.piece_size(i));
|
||||
t.set_hash(i, h.final());
|
||||
}
|
||||
|
||||
entry e = t.generate();
|
||||
torrent_file = new torrent_info(e);
|
||||
s.reset(default_storage_constructor(torrent_file, ".", fp));
|
||||
boost::intrusive_ptr<torrent_info> torrent_file(new torrent_info(t.generate()));
|
||||
|
||||
for (int i = 0; i < 6; ++i)
|
||||
test_transfer(torrent_file, i);
|
||||
|
|
Loading…
Reference in New Issue