separated file_storage from torrent_info and create_torrent

This commit is contained in:
Arvid Norberg 2008-05-28 08:44:40 +00:00
parent cf37d8544d
commit 3910fe78de
31 changed files with 1859 additions and 1514 deletions

View File

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

194
docs/make_torrent.rst Normal file
View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -53,6 +53,21 @@ namespace libtorrent
torrent_handle handle; torrent_handle handle;
}; };
struct TORRENT_EXPORT file_renamed_alert: torrent_alert
{
file_renamed_alert(torrent_handle const& h
, std::string const& name_
, std::string const& msg)
: torrent_alert(h, alert::warning, msg)
, name(name_)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new file_renamed_alert(*this)); }
std::string name;
};
struct TORRENT_EXPORT tracker_alert: torrent_alert struct TORRENT_EXPORT tracker_alert: torrent_alert
{ {
tracker_alert(torrent_handle const& h tracker_alert(torrent_handle const& h

View File

@ -35,6 +35,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/bencode.hpp" #include "libtorrent/bencode.hpp"
#include "libtorrent/peer_id.hpp" #include "libtorrent/peer_id.hpp"
#include "libtorrent/file_storage.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp"
#include <vector> #include <vector>
#include <string> #include <string>
#include <utility> #include <utility>
@ -44,8 +50,10 @@ POSSIBILITY OF SUCH DAMAGE.
#endif #endif
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/scoped_ptr.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
@ -56,26 +64,29 @@ namespace libtorrent
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
namespace pt = boost::posix_time; namespace pt = boost::posix_time;
struct create_torrent struct TORRENT_EXPORT create_torrent
{ {
create_torrent(); create_torrent(file_storage& fs, int piece_size);
create_torrent(file_storage& fs);
entry generate() const; entry generate() const;
file_storage const& files() const { return m_files; }
void set_comment(char const* str); void set_comment(char const* str);
void set_creator(char const* str); void set_creator(char const* str);
void set_piece_size(int size);
void set_hash(int index, sha1_hash const& h); void set_hash(int index, sha1_hash const& h);
void add_file(fs::path file, size_type size);
void add_url_seed(std::string const& url); void add_url_seed(std::string const& url);
void add_node(std::pair<std::string, int> const& node); void add_node(std::pair<std::string, int> const& node);
void add_tracker(std::string const& url, int tier = 0); void add_tracker(std::string const& url, int tier = 0);
int num_pieces() const { return m_num_pieces; } int num_pieces() const { return m_files.num_pieces(); }
int piece_length() const { return m_piece_length; } int piece_length() const { return m_files.piece_length(); }
int piece_size(int i) const; int piece_size(int i) const { return m_files.piece_size(i); }
private: private:
file_storage& m_files;
// the urls to the trackers // the urls to the trackers
typedef std::pair<std::string, int> announce_entry; typedef std::pair<std::string, int> announce_entry;
std::vector<announce_entry> m_urls; std::vector<announce_entry> m_urls;
@ -84,32 +95,15 @@ namespace libtorrent
std::vector<sha1_hash> m_piece_hash; std::vector<sha1_hash> m_piece_hash;
// the length of one piece
// if this is 0, the torrent_info is
// in an uninitialized state
int m_piece_length;
typedef std::pair<fs::path, size_type> file_entry;
// the list of files that this torrent consists of
std::vector<file_entry> m_files;
// dht nodes to add to the routing table/bootstrap from // dht nodes to add to the routing table/bootstrap from
typedef std::vector<std::pair<std::string, int> > nodes_t; typedef std::vector<std::pair<std::string, int> > nodes_t;
nodes_t m_nodes; nodes_t m_nodes;
// the sum of all filesizes
size_type m_total_size;
// the number of pieces in the torrent
int m_num_pieces;
// the hash that identifies this torrent // the hash that identifies this torrent
// is mutable because it's calculated // is mutable because it's calculated
// lazily // lazily
mutable sha1_hash m_info_hash; mutable sha1_hash m_info_hash;
std::string m_name;
// if a creation date is found in the torrent file // if a creation date is found in the torrent file
// this will be set to that, otherwise it'll be // this will be set to that, otherwise it'll be
// 1970, Jan 1 // 1970, Jan 1
@ -134,6 +128,72 @@ namespace libtorrent
// be announced on the dht // be announced on the dht
bool m_private; bool m_private;
}; };
namespace detail
{
inline bool default_pred(boost::filesystem::path const&) { return true; }
inline void nop(int i) {}
template <class Pred>
void add_files_impl(file_storage& fs, boost::filesystem::path const& p
, boost::filesystem::path const& l, Pred pred)
{
using boost::filesystem::path;
using boost::filesystem::directory_iterator;
std::string const& leaf = l.leaf();
if (leaf == ".." || leaf == ".") return;
if (!pred(l)) return;
path f(p / l);
if (is_directory(f))
{
for (directory_iterator i(f), end; i != end; ++i)
add_files_impl(fs, p, l / i->leaf(), pred);
}
else
{
fs.add_file(l, file_size(f));
}
}
}
template <class Pred>
void add_files(file_storage& fs, boost::filesystem::path const& file, Pred p)
{
detail::add_files_impl(fs, complete(file).branch_path(), file.leaf(), p);
}
inline void add_files(file_storage& fs, boost::filesystem::path const& file)
{
detail::add_files_impl(fs, complete(file).branch_path(), file.leaf(), detail::default_pred);
}
template <class Fun>
void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p, Fun f)
{
file_pool fp;
boost::scoped_ptr<storage_interface> st(
default_storage_constructor(const_cast<file_storage&>(t.files()), p, fp));
// calculate the hash for all pieces
int num = t.num_pieces();
std::vector<char> buf(t.piece_length());
for (int i = 0; i < num; ++i)
{
// read hits the disk and will block. Progress should
// be updated in between reads
st->read(&buf[0], i, 0, t.piece_size(i));
hasher h(&buf[0], t.piece_size(i));
t.set_hash(i, h.final());
f(i);
}
}
inline void set_piece_hashes(create_torrent& t, boost::filesystem::path const& p)
{
set_piece_hashes(t, p, detail::nop);
}
} }
#endif #endif

View File

@ -82,6 +82,7 @@ namespace libtorrent
, check_fastresume , check_fastresume
, check_files , check_files
, save_resume_data , save_resume_data
, rename_file
}; };
action_t action; action_t action;
@ -91,7 +92,7 @@ namespace libtorrent
boost::intrusive_ptr<piece_manager> storage; boost::intrusive_ptr<piece_manager> storage;
// arguments used for read and write // arguments used for read and write
int piece, offset; int piece, offset;
// used for move_storage. On errors, this is set // used for move_storage and rename_file. On errors, this is set
// to the error message // to the error message
std::string str; std::string str;

View File

@ -68,6 +68,7 @@ namespace libtorrent
boost::shared_ptr<file> open_file(void* st, fs::path const& p boost::shared_ptr<file> open_file(void* st, fs::path const& p
, file::open_mode m, std::string& error); , file::open_mode m, std::string& error);
void release(void* st); void release(void* st);
void release(fs::path const& p);
void resize(int size); void resize(int size);
private: private:

View File

@ -0,0 +1,146 @@
/*
Copyright (c) 2003-2008, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_FILE_STORAGE_HPP_INCLUDED
#define TORRENT_FILE_STORAGE_HPP_INCLUDED
#include <string>
#include <vector>
#ifdef _MSC_VER
#pragma warning(push, 1)
#endif
#include <boost/filesystem/path.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "libtorrent/size_type.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/peer_request.hpp"
namespace libtorrent
{
namespace fs = boost::filesystem;
struct TORRENT_EXPORT file_entry
{
file_entry(): offset(0), size(0), file_base(0) {}
fs::path path;
size_type offset; // the offset of this file inside the torrent
size_type size; // the size of this file
// the offset in the file where the storage starts.
// This is always 0 unless parts of the torrent is
// compressed into a single file, such as a so-called part file.
size_type file_base;
};
struct TORRENT_EXPORT file_slice
{
int file_index;
size_type offset;
size_type size;
};
class TORRENT_EXPORT file_storage
{
friend class torrent_info;
public:
file_storage();
~file_storage() {}
bool is_valid() const { return m_piece_length > 0; }
void add_file(file_entry const& e);
void add_file(fs::path const& p, size_type size);
void rename_file(int index, std::string const& new_filename);
std::vector<file_slice> map_block(int piece, size_type offset
, int size) const;
peer_request map_file(int file, size_type offset, int size) const;
typedef std::vector<file_entry>::const_iterator iterator;
typedef std::vector<file_entry>::const_reverse_iterator reverse_iterator;
iterator begin() const { return m_files.begin(); }
iterator end() const { return m_files.end(); }
reverse_iterator rbegin() const { return m_files.rbegin(); }
reverse_iterator rend() const { return m_files.rend(); }
int num_files() const
{ return int(m_files.size()); }
file_entry const& at(int index) const
{
TORRENT_ASSERT(index >= 0 && index < int(m_files.size()));
return m_files[index];
}
size_type total_size() const { TORRENT_ASSERT(m_piece_length > 0); return m_total_size; }
void set_num_pieces(int n) { m_num_pieces = n; }
int num_pieces() const { TORRENT_ASSERT(m_piece_length > 0); return m_num_pieces; }
void set_piece_length(int l) { m_piece_length = l; }
int piece_length() const { TORRENT_ASSERT(m_piece_length > 0); return m_piece_length; }
int piece_size(int index) const;
void set_name(std::string const& n) { m_name = n; }
const std::string& name() const { TORRENT_ASSERT(m_piece_length > 0); return m_name; }
void swap(file_storage& ti)
{
using std::swap;
swap(ti.m_piece_length, m_piece_length);
swap(ti.m_files, m_files);
swap(ti.m_total_size, m_total_size);
swap(ti.m_num_pieces, m_num_pieces);
swap(ti.m_name, m_name);
}
private:
int m_piece_length;
// the list of files that this torrent consists of
std::vector<file_entry> m_files;
// the sum of all filesizes
size_type m_total_size;
// the number of pieces in the torrent
int m_num_pieces;
std::string m_name;
};
}
#endif // TORRENT_FILE_STORAGE_HPP_INCLUDED

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2003, Arvid Norberg Copyright (c) 2003-2008, Arvid Norberg
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -30,9 +30,8 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef TORRENT_TORRENT_INFO_HPP_INCLUDE #ifndef TORRENT_TORRENT_INFO_HPP_INCLUDED
#define TORRENT_TORRENT_INFO_HPP_INCLUDE #define TORRENT_TORRENT_INFO_HPP_INCLUDED
#include <string> #include <string>
#include <vector> #include <vector>
@ -44,7 +43,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp> #include <boost/shared_array.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
@ -56,44 +54,17 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/socket.hpp" #include "libtorrent/socket.hpp"
#include "libtorrent/peer_id.hpp" #include "libtorrent/peer_id.hpp"
#include "libtorrent/size_type.hpp" #include "libtorrent/size_type.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/time.hpp" #include "libtorrent/time.hpp"
#include "libtorrent/intrusive_ptr_base.hpp" #include "libtorrent/intrusive_ptr_base.hpp"
#include "libtorrent/assert.hpp" #include "libtorrent/assert.hpp"
#include "libtorrent/file_storage.hpp"
namespace libtorrent namespace libtorrent
{ {
namespace pt = boost::posix_time; namespace pt = boost::posix_time;
namespace gr = boost::gregorian; namespace gr = boost::gregorian;
namespace fs = boost::filesystem;
struct TORRENT_EXPORT file_entry
{
file_entry(): offset(0), size(0), file_base(0) {}
fs::path path;
size_type offset; // the offset of this file inside the torrent
size_type size; // the size of this file
// the offset in the file where the storage starts.
// This is always 0 unless parts of the torrent is
// compressed into a single file, such as a so-called part file.
size_type file_base;
// if the path was incorrectly encoded, this is
// the original corrupt encoded string. It is
// preserved in order to be able to reproduce
// the correct info-hash
boost::shared_ptr<const fs::path> orig_path;
};
struct TORRENT_EXPORT file_slice
{
int file_index;
size_type offset;
size_type size;
};
struct TORRENT_EXPORT announce_entry struct TORRENT_EXPORT announce_entry
{ {
announce_entry(std::string const& u): url(u), tier(0) {} announce_entry(std::string const& u): url(u), tier(0) {}
@ -101,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,108 +89,56 @@ 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
torrent_info(entry const& torrent_file) TORRENT_DEPRECATED; torrent_info(entry const& torrent_file) TORRENT_DEPRECATED;
void print(std::ostream& os) const TORRENT_DEPRECATED; void print(std::ostream& os) const TORRENT_DEPRECATED;
// ------- end deprecation ------- // ------- end deprecation -------
bool is_valid() const { return m_piece_length > 0; } bool is_valid() const { return m_files.is_valid(); }
bool priv() const { return m_private; } bool priv() const { return m_private; }
int piece_size(int index) const; int piece_size(int index) const { return m_files.piece_size(index); }
sha1_hash hash_for_piece(int index) const sha1_hash hash_for_piece(int index) const
{ { return sha1_hash(hash_for_piece_ptr(index)); }
return sha1_hash(hash_for_piece_ptr(index));
}
char const* hash_for_piece_ptr(int index) const char const* hash_for_piece_ptr(int index) const
{ {
TORRENT_ASSERT(index >= 0); TORRENT_ASSERT(index >= 0);
TORRENT_ASSERT(index < m_num_pieces); TORRENT_ASSERT(index < m_files.num_pieces());
TORRENT_ASSERT(m_piece_hashes); TORRENT_ASSERT(m_piece_hashes);
TORRENT_ASSERT(m_piece_hashes >= m_info_section.get()); TORRENT_ASSERT(m_piece_hashes >= m_info_section.get());
TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size); TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size);
@ -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

View File

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

View File

@ -31,7 +31,8 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "libtorrent/create_torrent.hpp" #include "libtorrent/create_torrent.hpp"
#include "libtorrent/hasher.hpp" #include "libtorrent/file_pool.hpp"
#include "libtorrent/storage.hpp"
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp> #include <boost/date_time/gregorian/gregorian.hpp>
@ -41,22 +42,61 @@ namespace gr = boost::gregorian;
namespace libtorrent namespace libtorrent
{ {
create_torrent::create_torrent() create_torrent::create_torrent(file_storage& fs, int size)
: m_piece_length(0) : m_files(fs)
, m_total_size(0)
, m_num_pieces(0)
, m_info_hash()
, m_name()
, m_creation_date(pt::second_clock::universal_time()) , m_creation_date(pt::second_clock::universal_time())
, m_multifile(false) , m_multifile(fs.num_files() > 1)
, m_private(false) , m_private(false)
{} {
TORRENT_ASSERT(fs.num_files() > 0);
if (!m_multifile && m_files.at(0).path.has_branch_path()) m_multifile = true;
// make sure the size is an even power of 2
#ifndef NDEBUG
for (int i = 0; i < 32; ++i)
{
if (size & (1 << i))
{
TORRENT_ASSERT((size & ~(1 << i)) == 0);
break;
}
}
#endif
m_files.set_piece_length(size);
m_files.set_num_pieces(static_cast<int>(
(m_files.total_size() + m_files.piece_length() - 1) / m_files.piece_length()));
m_piece_hash.resize(m_files.num_pieces());
}
create_torrent::create_torrent(file_storage& fs)
: m_files(fs)
, m_creation_date(pt::second_clock::universal_time())
, m_multifile(fs.num_files() > 1)
, m_private(false)
{
TORRENT_ASSERT(fs.num_files() > 0);
if (!m_multifile && m_files.at(0).path.has_branch_path()) m_multifile = true;
const int target_size = 40 * 1024;
int size = fs.total_size() / (target_size / 20);
for (int i = 4*1024*1024; i > 16*1024; i /= 2)
{
if (size < i) continue;
size = i;
break;
}
m_files.set_piece_length(size);
m_files.set_num_pieces(static_cast<int>(
(m_files.total_size() + m_files.piece_length() - 1) / m_files.piece_length()));
m_piece_hash.resize(m_files.num_pieces());
}
entry create_torrent::generate() const entry create_torrent::generate() const
{ {
TORRENT_ASSERT(m_piece_length > 0); TORRENT_ASSERT(m_files.piece_length() > 0);
if (m_files.empty()) if (m_files.num_files() == 0)
{ {
// TODO: throw something here // TODO: throw something here
// throw // throw
@ -128,15 +168,13 @@ namespace libtorrent
} }
entry& info = dict["info"]; entry& info = dict["info"];
info["name"] = m_files.name();
info["name"] = m_name;
if (m_private) info["private"] = 1; if (m_private) info["private"] = 1;
if (!m_multifile) if (!m_multifile)
{ {
info["length"] = m_files.front().second; info["length"] = m_files.at(0).size;
} }
else else
{ {
@ -144,19 +182,19 @@ namespace libtorrent
{ {
entry& files = info["files"]; entry& files = info["files"];
for (std::vector<file_entry>::const_iterator i = m_files.begin(); for (file_storage::iterator i = m_files.begin();
i != m_files.end(); ++i) i != m_files.end(); ++i)
{ {
files.list().push_back(entry()); files.list().push_back(entry());
entry& file_e = files.list().back(); entry& file_e = files.list().back();
file_e["length"] = i->second; file_e["length"] = i->size;
entry& path_e = file_e["path"]; entry& path_e = file_e["path"];
TORRENT_ASSERT(i->first.has_branch_path()); TORRENT_ASSERT(i->path.has_branch_path());
TORRENT_ASSERT(*i->first.begin() == m_name); TORRENT_ASSERT(*i->path.begin() == m_files.name());
for (fs::path::iterator j = boost::next(i->first.begin()); for (fs::path::iterator j = boost::next(i->path.begin());
j != i->first.end(); ++j) j != i->path.end(); ++j)
{ {
path_e.list().push_back(entry(*j)); path_e.list().push_back(entry(*j));
} }
@ -164,7 +202,7 @@ namespace libtorrent
} }
} }
info["piece length"] = m_piece_length; info["piece length"] = m_files.piece_length();
entry& pieces = info["pieces"]; entry& pieces = info["pieces"];
std::string& p = pieces.string(); std::string& p = pieces.string();
@ -183,21 +221,6 @@ namespace libtorrent
} }
int create_torrent::piece_size(int index) const
{
TORRENT_ASSERT(index >= 0 && index < num_pieces());
if (index == num_pieces()-1)
{
int size = int(m_total_size
- (num_pieces() - 1) * piece_length());
TORRENT_ASSERT(size > 0);
TORRENT_ASSERT(size <= piece_length());
return int(size);
}
else
return piece_length();
}
void create_torrent::add_tracker(std::string const& url, int tier) void create_torrent::add_tracker(std::string const& url, int tier)
{ {
m_urls.push_back(announce_entry(url, tier)); m_urls.push_back(announce_entry(url, tier));
@ -207,32 +230,6 @@ namespace libtorrent
, bind(&announce_entry::second, _1) < bind(&announce_entry::second, _2)); , bind(&announce_entry::second, _1) < bind(&announce_entry::second, _2));
} }
void create_torrent::set_piece_size(int size)
{
// make sure the size is an even power of 2
#ifndef NDEBUG
for (int i = 0; i < 32; ++i)
{
if (size & (1 << i))
{
TORRENT_ASSERT((size & ~(1 << i)) == 0);
break;
}
}
#endif
m_piece_length = size;
m_num_pieces = static_cast<int>(
(m_total_size + m_piece_length - 1) / m_piece_length);
int old_num_pieces = static_cast<int>(m_piece_hash.size());
m_piece_hash.resize(m_num_pieces);
for (int i = old_num_pieces; i < m_num_pieces; ++i)
{
m_piece_hash[i].clear();
}
}
void create_torrent::set_hash(int index, sha1_hash const& h) void create_torrent::set_hash(int index, sha1_hash const& h)
{ {
TORRENT_ASSERT(index >= 0); TORRENT_ASSERT(index >= 0);
@ -240,46 +237,6 @@ namespace libtorrent
m_piece_hash[index] = h; m_piece_hash[index] = h;
} }
void create_torrent::add_file(fs::path file, size_type size)
{
// TORRENT_ASSERT(file.begin() != file.end());
if (!file.has_branch_path())
{
// you have already added at least one file with a
// path to the file (branch_path), which means that
// all the other files need to be in the same top
// directory as the first file.
TORRENT_ASSERT(m_files.empty());
TORRENT_ASSERT(!m_multifile);
m_name = file.string();
}
else
{
#ifndef NDEBUG
if (!m_files.empty())
TORRENT_ASSERT(m_name == *file.begin());
#endif
m_multifile = true;
m_name = *file.begin();
}
m_files.push_back(file_entry(file, size));
m_total_size += size;
if (m_piece_length == 0)
m_piece_length = 256 * 1024;
m_num_pieces = int((m_total_size + m_piece_length - 1) / m_piece_length);
int old_num_pieces = int(m_piece_hash.size());
m_piece_hash.resize(m_num_pieces);
if (m_num_pieces > old_num_pieces)
std::for_each(m_piece_hash.begin() + old_num_pieces
, m_piece_hash.end(), boost::bind(&sha1_hash::clear, _1));
}
void create_torrent::add_node(std::pair<std::string, int> const& node) void create_torrent::add_node(std::pair<std::string, int> const& node)
{ {
m_nodes.push_back(node); m_nodes.push_back(node);
@ -299,5 +256,6 @@ namespace libtorrent
{ {
m_created_by = str; m_created_by = str;
} }
} }

View File

@ -1049,6 +1049,13 @@ namespace libtorrent
ret = 0; ret = 0;
break; break;
} }
case disk_io_job::rename_file:
{
#ifdef TORRENT_DISK_STATS
m_log << log_time() << " rename file" << std::endl;
#endif
ret = j.storage->rename_file_impl(j.piece, j.str);
}
} }
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
} catch (std::exception& e) } catch (std::exception& e)

View File

@ -115,6 +115,16 @@ namespace libtorrent
return e.file_ptr; return e.file_ptr;
} }
void file_pool::release(fs::path const& p)
{
boost::mutex::scoped_lock l(m_mutex);
typedef nth_index<file_set, 0>::type path_view;
path_view& pt = get<0>(m_files);
path_view::iterator i = pt.find(p);
if (i != pt.end()) pt.erase(i);
}
void file_pool::release(void* st) void file_pool::release(void* st)
{ {
boost::mutex::scoped_lock l(m_mutex); boost::mutex::scoped_lock l(m_mutex);

150
src/file_storage.cpp Normal file
View File

@ -0,0 +1,150 @@
/*
Copyright (c) 2003-2008, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/pch.hpp"
#include "libtorrent/file_storage.hpp"
namespace libtorrent
{
file_storage::file_storage()
: m_piece_length(0)
, m_total_size(0)
, m_num_pieces(0)
{}
int file_storage::piece_size(int index) const
{
TORRENT_ASSERT(index >= 0 && index < num_pieces());
if (index == num_pieces()-1)
{
int size = int(total_size()
- size_type(num_pieces() - 1) * piece_length());
TORRENT_ASSERT(size > 0);
TORRENT_ASSERT(size <= piece_length());
return int(size);
}
else
return piece_length();
}
void file_storage::rename_file(int index, std::string const& new_filename)
{
TORRENT_ASSERT(index >= 0 && index < int(m_files.size()));
m_files[index].path = new_filename;
}
std::vector<file_slice> file_storage::map_block(int piece, size_type offset
, int size_) const
{
TORRENT_ASSERT(num_files() > 0);
std::vector<file_slice> ret;
size_type start = piece * (size_type)m_piece_length + offset;
size_type size = size_;
TORRENT_ASSERT(start + size <= m_total_size);
// find the file iterator and file offset
// TODO: make a vector that can map piece -> file index in O(1)
size_type file_offset = start;
std::vector<file_entry>::const_iterator file_iter;
int counter = 0;
for (file_iter = begin();; ++counter, ++file_iter)
{
TORRENT_ASSERT(file_iter != end());
if (file_offset < file_iter->size)
{
file_slice f;
f.file_index = counter;
f.offset = file_offset + file_iter->file_base;
f.size = (std::min)(file_iter->size - file_offset, (size_type)size);
size -= f.size;
file_offset += f.size;
ret.push_back(f);
}
TORRENT_ASSERT(size >= 0);
if (size <= 0) break;
file_offset -= file_iter->size;
}
return ret;
}
peer_request file_storage::map_file(int file_index, size_type file_offset
, int size) const
{
TORRENT_ASSERT(file_index < num_files());
TORRENT_ASSERT(file_index >= 0);
size_type offset = file_offset + at(file_index).offset;
peer_request ret;
ret.piece = int(offset / piece_length());
ret.start = int(offset - ret.piece * piece_length());
ret.length = size;
return ret;
}
void file_storage::add_file(fs::path const& file, size_type size)
{
TORRENT_ASSERT(size >= 0);
if (!file.has_branch_path())
{
// you have already added at least one file with a
// path to the file (branch_path), which means that
// all the other files need to be in the same top
// directory as the first file.
TORRENT_ASSERT(m_files.empty());
m_name = file.string();
}
else
{
if (m_files.empty())
m_name = *file.begin();
}
TORRENT_ASSERT(m_name == *file.begin());
file_entry e;
m_files.push_back(e);
m_files.back().size = size;
m_files.back().path = file;
m_files.back().offset = m_total_size;
m_total_size += size;
}
void file_storage::add_file(file_entry const& e)
{
add_file(e.path, e.size);
}
}

View File

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

View File

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

View File

@ -251,12 +251,12 @@ namespace libtorrent
{ {
std::vector<std::pair<size_type, std::time_t> > get_filesizes( std::vector<std::pair<size_type, std::time_t> > get_filesizes(
torrent_info const& t, fs::path p) file_storage const& s, fs::path p)
{ {
p = complete(p); p = complete(p);
std::vector<std::pair<size_type, std::time_t> > sizes; std::vector<std::pair<size_type, std::time_t> > sizes;
for (torrent_info::file_iterator i = t.begin_files(true); for (file_storage::iterator i = s.begin()
i != t.end_files(true); ++i) , end(s.end());i != end; ++i)
{ {
size_type size = 0; size_type size = 0;
std::time_t time = 0; std::time_t time = 0;
@ -289,13 +289,13 @@ namespace libtorrent
// pieces, so any older version of the resume data will // pieces, so any older version of the resume data will
// still be a correct subset of the actual data on disk. // still be a correct subset of the actual data on disk.
bool match_filesizes( bool match_filesizes(
torrent_info const& t file_storage const& fs
, fs::path p , fs::path p
, std::vector<std::pair<size_type, std::time_t> > const& sizes , std::vector<std::pair<size_type, std::time_t> > const& sizes
, bool compact_mode , bool compact_mode
, std::string* error) , std::string* error)
{ {
if ((int)sizes.size() != t.num_files(true)) if ((int)sizes.size() != fs.num_files())
{ {
if (error) *error = "mismatching number of files"; if (error) *error = "mismatching number of files";
return false; return false;
@ -304,8 +304,8 @@ namespace libtorrent
std::vector<std::pair<size_type, std::time_t> >::const_iterator s std::vector<std::pair<size_type, std::time_t> >::const_iterator s
= sizes.begin(); = sizes.begin();
for (torrent_info::file_iterator i = t.begin_files(true); for (file_storage::iterator i = fs.begin()
i != t.end_files(true); ++i, ++s) , end(fs.end());i != end; ++i, ++s)
{ {
size_type size = 0; size_type size = 0;
std::time_t time = 0; std::time_t time = 0;
@ -354,15 +354,16 @@ namespace libtorrent
class storage : public storage_interface, boost::noncopyable class storage : public storage_interface, boost::noncopyable
{ {
public: public:
storage(boost::intrusive_ptr<torrent_info const> info, fs::path const& path, file_pool& fp) storage(file_storage const& fs, fs::path const& path, file_pool& fp)
: m_info(info) : m_files(fs)
, m_files(fp) , m_pool(fp)
{ {
TORRENT_ASSERT(info->begin_files(true) != info->end_files(true)); TORRENT_ASSERT(m_files.begin() != m_files.end());
m_save_path = fs::complete(path); m_save_path = fs::complete(path);
TORRENT_ASSERT(m_save_path.is_complete()); TORRENT_ASSERT(m_save_path.is_complete());
} }
bool rename_file(int index, std::string const& new_filename);
bool release_files(); bool release_files();
bool delete_files(); bool delete_files();
bool initialize(bool allocate_files); bool initialize(bool allocate_files);
@ -379,14 +380,18 @@ namespace libtorrent
int read_impl(char* buf, int slot, int offset, int size, bool fill_zero); int read_impl(char* buf, int slot, int offset, int size, bool fill_zero);
~storage() ~storage()
{ m_files.release(this); } { m_pool.release(this); }
file_storage const& files() const { return m_mapped_files?*m_mapped_files:m_files; }
boost::scoped_ptr<file_storage> m_mapped_files;
file_storage const& m_files;
boost::intrusive_ptr<torrent_info const> m_info;
fs::path m_save_path; fs::path m_save_path;
// the file pool is typically stored in // the file pool is typically stored in
// the session, to make all storage // the session, to make all storage
// instances use the same pool // instances use the same pool
file_pool& m_files; file_pool& m_pool;
// temporary storage for moving pieces // temporary storage for moving pieces
buffer m_scratch_buffer; buffer m_scratch_buffer;
@ -399,7 +404,7 @@ namespace libtorrent
hasher whole; hasher whole;
int slot_size1 = piece_size; int slot_size1 = piece_size;
m_scratch_buffer.resize(slot_size1); m_scratch_buffer.resize(slot_size1);
int read_result = read_impl(&m_scratch_buffer[0], slot, 0, slot_size1, true); read_impl(&m_scratch_buffer[0], slot, 0, slot_size1, true);
if (ph.offset > 0) if (ph.offset > 0)
partial.update(&m_scratch_buffer[0], ph.offset); partial.update(&m_scratch_buffer[0], ph.offset);
whole.update(&m_scratch_buffer[0], slot_size1); whole.update(&m_scratch_buffer[0], slot_size1);
@ -426,8 +431,8 @@ namespace libtorrent
{ {
// first, create all missing directories // first, create all missing directories
fs::path last_path; fs::path last_path;
for (torrent_info::file_iterator file_iter = m_info->begin_files(true), for (file_storage::iterator file_iter = files().begin(),
end_iter = m_info->end_files(true); file_iter != end_iter; ++file_iter) end_iter = files().end(); file_iter != end_iter; ++file_iter)
{ {
fs::path dir = (m_save_path / file_iter->path).branch_path(); fs::path dir = (m_save_path / file_iter->path).branch_path();
@ -475,7 +480,7 @@ namespace libtorrent
if (allocate_files) if (allocate_files)
{ {
std::string error; std::string error;
boost::shared_ptr<file> f = m_files.open_file(this boost::shared_ptr<file> f = m_pool.open_file(this
, m_save_path / file_iter->path, file::in | file::out , m_save_path / file_iter->path, file::in | file::out
, error); , error);
if (f && f->error().empty()) if (f && f->error().empty())
@ -491,13 +496,46 @@ namespace libtorrent
#endif #endif
} }
// close files that were opened in write mode // close files that were opened in write mode
m_files.release(this); m_pool.release(this);
return false;
}
bool storage::rename_file(int index, std::string const& new_filename)
{
if (index < 0 || index >= m_files.num_files()) return true;
fs::path old_name = m_save_path / files().at(index).path;
m_pool.release(old_name);
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
fs::wpath old_path = safe_convert(old_name);
fs::wpath new_path = safe_convert(m_save_path / new_filename);
#else
fs::path const& old_path = old_name;
fs::path new_path = m_save_path / new_filename;
#endif
#ifndef BOOST_NO_EXCEPTIONS
try
{
#endif
rename(old_path, new_path);
if (!m_mapped_files)
{ m_mapped_files.reset(new file_storage(m_files)); }
m_mapped_files->rename_file(index, new_filename);
#ifndef BOOST_NO_EXCEPTIONS
}
catch (std::exception& e)
{
set_error(old_name.string(), e.what());
return true;
}
#endif
return false; return false;
} }
bool storage::release_files() bool storage::release_files()
{ {
m_files.release(this); m_pool.release(this);
buffer().swap(m_scratch_buffer); buffer().swap(m_scratch_buffer);
return false; return false;
} }
@ -505,7 +543,7 @@ namespace libtorrent
bool storage::delete_files() bool storage::delete_files()
{ {
// make sure we don't have the files open // make sure we don't have the files open
m_files.release(this); m_pool.release(this);
buffer().swap(m_scratch_buffer); buffer().swap(m_scratch_buffer);
int result = 0; int result = 0;
@ -515,8 +553,8 @@ namespace libtorrent
// delete the files from disk // delete the files from disk
std::set<std::string> directories; std::set<std::string> directories;
typedef std::set<std::string>::iterator iter_t; typedef std::set<std::string>::iterator iter_t;
for (torrent_info::file_iterator i = m_info->begin_files(true) for (file_storage::iterator i = files().begin()
, end(m_info->end_files(true)); i != end; ++i) , end(files().end()); i != end; ++i)
{ {
std::string p = (m_save_path / i->path).string(); std::string p = (m_save_path / i->path).string();
fs::path bp = i->path.branch_path(); fs::path bp = i->path.branch_path();
@ -584,7 +622,7 @@ namespace libtorrent
TORRENT_ASSERT(rd.type() == entry::dictionary_t); TORRENT_ASSERT(rd.type() == entry::dictionary_t);
std::vector<std::pair<size_type, std::time_t> > file_sizes std::vector<std::pair<size_type, std::time_t> > file_sizes
= get_filesizes(*m_info, m_save_path); = get_filesizes(files(), m_save_path);
entry::list_type& fl = rd["file sizes"].list(); entry::list_type& fl = rd["file sizes"].list();
for (std::vector<std::pair<size_type, std::time_t> >::iterator i for (std::vector<std::pair<size_type, std::time_t> >::iterator i
@ -642,7 +680,7 @@ namespace libtorrent
} }
entry::list_type const& slots = slots_ent->list(); entry::list_type const& slots = slots_ent->list();
bool seed = int(slots.size()) == m_info->num_pieces() bool seed = int(slots.size()) == m_files.num_pieces()
&& std::find_if(slots.begin(), slots.end() && std::find_if(slots.begin(), slots.end()
, boost::bind<bool>(std::less<int>() , boost::bind<bool>(std::less<int>()
, boost::bind((size_type const& (entry::*)() const) , boost::bind((size_type const& (entry::*)() const)
@ -655,11 +693,11 @@ namespace libtorrent
if (seed) if (seed)
{ {
if (m_info->num_files(true) != (int)file_sizes.size()) if (m_files.num_files() != (int)file_sizes.size())
{ {
error = "the number of files does not match the torrent (num: " error = "the number of files does not match the torrent (num: "
+ boost::lexical_cast<std::string>(file_sizes.size()) + " actual: " + boost::lexical_cast<std::string>(file_sizes.size()) + " actual: "
+ boost::lexical_cast<std::string>(m_info->num_files(true)) + ")"; + boost::lexical_cast<std::string>(m_files.num_files()) + ")";
return false; return false;
} }
@ -667,8 +705,8 @@ namespace libtorrent
fs = file_sizes.begin(); fs = file_sizes.begin();
// the resume data says we have the entire torrent // the resume data says we have the entire torrent
// make sure the file sizes are the right ones // make sure the file sizes are the right ones
for (torrent_info::file_iterator i = m_info->begin_files(true) for (file_storage::iterator i = files().begin()
, end(m_info->end_files(true)); i != end; ++i, ++fs) , end(files().end()); i != end; ++i, ++fs)
{ {
if (i->size != fs->first) if (i->size != fs->first)
{ {
@ -680,7 +718,7 @@ namespace libtorrent
} }
} }
return match_filesizes(*m_info, m_save_path, file_sizes return match_filesizes(files(), m_save_path, file_sizes
, !full_allocation_mode, &error); , !full_allocation_mode, &error);
} }
@ -716,14 +754,14 @@ namespace libtorrent
return false; return false;
#endif #endif
m_files.release(this); m_pool.release(this);
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400 #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
old_path = safe_convert((m_save_path / m_info->name()).string()); old_path = safe_convert((m_save_path / files().name()).string());
new_path = safe_convert((save_path / m_info->name()).string()); new_path = safe_convert((save_path / files().name()).string());
#else #else
old_path = m_save_path / m_info->name(); old_path = m_save_path / files().name();
new_path = save_path / m_info->name(); new_path = save_path / files().name();
#endif #endif
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
@ -740,16 +778,20 @@ namespace libtorrent
return true; return true;
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
} }
catch (std::exception&) {} catch (std::exception& e)
return false; {
set_error((m_save_path / files().name()).string(), e.what());
return true;
}
#endif #endif
return false;
} }
#ifndef NDEBUG #ifndef NDEBUG
/* /*
void storage::shuffle() void storage::shuffle()
{ {
int num_pieces = m_info->num_pieces(); int num_pieces = files().num_pieces();
std::vector<int> pieces(num_pieces); std::vector<int> pieces(num_pieces);
for (std::vector<int>::iterator i = pieces.begin(); for (std::vector<int>::iterator i = pieces.begin();
@ -766,7 +808,7 @@ namespace libtorrent
{ {
const int slot_index = targets[i]; const int slot_index = targets[i];
const int piece_index = pieces[i]; const int piece_index = pieces[i];
const int slot_size =static_cast<int>(m_info->piece_size(slot_index)); const int slot_size =static_cast<int>(m_files.piece_size(slot_index));
std::vector<char> buf(slot_size); std::vector<char> buf(slot_size);
read(&buf[0], piece_index, 0, slot_size); read(&buf[0], piece_index, 0, slot_size);
write(&buf[0], slot_index, 0, slot_size); write(&buf[0], slot_index, 0, slot_size);
@ -777,7 +819,7 @@ namespace libtorrent
bool storage::move_slot(int src_slot, int dst_slot) bool storage::move_slot(int src_slot, int dst_slot)
{ {
int piece_size = m_info->piece_size(dst_slot); int piece_size = m_files.piece_size(dst_slot);
m_scratch_buffer.resize(piece_size); m_scratch_buffer.resize(piece_size);
int ret1 = read_impl(&m_scratch_buffer[0], src_slot, 0, piece_size, true); int ret1 = read_impl(&m_scratch_buffer[0], src_slot, 0, piece_size, true);
int ret2 = write(&m_scratch_buffer[0], dst_slot, 0, piece_size); int ret2 = write(&m_scratch_buffer[0], dst_slot, 0, piece_size);
@ -787,9 +829,9 @@ namespace libtorrent
bool storage::swap_slots(int slot1, int slot2) bool storage::swap_slots(int slot1, int slot2)
{ {
// the size of the target slot is the size of the piece // the size of the target slot is the size of the piece
int piece_size = m_info->piece_length(); int piece_size = m_files.piece_length();
int piece1_size = m_info->piece_size(slot2); int piece1_size = m_files.piece_size(slot2);
int piece2_size = m_info->piece_size(slot1); int piece2_size = m_files.piece_size(slot1);
m_scratch_buffer.resize(piece_size * 2); m_scratch_buffer.resize(piece_size * 2);
int ret1 = read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true); int ret1 = read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true);
int ret2 = read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true); int ret2 = read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true);
@ -802,10 +844,10 @@ namespace libtorrent
bool storage::swap_slots3(int slot1, int slot2, int slot3) bool storage::swap_slots3(int slot1, int slot2, int slot3)
{ {
// the size of the target slot is the size of the piece // the size of the target slot is the size of the piece
int piece_size = m_info->piece_length(); int piece_size = m_files.piece_length();
int piece1_size = m_info->piece_size(slot2); int piece1_size = m_files.piece_size(slot2);
int piece2_size = m_info->piece_size(slot3); int piece2_size = m_files.piece_size(slot3);
int piece3_size = m_info->piece_size(slot1); int piece3_size = m_files.piece_size(slot1);
m_scratch_buffer.resize(piece_size * 2); m_scratch_buffer.resize(piece_size * 2);
int ret1 = read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true); int ret1 = read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true);
int ret2 = read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true); int ret2 = read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true);
@ -835,25 +877,25 @@ namespace libtorrent
, bool fill_zero) , bool fill_zero)
{ {
TORRENT_ASSERT(buf != 0); TORRENT_ASSERT(buf != 0);
TORRENT_ASSERT(slot >= 0 && slot < m_info->num_pieces()); TORRENT_ASSERT(slot >= 0 && slot < m_files.num_pieces());
TORRENT_ASSERT(offset >= 0); TORRENT_ASSERT(offset >= 0);
TORRENT_ASSERT(offset < m_info->piece_size(slot)); TORRENT_ASSERT(offset < m_files.piece_size(slot));
TORRENT_ASSERT(size > 0); TORRENT_ASSERT(size > 0);
#ifndef NDEBUG #ifndef NDEBUG
std::vector<file_slice> slices std::vector<file_slice> slices
= m_info->map_block(slot, offset, size, true); = files().map_block(slot, offset, size);
TORRENT_ASSERT(!slices.empty()); TORRENT_ASSERT(!slices.empty());
#endif #endif
size_type start = slot * (size_type)m_info->piece_length() + offset; size_type start = slot * (size_type)m_files.piece_length() + offset;
TORRENT_ASSERT(start + size <= m_info->total_size()); TORRENT_ASSERT(start + size <= m_files.total_size());
// find the file iterator and file offset // find the file iterator and file offset
size_type file_offset = start; size_type file_offset = start;
std::vector<file_entry>::const_iterator file_iter; std::vector<file_entry>::const_iterator file_iter;
for (file_iter = m_info->begin_files(true);;) for (file_iter = files().begin();;)
{ {
if (file_offset < file_iter->size) if (file_offset < file_iter->size)
break; break;
@ -864,7 +906,7 @@ namespace libtorrent
int buf_pos = 0; int buf_pos = 0;
std::string error; std::string error;
boost::shared_ptr<file> in(m_files.open_file( boost::shared_ptr<file> in(m_pool.open_file(
this, m_save_path / file_iter->path, file::in this, m_save_path / file_iter->path, file::in
, error)); , error));
if (!in) if (!in)
@ -899,7 +941,7 @@ namespace libtorrent
#endif #endif
int left_to_read = size; int left_to_read = size;
int slot_size = static_cast<int>(m_info->piece_size(slot)); int slot_size = static_cast<int>(m_files.piece_size(slot));
if (offset + left_to_read > slot_size) if (offset + left_to_read > slot_size)
left_to_read = slot_size - offset; left_to_read = slot_size - offset;
@ -924,7 +966,7 @@ namespace libtorrent
TORRENT_ASSERT(int(slices.size()) > counter); TORRENT_ASSERT(int(slices.size()) > counter);
size_type slice_size = slices[counter].size; size_type slice_size = slices[counter].size;
TORRENT_ASSERT(slice_size == read_bytes); TORRENT_ASSERT(slice_size == read_bytes);
TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path TORRENT_ASSERT(files().at(slices[counter].file_index).path
== file_iter->path); == file_iter->path);
#endif #endif
@ -961,7 +1003,7 @@ namespace libtorrent
file_offset = 0; file_offset = 0;
std::string error; std::string error;
in = m_files.open_file( in = m_pool.open_file(
this, path, file::in, error); this, path, file::in, error);
if (!in) if (!in)
{ {
@ -997,35 +1039,35 @@ namespace libtorrent
{ {
TORRENT_ASSERT(buf != 0); TORRENT_ASSERT(buf != 0);
TORRENT_ASSERT(slot >= 0); TORRENT_ASSERT(slot >= 0);
TORRENT_ASSERT(slot < m_info->num_pieces()); TORRENT_ASSERT(slot < m_files.num_pieces());
TORRENT_ASSERT(offset >= 0); TORRENT_ASSERT(offset >= 0);
TORRENT_ASSERT(size > 0); TORRENT_ASSERT(size > 0);
#ifndef NDEBUG #ifndef NDEBUG
std::vector<file_slice> slices std::vector<file_slice> slices
= m_info->map_block(slot, offset, size, true); = files().map_block(slot, offset, size);
TORRENT_ASSERT(!slices.empty()); TORRENT_ASSERT(!slices.empty());
#endif #endif
size_type start = slot * (size_type)m_info->piece_length() + offset; size_type start = slot * (size_type)m_files.piece_length() + offset;
// find the file iterator and file offset // find the file iterator and file offset
size_type file_offset = start; size_type file_offset = start;
std::vector<file_entry>::const_iterator file_iter; std::vector<file_entry>::const_iterator file_iter;
for (file_iter = m_info->begin_files(true);;) for (file_iter = files().begin();;)
{ {
if (file_offset < file_iter->size) if (file_offset < file_iter->size)
break; break;
file_offset -= file_iter->size; file_offset -= file_iter->size;
++file_iter; ++file_iter;
TORRENT_ASSERT(file_iter != m_info->end_files(true)); TORRENT_ASSERT(file_iter != files().end());
} }
fs::path p(m_save_path / file_iter->path); fs::path p(m_save_path / file_iter->path);
std::string error; std::string error;
boost::shared_ptr<file> out = m_files.open_file( boost::shared_ptr<file> out = m_pool.open_file(
this, p, file::out | file::in, error); this, p, file::out | file::in, error);
if (!out) if (!out)
@ -1050,7 +1092,7 @@ namespace libtorrent
} }
int left_to_write = size; int left_to_write = size;
int slot_size = static_cast<int>(m_info->piece_size(slot)); int slot_size = static_cast<int>(m_files.piece_size(slot));
if (offset + left_to_write > slot_size) if (offset + left_to_write > slot_size)
left_to_write = slot_size - offset; left_to_write = slot_size - offset;
@ -1074,7 +1116,7 @@ namespace libtorrent
{ {
TORRENT_ASSERT(int(slices.size()) > counter); TORRENT_ASSERT(int(slices.size()) > counter);
TORRENT_ASSERT(slices[counter].size == write_bytes); TORRENT_ASSERT(slices[counter].size == write_bytes);
TORRENT_ASSERT(m_info->file_at(slices[counter].file_index, true).path TORRENT_ASSERT(files().at(slices[counter].file_index).path
== file_iter->path); == file_iter->path);
TORRENT_ASSERT(buf_pos >= 0); TORRENT_ASSERT(buf_pos >= 0);
@ -1101,11 +1143,11 @@ namespace libtorrent
#endif #endif
++file_iter; ++file_iter;
TORRENT_ASSERT(file_iter != m_info->end_files(true)); TORRENT_ASSERT(file_iter != files().end());
fs::path p = m_save_path / file_iter->path; fs::path p = m_save_path / file_iter->path;
file_offset = 0; file_offset = 0;
std::string error; std::string error;
out = m_files.open_file( out = m_pool.open_file(
this, p, file::out | file::in, error); this, p, file::out | file::in, error);
if (!out) if (!out)
@ -1131,25 +1173,26 @@ namespace libtorrent
return size; return size;
} }
storage_interface* default_storage_constructor(boost::intrusive_ptr<torrent_info const> ti storage_interface* default_storage_constructor(file_storage const& fs
, fs::path const& path, file_pool& fp) , fs::path const& path, file_pool& fp)
{ {
return new storage(ti, path, fp); return new storage(fs, path, fp);
} }
// -- piece_manager ----------------------------------------------------- // -- piece_manager -----------------------------------------------------
piece_manager::piece_manager( piece_manager::piece_manager(
boost::shared_ptr<void> const& torrent boost::shared_ptr<void> const& torrent
, boost::intrusive_ptr<torrent_info const> ti , boost::intrusive_ptr<torrent_info const> info
, fs::path const& save_path , fs::path const& save_path
, file_pool& fp , file_pool& fp
, disk_io_thread& io , disk_io_thread& io
, storage_constructor_type sc , storage_constructor_type sc
, storage_mode_t sm) , storage_mode_t sm)
: m_storage(sc(ti, save_path, fp)) : m_info(info)
, m_files(m_info->files())
, m_storage(sc(m_files, save_path, fp))
, m_storage_mode(sm) , m_storage_mode(sm)
, m_info(ti)
, m_save_path(complete(save_path)) , m_save_path(complete(save_path))
, m_state(state_none) , m_state(state_none)
, m_current_slot(0) , m_current_slot(0)
@ -1213,6 +1256,17 @@ namespace libtorrent
m_io_thread.add_job(j, handler); m_io_thread.add_job(j, handler);
} }
void piece_manager::async_rename_file(int index, std::string const& name
, boost::function<void(int, disk_io_job const&)> const& handler)
{
disk_io_job j;
j.storage = this;
j.piece = index;
j.str = name;
j.action = disk_io_job::rename_file;
m_io_thread.add_job(j, handler);
}
void piece_manager::async_check_files( void piece_manager::async_check_files(
boost::function<void(int, disk_io_job const&)> const& handler) boost::function<void(int, disk_io_job const&)> const& handler)
{ {
@ -1241,6 +1295,8 @@ namespace libtorrent
m_io_thread.add_job(j, handler); m_io_thread.add_job(j, handler);
#ifndef NDEBUG #ifndef NDEBUG
boost::recursive_mutex::scoped_lock l(m_mutex); boost::recursive_mutex::scoped_lock l(m_mutex);
// if this assert is hit, it suggests
// that check_files was not successful
TORRENT_ASSERT(slot_for(r.piece) >= 0); TORRENT_ASSERT(slot_for(r.piece) >= 0);
#endif #endif
} }
@ -1295,7 +1351,7 @@ namespace libtorrent
int slot = slot_for(piece); int slot = slot_for(piece);
TORRENT_ASSERT(slot != has_no_slot); TORRENT_ASSERT(slot != has_no_slot);
return m_storage->hash_for_slot(slot, ph, m_info->piece_size(piece)); return m_storage->hash_for_slot(slot, ph, m_files.piece_size(piece));
} }
bool piece_manager::move_storage_impl(fs::path const& save_path) bool piece_manager::move_storage_impl(fs::path const& save_path)
@ -1373,7 +1429,7 @@ namespace libtorrent
TORRENT_ASSERT(buf); TORRENT_ASSERT(buf);
TORRENT_ASSERT(offset >= 0); TORRENT_ASSERT(offset >= 0);
TORRENT_ASSERT(size > 0); TORRENT_ASSERT(size > 0);
TORRENT_ASSERT(piece_index >= 0 && piece_index < m_info->num_pieces()); TORRENT_ASSERT(piece_index >= 0 && piece_index < m_files.num_pieces());
int slot = allocate_slot_for_piece(piece_index); int slot = allocate_slot_for_piece(piece_index);
int ret = m_storage->write(buf, slot, offset, size); int ret = m_storage->write(buf, slot, offset, size);
@ -1455,9 +1511,9 @@ namespace libtorrent
{ {
// INVARIANT_CHECK; // INVARIANT_CHECK;
const int piece_size = static_cast<int>(m_info->piece_length()); const int piece_size = static_cast<int>(m_files.piece_length());
const int last_piece_size = static_cast<int>(m_info->piece_size( const int last_piece_size = static_cast<int>(m_files.piece_size(
m_info->num_pieces() - 1)); m_files.num_pieces() - 1));
TORRENT_ASSERT((int)piece_data.size() >= last_piece_size); TORRENT_ASSERT((int)piece_data.size() >= last_piece_size);
@ -1579,8 +1635,8 @@ namespace libtorrent
int piece_manager::check_no_fastresume(std::string& error) int piece_manager::check_no_fastresume(std::string& error)
{ {
torrent_info::file_iterator i = m_info->begin_files(true); file_storage::iterator i = m_files.begin();
torrent_info::file_iterator end = m_info->end_files(true); file_storage::iterator end = m_files.end();
for (; i != end; ++i) for (; i != end; ++i)
{ {
@ -1612,9 +1668,9 @@ namespace libtorrent
{ {
m_state = state_full_check; m_state = state_full_check;
m_piece_to_slot.clear(); m_piece_to_slot.clear();
m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot); m_piece_to_slot.resize(m_files.num_pieces(), has_no_slot);
m_slot_to_piece.clear(); m_slot_to_piece.clear();
m_slot_to_piece.resize(m_info->num_pieces(), unallocated); m_slot_to_piece.resize(m_files.num_pieces(), unallocated);
if (m_storage_mode == storage_mode_compact) if (m_storage_mode == storage_mode_compact)
{ {
m_unallocated_slots.clear(); m_unallocated_slots.clear();
@ -1629,12 +1685,12 @@ namespace libtorrent
// in compact mode without checking, we need to // in compact mode without checking, we need to
// populate the unallocated list // populate the unallocated list
TORRENT_ASSERT(m_unallocated_slots.empty()); TORRENT_ASSERT(m_unallocated_slots.empty());
for (int i = 0, end(m_info->num_pieces()); i < end; ++i) for (int i = 0, end(m_files.num_pieces()); i < end; ++i)
m_unallocated_slots.push_back(i); m_unallocated_slots.push_back(i);
m_piece_to_slot.clear(); m_piece_to_slot.clear();
m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot); m_piece_to_slot.resize(m_files.num_pieces(), has_no_slot);
m_slot_to_piece.clear(); m_slot_to_piece.clear();
m_slot_to_piece.resize(m_info->num_pieces(), unallocated); m_slot_to_piece.resize(m_files.num_pieces(), unallocated);
} }
return check_init_storage(error); return check_init_storage(error);
@ -1675,7 +1731,7 @@ namespace libtorrent
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_ASSERT(m_info->piece_length() > 0); TORRENT_ASSERT(m_files.piece_length() > 0);
// if we don't have any resume data, return // if we don't have any resume data, return
if (rd.type() == entry::undefined_t) return check_no_fastresume(error); if (rd.type() == entry::undefined_t) return check_no_fastresume(error);
@ -1686,38 +1742,11 @@ namespace libtorrent
return check_no_fastresume(error); return check_no_fastresume(error);
} }
entry const* file_format = rd.find_key("file-format"); int block_size = (std::min)(16 * 1024, m_files.piece_length());
if (file_format == 0 || file_format->type() != entry::string_t)
{
error = "missing file format tag";
return check_no_fastresume(error);
}
if (file_format->string() != "libtorrent resume file")
{
error = "invalid file format tag";
return check_no_fastresume(error);
}
entry const* info_hash = rd.find_key("info-hash");
if (info_hash == 0 || info_hash->type() != entry::string_t)
{
error = "missing info-hash";
return check_no_fastresume(error);
}
if (sha1_hash(info_hash->string()) != m_info->info_hash())
{
error = "mismatching info-hash";
return check_no_fastresume(error);
}
int block_size = (std::min)(16 * 1024, m_info->piece_length());
entry const* blocks_per_piece_ent = rd.find_key("blocks per piece"); entry const* blocks_per_piece_ent = rd.find_key("blocks per piece");
if (blocks_per_piece_ent != 0 if (blocks_per_piece_ent != 0
&& blocks_per_piece_ent->type() == entry::int_t && blocks_per_piece_ent->type() == entry::int_t
&& blocks_per_piece_ent->integer() != m_info->piece_length() / block_size) && blocks_per_piece_ent->integer() != m_files.piece_length() / block_size)
{ {
error = "invalid 'blocks per piece' entry"; error = "invalid 'blocks per piece' entry";
return check_no_fastresume(error); return check_no_fastresume(error);
@ -1746,17 +1775,17 @@ namespace libtorrent
return check_no_fastresume(error); return check_no_fastresume(error);
} }
if ((int)slots->list().size() > m_info->num_pieces()) if ((int)slots->list().size() > m_files.num_pieces())
{ {
error = "file has more slots than torrent (slots: " error = "file has more slots than torrent (slots: "
+ boost::lexical_cast<std::string>(slots->list().size()) + " size: " + boost::lexical_cast<std::string>(slots->list().size()) + " size: "
+ boost::lexical_cast<std::string>(m_info->num_pieces()) + " )"; + boost::lexical_cast<std::string>(m_files.num_pieces()) + " )";
return check_no_fastresume(error); return check_no_fastresume(error);
} }
if (storage_mode == storage_mode_compact) if (storage_mode == storage_mode_compact)
{ {
int num_pieces = int(m_info->num_pieces()); int num_pieces = int(m_files.num_pieces());
m_slot_to_piece.resize(num_pieces, unallocated); m_slot_to_piece.resize(num_pieces, unallocated);
m_piece_to_slot.resize(num_pieces, has_no_slot); m_piece_to_slot.resize(num_pieces, has_no_slot);
int slot = 0; int slot = 0;
@ -1877,7 +1906,7 @@ namespace libtorrent
// is finished // is finished
int piece_manager::check_files(int& current_slot, int& have_piece, std::string& error) int piece_manager::check_files(int& current_slot, int& have_piece, std::string& error)
{ {
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_info->num_pieces()); TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces());
current_slot = m_current_slot; current_slot = m_current_slot;
have_piece = -1; have_piece = -1;
@ -1894,9 +1923,9 @@ namespace libtorrent
if (other_piece >= 0) if (other_piece >= 0)
{ {
if (m_scratch_buffer2.empty()) if (m_scratch_buffer2.empty())
m_scratch_buffer2.resize(m_info->piece_length()); m_scratch_buffer2.resize(m_files.piece_length());
int piece_size = m_info->piece_size(other_piece); int piece_size = m_files.piece_size(other_piece);
if (m_storage->read(&m_scratch_buffer2[0], piece, 0, piece_size) if (m_storage->read(&m_scratch_buffer2[0], piece, 0, piece_size)
!= piece_size) != piece_size)
{ {
@ -1910,7 +1939,7 @@ namespace libtorrent
// the slot where this piece belongs is // the slot where this piece belongs is
// free. Just move the piece there. // free. Just move the piece there.
int piece_size = m_info->piece_size(piece); int piece_size = m_files.piece_size(piece);
if (m_storage->write(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size) if (m_storage->write(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size)
{ {
error = m_storage->error(); error = m_storage->error();
@ -1926,19 +1955,19 @@ namespace libtorrent
return need_full_check; return need_full_check;
} }
while (m_current_slot < m_info->num_pieces() while (m_current_slot < m_files.num_pieces()
&& (m_slot_to_piece[m_current_slot] == m_current_slot && (m_slot_to_piece[m_current_slot] == m_current_slot
|| m_slot_to_piece[m_current_slot] < 0)) || m_slot_to_piece[m_current_slot] < 0))
{ {
++m_current_slot; ++m_current_slot;
} }
if (m_current_slot == m_info->num_pieces()) if (m_current_slot == m_files.num_pieces())
{ {
return check_init_storage(error); return check_init_storage(error);
} }
TORRENT_ASSERT(m_current_slot < m_info->num_pieces()); TORRENT_ASSERT(m_current_slot < m_files.num_pieces());
int piece = m_slot_to_piece[m_current_slot]; int piece = m_slot_to_piece[m_current_slot];
TORRENT_ASSERT(piece >= 0); TORRENT_ASSERT(piece >= 0);
@ -1949,9 +1978,9 @@ namespace libtorrent
// where this one goes. Store it in the scratch // where this one goes. Store it in the scratch
// buffer until next iteration. // buffer until next iteration.
if (m_scratch_buffer.empty()) if (m_scratch_buffer.empty())
m_scratch_buffer.resize(m_info->piece_length()); m_scratch_buffer.resize(m_files.piece_length());
int piece_size = m_info->piece_size(other_piece); int piece_size = m_files.piece_size(other_piece);
if (m_storage->read(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size) if (m_storage->read(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size)
{ {
error = m_storage->error(); error = m_storage->error();
@ -1975,7 +2004,7 @@ namespace libtorrent
TORRENT_ASSERT(m_state == state_full_check); TORRENT_ASSERT(m_state == state_full_check);
bool skip = check_one_piece(have_piece); bool skip = check_one_piece(have_piece);
TORRENT_ASSERT(m_current_slot <= m_info->num_pieces()); TORRENT_ASSERT(m_current_slot <= m_files.num_pieces());
if (skip) if (skip)
{ {
@ -1984,9 +2013,9 @@ namespace libtorrent
// completely. We should skip all pieces belonging to that file. // completely. We should skip all pieces belonging to that file.
// find the file that failed, and skip all the pieces in that file // find the file that failed, and skip all the pieces in that file
size_type file_offset = 0; size_type file_offset = 0;
size_type current_offset = size_type(m_current_slot) * m_info->piece_length(); size_type current_offset = size_type(m_current_slot) * m_files.piece_length();
for (torrent_info::file_iterator i = m_info->begin_files(true); for (file_storage::iterator i = m_files.begin()
i != m_info->end_files(true); ++i) , end(m_files.end()); i != end; ++i)
{ {
file_offset += i->size; file_offset += i->size;
if (file_offset > current_offset) break; if (file_offset > current_offset) break;
@ -1994,8 +2023,8 @@ namespace libtorrent
TORRENT_ASSERT(file_offset > current_offset); TORRENT_ASSERT(file_offset > current_offset);
int skip_blocks = static_cast<int>( int skip_blocks = static_cast<int>(
(file_offset - current_offset + m_info->piece_length() - 1) (file_offset - current_offset + m_files.piece_length() - 1)
/ m_info->piece_length()); / m_files.piece_length());
if (m_storage_mode == storage_mode_compact) if (m_storage_mode == storage_mode_compact)
{ {
@ -2008,15 +2037,15 @@ namespace libtorrent
// current slot will increase by one at the end of the for-loop too // current slot will increase by one at the end of the for-loop too
m_current_slot += skip_blocks - 1; m_current_slot += skip_blocks - 1;
TORRENT_ASSERT(m_current_slot <= m_info->num_pieces()); TORRENT_ASSERT(m_current_slot <= m_files.num_pieces());
} }
++m_current_slot; ++m_current_slot;
current_slot = m_current_slot; current_slot = m_current_slot;
if (m_current_slot >= m_info->num_pieces()) if (m_current_slot >= m_files.num_pieces())
{ {
TORRENT_ASSERT(m_current_slot == m_info->num_pieces()); TORRENT_ASSERT(m_current_slot == m_files.num_pieces());
// clear the memory we've been using // clear the memory we've been using
std::vector<char>().swap(m_piece_data); std::vector<char>().swap(m_piece_data);
@ -2059,19 +2088,19 @@ namespace libtorrent
// DO THE FULL CHECK // DO THE FULL CHECK
// ------------------------ // ------------------------
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_info->num_pieces()); TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces());
TORRENT_ASSERT(int(m_slot_to_piece.size()) == m_info->num_pieces()); TORRENT_ASSERT(int(m_slot_to_piece.size()) == m_files.num_pieces());
TORRENT_ASSERT(have_piece == -1); TORRENT_ASSERT(have_piece == -1);
// initialization for the full check // initialization for the full check
if (m_hash_to_piece.empty()) if (m_hash_to_piece.empty())
{ {
for (int i = 0; i < m_info->num_pieces(); ++i) for (int i = 0; i < m_files.num_pieces(); ++i)
m_hash_to_piece.insert(std::make_pair(m_info->hash_for_piece(i), i)); m_hash_to_piece.insert(std::make_pair(m_info->hash_for_piece(i), i));
} }
m_piece_data.resize(int(m_info->piece_length())); m_piece_data.resize(int(m_files.piece_length()));
int piece_size = m_info->piece_size(m_current_slot); int piece_size = m_files.piece_size(m_current_slot);
int num_read = m_storage->read(&m_piece_data[0] int num_read = m_storage->read(&m_piece_data[0]
, m_current_slot, 0, piece_size); , m_current_slot, 0, piece_size);
@ -2348,7 +2377,7 @@ namespace libtorrent
// special case to make sure we don't use the last slot // special case to make sure we don't use the last slot
// when we shouldn't, since it's smaller than ordinary slots // when we shouldn't, since it's smaller than ordinary slots
if (*iter == m_info->num_pieces() - 1 && piece_index != *iter) if (*iter == m_files.num_pieces() - 1 && piece_index != *iter)
{ {
if (m_free_slots.size() == 1) if (m_free_slots.size() == 1)
allocate_slots(1); allocate_slots(1);
@ -2481,14 +2510,14 @@ namespace libtorrent
{ {
boost::recursive_mutex::scoped_lock lock(m_mutex); boost::recursive_mutex::scoped_lock lock(m_mutex);
TORRENT_ASSERT(m_current_slot <= m_info->num_pieces()); TORRENT_ASSERT(m_current_slot <= m_files.num_pieces());
if (m_unallocated_slots.empty() if (m_unallocated_slots.empty()
&& m_free_slots.empty() && m_free_slots.empty()
&& m_state == state_finished) && m_state == state_finished)
{ {
TORRENT_ASSERT(m_storage_mode != storage_mode_compact TORRENT_ASSERT(m_storage_mode != storage_mode_compact
|| m_info->num_pieces() == 0); || m_files.num_pieces() == 0);
} }
if (m_storage_mode != storage_mode_compact) if (m_storage_mode != storage_mode_compact)
@ -2508,8 +2537,8 @@ namespace libtorrent
{ {
if (m_piece_to_slot.empty()) return; if (m_piece_to_slot.empty()) return;
TORRENT_ASSERT((int)m_piece_to_slot.size() == m_info->num_pieces()); TORRENT_ASSERT((int)m_piece_to_slot.size() == m_files.num_pieces());
TORRENT_ASSERT((int)m_slot_to_piece.size() == m_info->num_pieces()); TORRENT_ASSERT((int)m_slot_to_piece.size() == m_files.num_pieces());
for (std::vector<int>::const_iterator i = m_free_slots.begin(); for (std::vector<int>::const_iterator i = m_free_slots.begin();
i != m_free_slots.end(); ++i) i != m_free_slots.end(); ++i)
@ -2531,7 +2560,7 @@ namespace libtorrent
== m_unallocated_slots.end()); == m_unallocated_slots.end());
} }
for (int i = 0; i < m_info->num_pieces(); ++i) for (int i = 0; i < m_files.num_pieces(); ++i)
{ {
// Check domain of piece_to_slot's elements // Check domain of piece_to_slot's elements
if (m_piece_to_slot[i] != has_no_slot) if (m_piece_to_slot[i] != has_no_slot)
@ -2620,7 +2649,7 @@ namespace libtorrent
s << "index\tslot\tpiece\n"; s << "index\tslot\tpiece\n";
for (int i = 0; i < m_info->num_pieces(); ++i) for (int i = 0; i < m_files.num_pieces(); ++i)
{ {
s << i << "\t" << m_slot_to_piece[i] << "\t"; s << i << "\t" << m_slot_to_piece[i] << "\t";
s << m_piece_to_slot[i] << "\n"; s << m_piece_to_slot[i] << "\n";

View File

@ -424,8 +424,34 @@ namespace libtorrent
m_state = torrent_status::queued_for_checking; m_state = torrent_status::queued_for_checking;
if (m_resume_data.type() == entry::dictionary_t) read_resume_data(m_resume_data); if (m_resume_data.type() == entry::dictionary_t)
{
char const* error = 0;
entry const* file_format = m_resume_data.find_key("file-format");
if (file_format->string() != "libtorrent resume file")
error = "invalid file format tag";
entry const* info_hash = m_resume_data.find_key("info-hash");
if (!error && (info_hash == 0 || info_hash->type() != entry::string_t))
error = "missing info-hash";
if (!error && sha1_hash(info_hash->string()) != m_torrent_file->info_hash())
error = "mismatching info-hash";
if (error && m_ses.m_alerts.should_post(alert::warning))
{
m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), error));
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
(*m_ses.m_logger) << "fastresume data for "
<< torrent_file().name() << " rejected: "
<< error << "\n";
#endif
}
if (error) m_resume_data = entry();
else read_resume_data(m_resume_data);
}
m_storage->async_check_fastresume(&m_resume_data m_storage->async_check_fastresume(&m_resume_data
, bind(&torrent::on_resume_data_checked , bind(&torrent::on_resume_data_checked
, shared_from_this(), _1, _2)); , shared_from_this(), _1, _2));
@ -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;
} }
} }

View File

@ -215,6 +215,12 @@ namespace libtorrent
TORRENT_FORWARD(move_storage(save_path)); TORRENT_FORWARD(move_storage(save_path));
} }
void torrent_handle::rename_file(int index, fs::path const& new_name) const
{
INVARIANT_CHECK;
TORRENT_FORWARD(rename_file(index, new_name.string()));
}
void torrent_handle::add_extension( void torrent_handle::add_extension(
boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext
, void* userdata) , void* userdata)

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2008, Arvid Norberg Copyright (c) 2003-2008, Arvid Norberg
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -153,11 +153,7 @@ namespace
// save the original encoding and replace the // save the original encoding and replace the
// commonly used path with the correctly // commonly used path with the correctly
// encoded string // encoded string
if (!valid_encoding) if (!valid_encoding) target.path = tmp_path;
{
target.orig_path.reset(new fs::path(target.path));
target.path = tmp_path;
}
} }
bool extract_single_file(lazy_entry const& dict, file_entry& target bool extract_single_file(lazy_entry const& dict, file_entry& target
@ -194,40 +190,26 @@ namespace
return true; return true;
} }
bool extract_files(lazy_entry const& list, std::vector<file_entry>& target bool extract_files(lazy_entry const& list, file_storage& target
, std::string const& root_dir) , std::string const& root_dir)
{ {
size_type offset = 0;
if (list.type() != lazy_entry::list_t) return false; if (list.type() != lazy_entry::list_t) return false;
for (int i = 0, end(list.list_size()); i < end; ++i) for (int i = 0, end(list.list_size()); i < end; ++i)
{ {
target.push_back(file_entry()); file_entry e;
if (!extract_single_file(*list.list_at(i), target.back(), root_dir)) if (!extract_single_file(*list.list_at(i), e, root_dir))
return false; return false;
target.back().offset = offset; target.add_file(e);
offset += target.back().size;
} }
return true; return true;
} }
/*
void remove_dir(fs::path& p)
{
TORRENT_ASSERT(p.begin() != p.end());
path tmp;
for (path::iterator i = boost::next(p.begin()); i != p.end(); ++i)
tmp /= *i;
p = tmp;
}
*/
} }
namespace libtorrent namespace libtorrent
{ {
// standard constructor that parses a torrent file // standard constructor that parses a torrent file
torrent_info::torrent_info(entry const& torrent_file) torrent_info::torrent_info(entry const& torrent_file)
: m_num_pieces(0) : m_creation_date(pt::ptime(pt::not_a_date_time))
, m_creation_date(pt::ptime(pt::not_a_date_time))
, m_multifile(false) , m_multifile(false)
, m_private(false) , m_private(false)
, m_info_section_size(0) , m_info_section_size(0)
@ -249,8 +231,7 @@ namespace libtorrent
} }
torrent_info::torrent_info(lazy_entry const& torrent_file) torrent_info::torrent_info(lazy_entry const& torrent_file)
: m_num_pieces(0) : m_creation_date(pt::ptime(pt::not_a_date_time))
, m_creation_date(pt::ptime(pt::not_a_date_time))
, m_multifile(false) , m_multifile(false)
, m_private(false) , m_private(false)
, m_info_section_size(0) , m_info_section_size(0)
@ -266,8 +247,7 @@ namespace libtorrent
} }
torrent_info::torrent_info(char const* buffer, int size) torrent_info::torrent_info(char const* buffer, int size)
: m_num_pieces(0) : m_creation_date(pt::ptime(pt::not_a_date_time))
, m_creation_date(pt::ptime(pt::not_a_date_time))
, m_multifile(false) , m_multifile(false)
, m_private(false) , m_private(false)
, m_info_section_size(0) , m_info_section_size(0)
@ -289,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;
}
} }

View File

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

View File

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

View File

@ -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");
}
// ============================================== // ==============================================

View File

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

View File

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