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