optimized memory usage of torrent_info and file_storage
This commit is contained in:
parent
7cd628e78d
commit
894db973e8
|
@ -1,3 +1,5 @@
|
||||||
|
* optimized memory usage of torrent_info and file_storage, forcing some API changes
|
||||||
|
around file_storage and file_entry
|
||||||
* support trackerid tracker extension
|
* support trackerid tracker extension
|
||||||
* graceful peer disconnect mode which finishes transactions before disconnecting peers
|
* graceful peer disconnect mode which finishes transactions before disconnecting peers
|
||||||
* support chunked encoding for web seeds
|
* support chunked encoding for web seeds
|
||||||
|
|
|
@ -48,12 +48,12 @@ namespace
|
||||||
ct.add_node(std::make_pair(addr, port));
|
ct.add_node(std::make_pair(addr, port));
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_file(file_storage& ct, file_entry const& fe
|
void add_file(file_storage& ct, file_entry const& fe
|
||||||
, std::string const& hash, std::string const& linkpath)
|
, std::string const& hash, std::string const& linkpath)
|
||||||
{
|
{
|
||||||
ct.add_file(fe, hash.empty() ? 0 : &sha1_hash(hash)
|
ct.add_file(fe, hash.empty() ? 0 : hash.c_str()
|
||||||
, linkpath.empty() ? 0 : &linkpath);
|
, linkpath.empty() ? 0 : &linkpath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bind_create_torrent()
|
void bind_create_torrent()
|
||||||
|
@ -82,6 +82,12 @@ void bind_create_torrent()
|
||||||
#endif
|
#endif
|
||||||
.def("num_files", &file_storage::num_files)
|
.def("num_files", &file_storage::num_files)
|
||||||
.def("at", &file_storage::at, return_internal_reference<>())
|
.def("at", &file_storage::at, return_internal_reference<>())
|
||||||
|
.def("hash", &file_storage::hash)
|
||||||
|
.def("symlink", &file_storage::symlink, return_internal_reference<>())
|
||||||
|
.def("file_index", &file_storage::file_index)
|
||||||
|
.def("file_base", &file_storage::file_base)
|
||||||
|
.def("set_file_base", &file_storage::set_file_base)
|
||||||
|
.def("file_path", &file_storage::file_path)
|
||||||
.def("total_size", &file_storage::total_size)
|
.def("total_size", &file_storage::total_size)
|
||||||
.def("set_num_pieces", &file_storage::set_num_pieces)
|
.def("set_num_pieces", &file_storage::set_num_pieces)
|
||||||
.def("num_pieces", &file_storage::num_pieces)
|
.def("num_pieces", &file_storage::num_pieces)
|
||||||
|
|
|
@ -102,6 +102,20 @@ namespace
|
||||||
bool get_send_stats(announce_entry const& ae)
|
bool get_send_stats(announce_entry const& ae)
|
||||||
{ return ae.send_stats; }
|
{ return ae.send_stats; }
|
||||||
|
|
||||||
|
|
||||||
|
bool get_size(file_entry const& fe)
|
||||||
|
{ return fe.size; }
|
||||||
|
bool get_offset(file_entry const& fe)
|
||||||
|
{ return fe.offset; }
|
||||||
|
bool get_pad_file(file_entry const& fe)
|
||||||
|
{ return fe.pad_file; }
|
||||||
|
bool get_executable_attribute(file_entry const& fe)
|
||||||
|
{ return fe.executable_attribute; }
|
||||||
|
bool get_hidden_attribute(file_entry const& fe)
|
||||||
|
{ return fe.hidden_attribute; }
|
||||||
|
bool get_symlink_attribute(file_entry const& fe)
|
||||||
|
{ return fe.symlink_attribute; }
|
||||||
|
|
||||||
} // namespace unnamed
|
} // namespace unnamed
|
||||||
|
|
||||||
void bind_torrent_info()
|
void bind_torrent_info()
|
||||||
|
@ -168,14 +182,14 @@ void bind_torrent_info()
|
||||||
;
|
;
|
||||||
|
|
||||||
class_<file_entry>("file_entry")
|
class_<file_entry>("file_entry")
|
||||||
.add_property("path"
|
.def("filename", &file_entry::filename)
|
||||||
, make_getter(
|
.def("set_name", &file_entry::set_name)
|
||||||
&file_entry::path, return_value_policy<copy_non_const_reference>()
|
.add_property("pad_file", &get_pad_file)
|
||||||
)
|
.add_property("executable_attribute", &get_executable_attribute)
|
||||||
)
|
.add_property("hidden_attribute", &get_hidden_attribute)
|
||||||
.def_readonly("offset", &file_entry::offset)
|
.add_property("symlink_attribute", &get_symlink_attribute)
|
||||||
.def_readonly("size", &file_entry::size)
|
.add_property("offset", &get_offset)
|
||||||
.def_readonly("file_base", &file_entry::file_base)
|
.add_property("size", &get_size)
|
||||||
;
|
;
|
||||||
|
|
||||||
class_<announce_entry>("announce_entry", init<std::string const&>())
|
class_<announce_entry>("announce_entry", init<std::string const&>())
|
||||||
|
|
|
@ -172,8 +172,12 @@ file structure. Its synopsis::
|
||||||
int piece_length() const;
|
int piece_length() const;
|
||||||
int piece_size(int index) const;
|
int piece_size(int index) const;
|
||||||
|
|
||||||
sha1_hash const& hash(int index) const;
|
sha1_hash const& hash(file_entry const& fe) const;
|
||||||
std::string const& symlink(int index) const;
|
std::string const& symlink(file_entry const& fe) const;
|
||||||
|
time_t mtime(file_entry const& fe) const;
|
||||||
|
int file_index(file_entry const& fe) const;
|
||||||
|
size_type file_base(file_entry const& fe) const;
|
||||||
|
void set_file_base(file_entry const& fe, size_type off);
|
||||||
|
|
||||||
void set_name(std::string const& n);
|
void set_name(std::string const& n);
|
||||||
void set_name(std::wstring const& n);
|
void set_name(std::wstring const& n);
|
||||||
|
@ -218,17 +222,47 @@ can be changed by calling ``set_name``.
|
||||||
The built in functions to traverse a directory to add files will
|
The built in functions to traverse a directory to add files will
|
||||||
make sure this requirement is fulfilled.
|
make sure this requirement is fulfilled.
|
||||||
|
|
||||||
hash() symlink()
|
hash() symlink() mtime() file_index()
|
||||||
----------------
|
-------------------------------------
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
sha1_hash const& hash(int index) const;
|
sha1_hash hash(file_entry const& fe) const;
|
||||||
std::string const& symlink(int index) const;
|
std::string const& symlink(file_entry const& fe) const;
|
||||||
|
time_t mtime(file_entry const& fe) const;
|
||||||
|
int file_index(file_entry const& fe) const;
|
||||||
|
|
||||||
These functions are used to resolve the symlink index and file hash
|
These functions are used to query the symlink, file hash,
|
||||||
index in ``file_entry``.
|
modification time and the file-index from a ``file_entry``.
|
||||||
|
|
||||||
|
For these functions to function, the file entry must be an
|
||||||
|
actual object from this same ``file_storage`` object. It may
|
||||||
|
not be a copy.
|
||||||
|
|
||||||
|
The file hash is a sha-1 hash of the file, or 0 if none was
|
||||||
|
provided in the torrent file. This can potentially be used to
|
||||||
|
join a bittorrent network with other file sharing networks.
|
||||||
|
|
||||||
|
The modification time is the posix time when a file was last
|
||||||
|
modified when the torrent was created, or 0 if it was not provided.
|
||||||
|
|
||||||
|
The file index of a file is simply a 0 based index of the
|
||||||
|
file as they are ordered in the torrent file.
|
||||||
|
|
||||||
|
file_base() set_file_base()
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
size_type file_base(file_entry const& fe) const;
|
||||||
|
void set_file_base(file_entry const& fe, size_type off);
|
||||||
|
|
||||||
|
The file base of a file is the offset within the file on the filsystem
|
||||||
|
where it starts to write. For the most part, this is always 0. It's
|
||||||
|
possible to map several files (in the torrent) into a single file on
|
||||||
|
the filesystem by making them all point to the same filename, but with
|
||||||
|
different file bases, so that they don't overlap.
|
||||||
|
``torrent_info::remap_files`` can be used to use a new file layout.
|
||||||
|
|
||||||
create_torrent
|
create_torrent
|
||||||
==============
|
==============
|
||||||
|
|
|
@ -1350,9 +1350,6 @@ The ``torrent_info`` has the following synopsis::
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// flags for torrent_info constructor
|
|
||||||
enum flags_t { omit_filehashes = 1 };
|
|
||||||
|
|
||||||
// these constructors throws exceptions on error
|
// these constructors throws exceptions on error
|
||||||
torrent_info(sha1_hash const& info_hash, int flags = 0);
|
torrent_info(sha1_hash const& info_hash, int flags = 0);
|
||||||
torrent_info(lazy_entry const& torrent_file, int flags = 0);
|
torrent_info(lazy_entry const& torrent_file, int flags = 0);
|
||||||
|
@ -1461,10 +1458,7 @@ torrent_info object. The overloads that do not take the extra error_code_ parame
|
||||||
always throw if an error occurs. These overloads are not available when building without
|
always throw if an error occurs. These overloads are not available when building without
|
||||||
exception support.
|
exception support.
|
||||||
|
|
||||||
The ``flags`` argument can be used to disable loading of potentially unnecessary hashes
|
The ``flags`` argument is currently unused.
|
||||||
for individual files (if included in the torrent file). This is especially useful if
|
|
||||||
you're loading torrents with thousands of files on a memory constrained system. If so,
|
|
||||||
pass in ``torrent_info::omit_filehashes`` as the flags argument.
|
|
||||||
|
|
||||||
|
|
||||||
add_tracker()
|
add_tracker()
|
||||||
|
@ -1547,7 +1541,7 @@ iterators with the type ``file_entry``.
|
||||||
|
|
||||||
struct file_entry
|
struct file_entry
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string filename();
|
||||||
size_type offset;
|
size_type offset;
|
||||||
size_type size;
|
size_type size;
|
||||||
size_type file_base;
|
size_type file_base;
|
||||||
|
@ -1560,9 +1554,9 @@ iterators with the type ``file_entry``.
|
||||||
bool symlink_attribute:1;
|
bool symlink_attribute:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
The ``path`` is the full (relative) path of each file. i.e. if it is a multi-file
|
The ``filename`` function returns the filename of this file. It does not include the
|
||||||
torrent, all the files starts with a directory with the same name as ``torrent_info::name()``.
|
path, just the leaf name. To get the full path name, use ``file_storage::file_path()``.
|
||||||
The filenames are encoded with UTF-8.
|
The filenames are unicode strings encoded in UTF-8.
|
||||||
|
|
||||||
``size`` is the size of the file (in bytes) and ``offset`` is the byte offset
|
``size`` is the size of the file (in bytes) and ``offset`` is the byte offset
|
||||||
of the file within the torrent. i.e. the sum of all the sizes of the files
|
of the file within the torrent. i.e. the sum of all the sizes of the files
|
||||||
|
@ -1584,7 +1578,7 @@ is set. To resolve the symlink, call ``file_storage::symlink(e.symlink_index)``.
|
||||||
``filehash_index`` is an index into an array of sha-1 hashes in ``file_storage``, or
|
``filehash_index`` is an index into an array of sha-1 hashes in ``file_storage``, or
|
||||||
-1 if this file doesn't have a hash specified. The hash is the hash of the actual
|
-1 if this file doesn't have a hash specified. The hash is the hash of the actual
|
||||||
content of the file, and can be used to potentially find alternative sources for it.
|
content of the file, and can be used to potentially find alternative sources for it.
|
||||||
To resolve the hash, use ``file_storage::hash(e.filehash_index)``.
|
To resolve the hash, use ``file_storage::hash(e)``.
|
||||||
|
|
||||||
``pad_file`` is set to true for files that are not part of the data of the torrent.
|
``pad_file`` is set to true for files that are not part of the data of the torrent.
|
||||||
They are just there to make sure the next file is aligned to a particular byte offset
|
They are just there to make sure the next file is aligned to a particular byte offset
|
||||||
|
|
|
@ -1715,7 +1715,7 @@ int main(int argc, char* argv[])
|
||||||
, pad_file?esc("34"):""
|
, pad_file?esc("34"):""
|
||||||
, progress / 10.f
|
, progress / 10.f
|
||||||
, add_suffix(file_progress[i]).c_str()
|
, add_suffix(file_progress[i]).c_str()
|
||||||
, filename(info.file_at(i).path).c_str()
|
, filename(info.files().file_path(info.file_at(i))).c_str()
|
||||||
, pad_file?esc("0"):"");
|
, pad_file?esc("0"):"");
|
||||||
out += str;
|
out += str;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,8 @@ int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
printf("sizeof(file_entry): %d\n", int(sizeof(file_entry)));
|
||||||
|
|
||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
{
|
{
|
||||||
fputs("usage: dump_torrent torrent-file\n", stderr);
|
fputs("usage: dump_torrent torrent-file\n", stderr);
|
||||||
|
@ -70,7 +72,7 @@ int main(int argc, char* argv[])
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n\n----- raw info -----\n\n%s\n", print_entry(e).c_str());
|
// printf("\n\n----- raw info -----\n\n%s\n", print_entry(e).c_str());
|
||||||
|
|
||||||
torrent_info t(e, ec);
|
torrent_info t(e, ec);
|
||||||
if (ec)
|
if (ec)
|
||||||
|
@ -78,6 +80,8 @@ int main(int argc, char* argv[])
|
||||||
fprintf(stderr, "%s\n", ec.message().c_str());
|
fprintf(stderr, "%s\n", ec.message().c_str());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
e.clear();
|
||||||
|
std::vector<char>().swap(buf);
|
||||||
|
|
||||||
// print info about torrent
|
// print info about torrent
|
||||||
printf("\n\n----- torrent file info -----\n\n"
|
printf("\n\n----- torrent file info -----\n\n"
|
||||||
|
@ -106,6 +110,7 @@ int main(int argc, char* argv[])
|
||||||
"created by: %s\n"
|
"created by: %s\n"
|
||||||
"magnet link: %s\n"
|
"magnet link: %s\n"
|
||||||
"name: %s\n"
|
"name: %s\n"
|
||||||
|
"number of files: %d\n"
|
||||||
"files:\n"
|
"files:\n"
|
||||||
, t.num_pieces()
|
, t.num_pieces()
|
||||||
, t.piece_length()
|
, t.piece_length()
|
||||||
|
@ -113,24 +118,26 @@ int main(int argc, char* argv[])
|
||||||
, t.comment().c_str()
|
, t.comment().c_str()
|
||||||
, t.creator().c_str()
|
, t.creator().c_str()
|
||||||
, make_magnet_uri(t).c_str()
|
, make_magnet_uri(t).c_str()
|
||||||
, t.name().c_str());
|
, t.name().c_str()
|
||||||
|
, t.num_files());
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (torrent_info::file_iterator i = t.begin_files();
|
for (torrent_info::file_iterator i = t.begin_files();
|
||||||
i != t.end_files(); ++i, ++index)
|
i != t.end_files(); ++i, ++index)
|
||||||
{
|
{
|
||||||
int first = t.map_file(index, 0, 0).piece;
|
int first = t.map_file(index, 0, 0).piece;
|
||||||
int last = t.map_file(index, (std::max)(i->size-1, size_type(0)), 0).piece;
|
int last = t.map_file(index, (std::max)(i->size-1, size_type(0)), 0).piece;
|
||||||
printf(" %11"PRId64" %c%c%c%c [ %4d, %4d ] %s %s %s%s\n"
|
printf(" %11"PRId64" %c%c%c%c [ %4d, %4d ] %7u %s %s %s%s\n"
|
||||||
, i->size
|
, i->size
|
||||||
, (i->pad_file?'p':'-')
|
, (i->pad_file?'p':'-')
|
||||||
, (i->executable_attribute?'x':'-')
|
, (i->executable_attribute?'x':'-')
|
||||||
, (i->hidden_attribute?'h':'-')
|
, (i->hidden_attribute?'h':'-')
|
||||||
, (i->symlink_attribute?'l':'-')
|
, (i->symlink_attribute?'l':'-')
|
||||||
, first, last
|
, first, last
|
||||||
, i->filehash_index != -1 ? to_hex(t.files().hash(i->filehash_index).to_string()).c_str() : ""
|
, boost::uint32_t(t.files().mtime(*i))
|
||||||
, i->path.c_str()
|
, t.files().hash(*i) != sha1_hash(0) ? to_hex(t.files().hash(*i).to_string()).c_str() : ""
|
||||||
|
, t.files().file_path(*i).c_str()
|
||||||
, i->symlink_attribute ? "-> ": ""
|
, i->symlink_attribute ? "-> ": ""
|
||||||
, i->symlink_attribute && i->symlink_index != -1 ? t.files().symlink(i->symlink_index).c_str() : "");
|
, i->symlink_attribute && i->symlink_index != -1 ? t.files().symlink(*i).c_str() : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -84,7 +84,7 @@ int main(int argc, char const* argv[])
|
||||||
{
|
{
|
||||||
if (ti->file_at(i).size == files[i].first) continue;
|
if (ti->file_at(i).size == files[i].first) continue;
|
||||||
fprintf(stderr, "Files for this torrent are missing or incomplete: %s was %"PRId64" bytes, expected %"PRId64" bytes\n"
|
fprintf(stderr, "Files for this torrent are missing or incomplete: %s was %"PRId64" bytes, expected %"PRId64" bytes\n"
|
||||||
, ti->file_at(i).path.c_str(), files[i].first, ti->file_at(i).size);
|
, ti->files().file_path(ti->file_at(i)).c_str(), files[i].first, ti->file_at(i).size);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,15 +51,16 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
struct file_entry;
|
struct file_entry;
|
||||||
|
struct file_storage;
|
||||||
|
|
||||||
struct TORRENT_EXPORT file_pool : boost::noncopyable
|
struct TORRENT_EXPORT file_pool : boost::noncopyable
|
||||||
{
|
{
|
||||||
file_pool(int size = 40): m_size(size), m_low_prio_io(true) {}
|
file_pool(int size = 40): m_size(size), m_low_prio_io(true) {}
|
||||||
|
|
||||||
boost::intrusive_ptr<file> open_file(void* st, std::string const& p
|
boost::intrusive_ptr<file> open_file(void* st, std::string const& p
|
||||||
, file_entry const& fe, int m, error_code& ec);
|
, file_entry const& fe, file_storage const& fs, int m, error_code& ec);
|
||||||
void release(void* st);
|
void release(void* st);
|
||||||
void release(void* st, file_entry const& fe);
|
void release(void* st, int file_index);
|
||||||
void resize(int size);
|
void resize(int size);
|
||||||
int size_limit() const { return m_size; }
|
int size_limit() const { return m_size; }
|
||||||
void set_low_prio_io(bool b) { m_low_prio_io = b; }
|
void set_low_prio_io(bool b) { m_low_prio_io = b; }
|
||||||
|
|
|
@ -41,7 +41,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/assert.hpp"
|
#include "libtorrent/assert.hpp"
|
||||||
#include "libtorrent/peer_request.hpp"
|
#include "libtorrent/peer_request.hpp"
|
||||||
#include "libtorrent/peer_id.hpp"
|
#include "libtorrent/peer_id.hpp"
|
||||||
#include "libtorrent/copy_ptr.hpp"
|
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
@ -49,43 +48,59 @@ namespace libtorrent
|
||||||
|
|
||||||
struct TORRENT_EXPORT file_entry
|
struct TORRENT_EXPORT file_entry
|
||||||
{
|
{
|
||||||
|
friend class file_storage;
|
||||||
file_entry()
|
file_entry()
|
||||||
: offset(0)
|
: name(0)
|
||||||
, size(0)
|
, offset(0)
|
||||||
, file_base(0)
|
|
||||||
, mtime(0)
|
|
||||||
, file_index(0)
|
|
||||||
, filehash_index(-1)
|
|
||||||
, symlink_index(-1)
|
, symlink_index(-1)
|
||||||
|
, size(0)
|
||||||
|
, name_len(0)
|
||||||
, pad_file(false)
|
, pad_file(false)
|
||||||
, hidden_attribute(false)
|
, hidden_attribute(false)
|
||||||
, executable_attribute(false)
|
, executable_attribute(false)
|
||||||
, symlink_attribute(false)
|
, symlink_attribute(false)
|
||||||
|
, path_index(-1)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::string path;
|
file_entry(file_entry const& fe);
|
||||||
|
file_entry& operator=(file_entry const& fe);
|
||||||
|
|
||||||
|
~file_entry();
|
||||||
|
|
||||||
|
void set_name(char const* n, int borrow_chars = 0);
|
||||||
|
std::string filename() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// This string is not necessarily null terminated!
|
||||||
|
// that's why it's private, to keep people away from it
|
||||||
|
char const* name;
|
||||||
|
public:
|
||||||
|
|
||||||
// the offset of this file inside the torrent
|
// the offset of this file inside the torrent
|
||||||
size_type offset;
|
size_type offset:48;
|
||||||
// the size of this file
|
|
||||||
size_type size;
|
|
||||||
// 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;
|
|
||||||
// modification time
|
|
||||||
time_t mtime;
|
|
||||||
// the index of this file, as ordered in the torrent
|
|
||||||
int file_index;
|
|
||||||
// index into file_storage::m_file_hashes or -1
|
|
||||||
// if this file does not have a hash
|
|
||||||
int filehash_index;
|
|
||||||
// index into file_storage::m_symlinks or -1
|
// index into file_storage::m_symlinks or -1
|
||||||
// if this is not a symlink
|
// if this is not a symlink
|
||||||
int symlink_index;
|
size_type symlink_index:16;
|
||||||
|
|
||||||
|
// the size of this file
|
||||||
|
size_type size:48;
|
||||||
|
|
||||||
|
// the number of characters in the name. If this is
|
||||||
|
// 0, name is null terminated and owned by this object
|
||||||
|
// (i.e. it should be freed in the destructor). If
|
||||||
|
// the len is > 0, the name pointer doesn not belong
|
||||||
|
// to this object, and it's not null terminated
|
||||||
|
size_type name_len:10;
|
||||||
bool pad_file:1;
|
bool pad_file:1;
|
||||||
bool hidden_attribute:1;
|
bool hidden_attribute:1;
|
||||||
bool executable_attribute:1;
|
bool executable_attribute:1;
|
||||||
bool symlink_attribute:1;
|
bool symlink_attribute:1;
|
||||||
|
// the index into file_storage::m_paths. To get
|
||||||
|
// the full path to this file, concatenate the path
|
||||||
|
// from that array with the 'name' field in
|
||||||
|
// this struct
|
||||||
|
int path_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TORRENT_EXPORT file_slice
|
struct TORRENT_EXPORT file_slice
|
||||||
|
@ -114,11 +129,12 @@ namespace libtorrent
|
||||||
|
|
||||||
void reserve(int num_files);
|
void reserve(int num_files);
|
||||||
|
|
||||||
void add_file(file_entry const& e, sha1_hash const* filehash = 0
|
void add_file(file_entry const& e, char const* filehash = 0
|
||||||
, std::string const* symlink = 0);
|
, std::string const* symlink = 0, time_t mtime = 0);
|
||||||
|
|
||||||
void add_file(std::string const& p, size_type size, int flags = 0
|
void add_file(std::string const& p, size_type size, int flags = 0
|
||||||
, std::time_t mtime = 0, std::string const& s_p = "");
|
, std::time_t mtime = 0, std::string const& s_p = "");
|
||||||
|
|
||||||
void rename_file(int index, std::string const& new_filename);
|
void rename_file(int index, std::string const& new_filename);
|
||||||
|
|
||||||
#if TORRENT_USE_WSTRING
|
#if TORRENT_USE_WSTRING
|
||||||
|
@ -149,17 +165,14 @@ namespace libtorrent
|
||||||
return m_files[index];
|
return m_files[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
sha1_hash const& hash(int index) const
|
sha1_hash hash(file_entry const& fe) const;
|
||||||
{
|
std::string const& symlink(file_entry const& fe) const;
|
||||||
TORRENT_ASSERT(index >= 0 && index < int(m_file_hashes.size()));
|
time_t mtime(file_entry const& fe) const;
|
||||||
return m_file_hashes[index];
|
int file_index(file_entry const& fe) const;
|
||||||
}
|
size_type file_base(file_entry const& fe) const;
|
||||||
|
void set_file_base(file_entry const& fe, size_type off);
|
||||||
std::string const& symlink(int index) const
|
|
||||||
{
|
std::string file_path(file_entry const& fe) const;
|
||||||
TORRENT_ASSERT(index >= 0 && index < int(m_symlinks.size()));
|
|
||||||
return m_symlinks[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type total_size() const { return m_total_size; }
|
size_type total_size() const { return m_total_size; }
|
||||||
void set_num_pieces(int n) { m_num_pieces = n; }
|
void set_num_pieces(int n) { m_num_pieces = n; }
|
||||||
|
@ -188,19 +201,40 @@ namespace libtorrent
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void update_path_index(file_entry& e);
|
||||||
|
void reorder_file(int index, int dst);
|
||||||
|
|
||||||
// the list of files that this torrent consists of
|
// the list of files that this torrent consists of
|
||||||
std::vector<file_entry> m_files;
|
std::vector<file_entry> m_files;
|
||||||
|
|
||||||
// if there are sha1 hashes for each individual file
|
// if there are sha1 hashes for each individual file
|
||||||
// each file_entry has an index into this vector
|
// there are as many entries in this array as the
|
||||||
// and the actual hashes are in here
|
// m_files array. Each entry in m_files has a corresponding
|
||||||
std::vector<sha1_hash> m_file_hashes;
|
// hash pointer in this array. The reason to split it up
|
||||||
|
// in separate arrays is to save memory in case the torrent
|
||||||
|
// doesn't have file hashes
|
||||||
|
std::vector<char const*> m_file_hashes;
|
||||||
|
|
||||||
// for files that are symlinks, the symlink
|
// for files that are symlinks, the symlink
|
||||||
// path_index in the file_entry indexes
|
// path_index in the file_entry indexes
|
||||||
// this vector of strings
|
// this vector of strings
|
||||||
std::vector<std::string> m_symlinks;
|
std::vector<std::string> m_symlinks;
|
||||||
|
|
||||||
|
// the modification times of each file. This vector
|
||||||
|
// is empty if no file have a modification time.
|
||||||
|
// each element corresponds to the file with the same
|
||||||
|
// index in m_files
|
||||||
|
std::vector<time_t> m_mtime;
|
||||||
|
|
||||||
|
// if any file has a non-zero file base (i.e. multiple
|
||||||
|
// files residing in the same physical file at different
|
||||||
|
// offsets)
|
||||||
|
std::vector<size_type> m_file_base;
|
||||||
|
|
||||||
|
// all unique paths files have. The file_entry::path_index
|
||||||
|
// points into this array
|
||||||
|
std::vector<std::string> m_paths;
|
||||||
|
|
||||||
// name of torrent. For multi-file torrents
|
// name of torrent. For multi-file torrents
|
||||||
// this is always the root directory
|
// this is always the root directory
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
|
|
|
@ -78,7 +78,7 @@ namespace libtorrent
|
||||||
none_t, dict_t, list_t, string_t, int_t
|
none_t, dict_t, list_t, string_t, int_t
|
||||||
};
|
};
|
||||||
|
|
||||||
lazy_entry() : m_begin(0), m_end(0), m_type(none_t)
|
lazy_entry() : m_begin(0), m_len(0), m_type(none_t)
|
||||||
{ m_data.start = 0; }
|
{ m_data.start = 0; }
|
||||||
|
|
||||||
entry_type_t type() const { return (entry_type_t)m_type; }
|
entry_type_t type() const { return (entry_type_t)m_type; }
|
||||||
|
@ -92,7 +92,7 @@ namespace libtorrent
|
||||||
m_data.start = start;
|
m_data.start = start;
|
||||||
m_size = length;
|
m_size = length;
|
||||||
m_begin = start - 1; // include 'i'
|
m_begin = start - 1; // include 'i'
|
||||||
m_end = start + length + 1; // include 'e'
|
m_len = length + 2; // include 'e'
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type int_value() const;
|
size_type int_value() const;
|
||||||
|
@ -202,7 +202,7 @@ namespace libtorrent
|
||||||
void set_end(char const* end)
|
void set_end(char const* end)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(end > m_begin);
|
TORRENT_ASSERT(end > m_begin);
|
||||||
m_end = end;
|
m_len = end - m_begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
@ -235,7 +235,7 @@ namespace libtorrent
|
||||||
swap(m_data.start, e.m_data.start);
|
swap(m_data.start, e.m_data.start);
|
||||||
swap(m_size, e.m_size);
|
swap(m_size, e.m_size);
|
||||||
swap(m_begin, e.m_begin);
|
swap(m_begin, e.m_begin);
|
||||||
swap(m_end, e.m_end);
|
swap(m_len, e.m_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -250,11 +250,16 @@ namespace libtorrent
|
||||||
// used for dictionaries and lists to record the range
|
// used for dictionaries and lists to record the range
|
||||||
// in the original buffer they are based on
|
// in the original buffer they are based on
|
||||||
char const* m_begin;
|
char const* m_begin;
|
||||||
char const* m_end;
|
// the number of bytes this entry extends in the
|
||||||
|
// bencoded byffer
|
||||||
|
boost::uint32_t m_len;
|
||||||
|
|
||||||
boost::uint32_t m_size; // if list or dictionary, the number of items
|
// if list or dictionary, the number of items
|
||||||
boost::uint32_t m_capacity:29; // if list or dictionary, allocated number of items
|
boost::uint32_t m_size;
|
||||||
unsigned int m_type:3;
|
// if list or dictionary, allocated number of items
|
||||||
|
boost::uint32_t m_capacity:29;
|
||||||
|
// element type (dict, list, int, string)
|
||||||
|
boost::uint32_t m_type:3;
|
||||||
|
|
||||||
// non-copyable
|
// non-copyable
|
||||||
lazy_entry(lazy_entry const&);
|
lazy_entry(lazy_entry const&);
|
||||||
|
|
|
@ -227,8 +227,6 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum flags_t { omit_filehashes = 1 };
|
|
||||||
|
|
||||||
#ifndef BOOST_NO_EXCEPTIONS
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
torrent_info(lazy_entry const& torrent_file, int flags = 0);
|
torrent_info(lazy_entry const& torrent_file, int flags = 0);
|
||||||
torrent_info(char const* buffer, int size, int flags = 0);
|
torrent_info(char const* buffer, int size, int flags = 0);
|
||||||
|
|
|
@ -118,7 +118,7 @@ namespace libtorrent
|
||||||
// return instead of crash in release mode
|
// return instead of crash in release mode
|
||||||
if (fs.num_files() == 0) return;
|
if (fs.num_files() == 0) return;
|
||||||
|
|
||||||
if (!m_multifile && has_parent_path(m_files.at(0).path)) m_multifile = true;
|
if (!m_multifile && has_parent_path(m_files.file_path(m_files.at(0)))) m_multifile = true;
|
||||||
|
|
||||||
// a piece_size of 0 means automatic
|
// a piece_size of 0 means automatic
|
||||||
if (piece_size == 0 && !m_merkle_torrent)
|
if (piece_size == 0 && !m_merkle_torrent)
|
||||||
|
@ -301,7 +301,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (!m_multifile)
|
if (!m_multifile)
|
||||||
{
|
{
|
||||||
if (m_include_mtime) info["mtime"] = m_files.at(0).mtime;
|
if (m_include_mtime) info["mtime"] = m_files.mtime(m_files.at(0));
|
||||||
info["length"] = m_files.at(0).size;
|
info["length"] = m_files.at(0).size;
|
||||||
if (m_files.at(0).pad_file
|
if (m_files.at(0).pad_file
|
||||||
|| m_files.at(0).hidden_attribute
|
|| m_files.at(0).hidden_attribute
|
||||||
|
@ -320,7 +320,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
entry& sympath_e = info["symlink path"];
|
entry& sympath_e = info["symlink path"];
|
||||||
|
|
||||||
std::string split = split_path(m_files.symlink(m_files.at(0).symlink_index));
|
std::string split = split_path(m_files.symlink(m_files.at(0)));
|
||||||
for (char const* e = split.c_str(); e != 0; e = next_path_element(e))
|
for (char const* e = split.c_str(); e != 0; e = next_path_element(e))
|
||||||
sympath_e.list().push_back(entry(e));
|
sympath_e.list().push_back(entry(e));
|
||||||
}
|
}
|
||||||
|
@ -340,13 +340,13 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
files.list().push_back(entry());
|
files.list().push_back(entry());
|
||||||
entry& file_e = files.list().back();
|
entry& file_e = files.list().back();
|
||||||
if (m_include_mtime) file_e["mtime"] = i->mtime;
|
if (m_include_mtime && m_files.mtime(*i)) file_e["mtime"] = m_files.mtime(*i);
|
||||||
file_e["length"] = i->size;
|
file_e["length"] = i->size;
|
||||||
entry& path_e = file_e["path"];
|
entry& path_e = file_e["path"];
|
||||||
|
|
||||||
TORRENT_ASSERT(has_parent_path(i->path));
|
TORRENT_ASSERT(has_parent_path(m_files.file_path(*i)));
|
||||||
|
|
||||||
std::string split = split_path(i->path);
|
std::string split = split_path(m_files.file_path(*i));
|
||||||
TORRENT_ASSERT(split.c_str() == m_files.name());
|
TORRENT_ASSERT(split.c_str() == m_files.name());
|
||||||
|
|
||||||
for (char const* e = next_path_element(split.c_str());
|
for (char const* e = next_path_element(split.c_str());
|
||||||
|
@ -370,7 +370,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
entry& sympath_e = file_e["symlink path"];
|
entry& sympath_e = file_e["symlink path"];
|
||||||
|
|
||||||
std::string split = split_path(m_files.symlink(i->symlink_index));
|
std::string split = split_path(m_files.symlink(*i));
|
||||||
for (char const* e = split.c_str(); e != 0; e = next_path_element(e))
|
for (char const* e = split.c_str(); e != 0; e = next_path_element(e))
|
||||||
sympath_e.list().push_back(entry(e));
|
sympath_e.list().push_back(entry(e));
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,14 +41,14 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
boost::intrusive_ptr<file> file_pool::open_file(void* st, std::string const& p
|
boost::intrusive_ptr<file> file_pool::open_file(void* st, std::string const& p
|
||||||
, file_entry const& fe, int m, error_code& ec)
|
, file_entry const& fe, file_storage const& fs, int m, error_code& ec)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(st != 0);
|
TORRENT_ASSERT(st != 0);
|
||||||
TORRENT_ASSERT(is_complete(p));
|
TORRENT_ASSERT(is_complete(p));
|
||||||
TORRENT_ASSERT((m & file::rw_mask) == file::read_only
|
TORRENT_ASSERT((m & file::rw_mask) == file::read_only
|
||||||
|| (m & file::rw_mask) == file::read_write);
|
|| (m & file::rw_mask) == file::read_write);
|
||||||
mutex::scoped_lock l(m_mutex);
|
mutex::scoped_lock l(m_mutex);
|
||||||
file_set::iterator i = m_files.find(std::make_pair(st, fe.file_index));
|
file_set::iterator i = m_files.find(std::make_pair(st, fs.file_index(fe)));
|
||||||
if (i != m_files.end())
|
if (i != m_files.end())
|
||||||
{
|
{
|
||||||
lru_file_entry& e = i->second;
|
lru_file_entry& e = i->second;
|
||||||
|
@ -77,7 +77,7 @@ namespace libtorrent
|
||||||
// the new read/write privilages
|
// the new read/write privilages
|
||||||
TORRENT_ASSERT(e.file_ptr->refcount() == 1);
|
TORRENT_ASSERT(e.file_ptr->refcount() == 1);
|
||||||
e.file_ptr->close();
|
e.file_ptr->close();
|
||||||
std::string full_path = combine_path(p, fe.path);
|
std::string full_path = combine_path(p, fs.file_path(fe));
|
||||||
if (!e.file_ptr->open(full_path, m, ec))
|
if (!e.file_ptr->open(full_path, m, ec))
|
||||||
{
|
{
|
||||||
m_files.erase(i);
|
m_files.erase(i);
|
||||||
|
@ -115,12 +115,12 @@ namespace libtorrent
|
||||||
ec = error_code(ENOMEM, get_posix_category());
|
ec = error_code(ENOMEM, get_posix_category());
|
||||||
return e.file_ptr;
|
return e.file_ptr;
|
||||||
}
|
}
|
||||||
std::string full_path = combine_path(p, fe.path);
|
std::string full_path = combine_path(p, fs.file_path(fe));
|
||||||
if (!e.file_ptr->open(full_path, m, ec))
|
if (!e.file_ptr->open(full_path, m, ec))
|
||||||
return boost::intrusive_ptr<file>();
|
return boost::intrusive_ptr<file>();
|
||||||
e.mode = m;
|
e.mode = m;
|
||||||
e.key = st;
|
e.key = st;
|
||||||
m_files.insert(std::make_pair(std::make_pair(st, fe.file_index), e));
|
m_files.insert(std::make_pair(std::make_pair(st, fs.file_index(fe)), e));
|
||||||
TORRENT_ASSERT(e.file_ptr->is_open());
|
TORRENT_ASSERT(e.file_ptr->is_open());
|
||||||
return e.file_ptr;
|
return e.file_ptr;
|
||||||
}
|
}
|
||||||
|
@ -134,10 +134,10 @@ namespace libtorrent
|
||||||
m_files.erase(i);
|
m_files.erase(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_pool::release(void* st, file_entry const& fe)
|
void file_pool::release(void* st, int file_index)
|
||||||
{
|
{
|
||||||
mutex::scoped_lock l(m_mutex);
|
mutex::scoped_lock l(m_mutex);
|
||||||
file_set::iterator i = m_files.find(std::make_pair(st, fe.file_index));
|
file_set::iterator i = m_files.find(std::make_pair(st, file_index));
|
||||||
if (i != m_files.end()) m_files.erase(i);
|
if (i != m_files.end()) m_files.erase(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,88 @@ namespace libtorrent
|
||||||
return piece_length();
|
return piece_length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void file_storage::update_path_index(file_entry& e)
|
||||||
|
{
|
||||||
|
std::string parent = parent_path(e.filename());
|
||||||
|
if (parent.empty())
|
||||||
|
{
|
||||||
|
e.path_index = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// do we already have this path in the path list?
|
||||||
|
std::vector<std::string>::reverse_iterator p
|
||||||
|
= std::find(m_paths.rbegin(), m_paths.rend(), parent);
|
||||||
|
|
||||||
|
if (p == m_paths.rend())
|
||||||
|
{
|
||||||
|
// no, we don't. add it
|
||||||
|
e.path_index = m_paths.size();
|
||||||
|
m_paths.push_back(parent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// yes we do. use it
|
||||||
|
e.path_index = p.base() - m_paths.begin() - 1;
|
||||||
|
}
|
||||||
|
e.set_name(filename(e.filename()).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file_entry::~file_entry() { if (name_len == 0) free((void*)name); }
|
||||||
|
|
||||||
|
file_entry::file_entry(file_entry const& fe)
|
||||||
|
: name(0)
|
||||||
|
, offset(fe.offset)
|
||||||
|
, symlink_index(fe.symlink_index)
|
||||||
|
, size(fe.size)
|
||||||
|
, name_len(fe.name_len)
|
||||||
|
, pad_file(fe.pad_file)
|
||||||
|
, hidden_attribute(fe.hidden_attribute)
|
||||||
|
, executable_attribute(fe.executable_attribute)
|
||||||
|
, symlink_attribute(fe.symlink_attribute)
|
||||||
|
, path_index(fe.path_index)
|
||||||
|
{
|
||||||
|
set_name(fe.name, fe.name_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_entry& file_entry::operator=(file_entry const& fe)
|
||||||
|
{
|
||||||
|
offset = fe.offset;
|
||||||
|
size = fe.size;
|
||||||
|
path_index = fe.path_index;
|
||||||
|
symlink_index = fe.symlink_index;
|
||||||
|
pad_file = fe.pad_file;
|
||||||
|
hidden_attribute = fe.hidden_attribute;
|
||||||
|
executable_attribute = fe.executable_attribute;
|
||||||
|
symlink_attribute = fe.symlink_attribute;
|
||||||
|
set_name(fe.name, fe.name_len);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_entry::set_name(char const* n, int borrow_chars)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(borrow_chars >= 0);
|
||||||
|
if (borrow_chars > 1023) borrow_chars = 1023;
|
||||||
|
if (name_len == 0) free((void*)name);
|
||||||
|
if (n == 0)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(borrow_chars == 0);
|
||||||
|
name = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = borrow_chars ? n : strdup(n);
|
||||||
|
}
|
||||||
|
name_len = borrow_chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string file_entry::filename() const
|
||||||
|
{
|
||||||
|
if (name_len) return std::string(name, name_len);
|
||||||
|
return name ? name : "";
|
||||||
|
}
|
||||||
|
|
||||||
#if TORRENT_USE_WSTRING
|
#if TORRENT_USE_WSTRING
|
||||||
void file_storage::set_name(std::wstring const& n)
|
void file_storage::set_name(std::wstring const& n)
|
||||||
{
|
{
|
||||||
|
@ -80,7 +162,8 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(index >= 0 && index < int(m_files.size()));
|
TORRENT_ASSERT(index >= 0 && index < int(m_files.size()));
|
||||||
std::string utf8;
|
std::string utf8;
|
||||||
wchar_utf8(new_filename, utf8);
|
wchar_utf8(new_filename, utf8);
|
||||||
m_files[index].path = utf8;
|
m_files[index].set_name(utf8.c_str());
|
||||||
|
update_path_index(m_files[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_storage::add_file(std::wstring const& file, size_type size, int flags
|
void file_storage::add_file(std::wstring const& file, size_type size, int flags
|
||||||
|
@ -95,7 +178,8 @@ namespace libtorrent
|
||||||
void file_storage::rename_file(int index, std::string const& new_filename)
|
void file_storage::rename_file(int index, std::string const& new_filename)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(index >= 0 && index < int(m_files.size()));
|
TORRENT_ASSERT(index >= 0 && index < int(m_files.size()));
|
||||||
m_files[index].path = new_filename;
|
m_files[index].set_name(new_filename.c_str());
|
||||||
|
update_path_index(m_files[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -149,7 +233,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
file_slice f;
|
file_slice f;
|
||||||
f.file_index = file_iter - begin();
|
f.file_index = file_iter - begin();
|
||||||
f.offset = file_offset + file_iter->file_base;
|
f.offset = file_offset + file_base(*file_iter);
|
||||||
f.size = (std::min)(file_iter->size - file_offset, (size_type)size);
|
f.size = (std::min)(file_iter->size - file_offset, (size_type)size);
|
||||||
size -= f.size;
|
size -= f.size;
|
||||||
file_offset += f.size;
|
file_offset += f.size;
|
||||||
|
@ -161,6 +245,13 @@ namespace libtorrent
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string file_storage::file_path(file_entry const& fe) const
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(fe.path_index >= -1 && fe.path_index < int(m_paths.size()));
|
||||||
|
if (fe.path_index == -1) return fe.filename();
|
||||||
|
return combine_path(m_paths[fe.path_index], fe.filename());
|
||||||
|
}
|
||||||
|
|
||||||
peer_request file_storage::map_file(int file_index, size_type file_offset
|
peer_request file_storage::map_file(int file_index, size_type file_offset
|
||||||
, int size) const
|
, int size) const
|
||||||
{
|
{
|
||||||
|
@ -196,9 +287,8 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(m_name == split_path(file).c_str());
|
TORRENT_ASSERT(m_name == split_path(file).c_str());
|
||||||
m_files.push_back(file_entry());
|
m_files.push_back(file_entry());
|
||||||
file_entry& e = m_files.back();
|
file_entry& e = m_files.back();
|
||||||
e.file_index = m_files.size() - 1;
|
e.set_name(file.c_str());
|
||||||
e.size = size;
|
e.size = size;
|
||||||
e.path = file;
|
|
||||||
e.offset = m_total_size;
|
e.offset = m_total_size;
|
||||||
e.pad_file = (flags & pad_file) != 0;
|
e.pad_file = (flags & pad_file) != 0;
|
||||||
e.hidden_attribute = (flags & attribute_hidden) != 0;
|
e.hidden_attribute = (flags & attribute_hidden) != 0;
|
||||||
|
@ -208,45 +298,137 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
e.symlink_index = m_symlinks.size();
|
e.symlink_index = m_symlinks.size();
|
||||||
m_symlinks.push_back(symlink_path);
|
m_symlinks.push_back(symlink_path);
|
||||||
|
|
||||||
}
|
}
|
||||||
e.mtime = mtime;
|
if (mtime)
|
||||||
|
{
|
||||||
|
if (m_mtime.size() < m_files.size()) m_mtime.resize(m_files.size());
|
||||||
|
m_mtime[m_files.size() - 1] = mtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_path_index(e);
|
||||||
m_total_size += size;
|
m_total_size += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_storage::add_file(file_entry const& ent, sha1_hash const* filehash
|
void file_storage::add_file(file_entry const& ent, char const* filehash
|
||||||
, std::string const* symlink)
|
, std::string const* symlink, time_t mtime)
|
||||||
{
|
{
|
||||||
if (!has_parent_path(ent.path))
|
if (!has_parent_path(ent.filename()))
|
||||||
{
|
{
|
||||||
// you have already added at least one file with a
|
// you have already added at least one file with a
|
||||||
// path to the file (branch_path), which means that
|
// path to the file (branch_path), which means that
|
||||||
// all the other files need to be in the same top
|
// all the other files need to be in the same top
|
||||||
// directory as the first file.
|
// directory as the first file.
|
||||||
TORRENT_ASSERT(m_files.empty());
|
TORRENT_ASSERT(m_files.empty());
|
||||||
m_name = ent.path;
|
m_name = ent.filename();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_files.empty())
|
if (m_files.empty())
|
||||||
m_name = *ent.path.begin();
|
m_name = split_path(ent.filename()).c_str();
|
||||||
}
|
}
|
||||||
m_files.push_back(ent);
|
m_files.push_back(ent);
|
||||||
file_entry& e = m_files.back();
|
file_entry& e = m_files.back();
|
||||||
e.offset = m_total_size;
|
e.offset = m_total_size;
|
||||||
e.file_index = m_files.size() - 1;
|
|
||||||
m_total_size += ent.size;
|
m_total_size += ent.size;
|
||||||
if (filehash)
|
if (filehash)
|
||||||
{
|
{
|
||||||
e.filehash_index = m_file_hashes.size();
|
if (m_file_hashes.size() < m_files.size()) m_file_hashes.resize(m_files.size());
|
||||||
m_file_hashes.push_back(*filehash);
|
m_file_hashes[m_files.size() - 1] = filehash;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (symlink)
|
if (symlink)
|
||||||
{
|
{
|
||||||
e.symlink_index = m_symlinks.size();
|
e.symlink_index = m_symlinks.size();
|
||||||
m_symlinks.push_back(*symlink);
|
m_symlinks.push_back(*symlink);
|
||||||
}
|
}
|
||||||
|
if (mtime)
|
||||||
|
{
|
||||||
|
if (m_mtime.size() < m_files.size()) m_mtime.resize(m_files.size());
|
||||||
|
m_mtime[m_files.size() - 1] = mtime;
|
||||||
|
}
|
||||||
|
update_path_index(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
sha1_hash file_storage::hash(file_entry const& fe) const
|
||||||
|
{
|
||||||
|
int index = &fe - &m_files[0];
|
||||||
|
if (index >= m_file_hashes.size()) return sha1_hash(0);
|
||||||
|
return sha1_hash(m_file_hashes[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const& file_storage::symlink(file_entry const& fe) const
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(fe.symlink_index < int(m_symlinks.size()));
|
||||||
|
return m_symlinks[fe.symlink_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t file_storage::mtime(file_entry const& fe) const
|
||||||
|
{
|
||||||
|
int index = &fe - &m_files[0];
|
||||||
|
if (index >= m_mtime.size()) return 0;
|
||||||
|
return m_mtime[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
int file_storage::file_index(file_entry const& fe) const
|
||||||
|
{
|
||||||
|
int index = &fe - &m_files[0];
|
||||||
|
TORRENT_ASSERT(index >= 0 && index < m_files.size());
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_storage::set_file_base(file_entry const& fe, size_type off)
|
||||||
|
{
|
||||||
|
int index = &fe - &m_files[0];
|
||||||
|
TORRENT_ASSERT(index >= 0 && index < m_files.size());
|
||||||
|
if (m_file_base.size() <= index) m_file_base.resize(index);
|
||||||
|
m_file_base[index] = off;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type file_storage::file_base(file_entry const& fe) const
|
||||||
|
{
|
||||||
|
int index = &fe - &m_files[0];
|
||||||
|
if (index >= m_file_base.size()) return 0;
|
||||||
|
return m_file_base[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compare_file_entry_size(file_entry const& fe1, file_entry const& fe2)
|
||||||
|
{ return fe1.size < fe2.size; }
|
||||||
|
|
||||||
|
void file_storage::reorder_file(int index, int dst)
|
||||||
|
{
|
||||||
|
file_entry e = m_files[index];
|
||||||
|
m_files.erase(m_files.begin() + index);
|
||||||
|
m_files.insert(m_files.begin() + dst, e);
|
||||||
|
if (!m_mtime.empty())
|
||||||
|
{
|
||||||
|
time_t mtime = 0;
|
||||||
|
if (m_mtime.size() > index)
|
||||||
|
{
|
||||||
|
mtime = m_mtime[index];
|
||||||
|
m_mtime.erase(m_mtime.begin() + index);
|
||||||
|
}
|
||||||
|
m_mtime.insert(m_mtime.begin() + dst, mtime);
|
||||||
|
}
|
||||||
|
if (!m_file_hashes.empty())
|
||||||
|
{
|
||||||
|
char const* fh = 0;
|
||||||
|
if (m_file_hashes.size() > index)
|
||||||
|
{
|
||||||
|
fh = m_file_hashes[index];
|
||||||
|
m_file_hashes.erase(m_file_hashes.begin() + index);
|
||||||
|
}
|
||||||
|
m_file_hashes.insert(m_file_hashes.begin() + dst, fh);
|
||||||
|
}
|
||||||
|
if (!m_file_base.empty())
|
||||||
|
{
|
||||||
|
size_type base = 0;
|
||||||
|
if (m_file_base.size() > index)
|
||||||
|
{
|
||||||
|
base = m_file_base[index];
|
||||||
|
m_file_base.erase(m_file_base.begin() + index);
|
||||||
|
}
|
||||||
|
m_file_base.insert(m_file_base.begin() + dst, base);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void file_storage::optimize(int pad_file_limit)
|
void file_storage::optimize(int pad_file_limit)
|
||||||
|
@ -263,10 +445,10 @@ namespace libtorrent
|
||||||
// put the largest file at the front, to make sure
|
// put the largest file at the front, to make sure
|
||||||
// it's aligned
|
// it's aligned
|
||||||
std::vector<file_entry>::iterator i = std::max_element(m_files.begin(), m_files.end()
|
std::vector<file_entry>::iterator i = std::max_element(m_files.begin(), m_files.end()
|
||||||
, boost::bind(&file_entry::size, _1) < boost::bind(&file_entry::size, _2));
|
, &compare_file_entry_size);
|
||||||
|
|
||||||
using std::iter_swap;
|
int index = file_index(*i);
|
||||||
iter_swap(i, m_files.begin());
|
reorder_file(index, 0);
|
||||||
|
|
||||||
size_type off = 0;
|
size_type off = 0;
|
||||||
int padding_file = 0;
|
int padding_file = 0;
|
||||||
|
@ -296,9 +478,9 @@ namespace libtorrent
|
||||||
if (best_match != m_files.end())
|
if (best_match != m_files.end())
|
||||||
{
|
{
|
||||||
// we found one
|
// we found one
|
||||||
file_entry e = *best_match;
|
int index = file_index(*best_match);
|
||||||
m_files.erase(best_match);
|
reorder_file(index, file_index(*i));
|
||||||
i = m_files.insert(i, e);
|
|
||||||
i->offset = off;
|
i->offset = off;
|
||||||
off += i->size;
|
off += i->size;
|
||||||
continue;
|
continue;
|
||||||
|
@ -311,10 +493,9 @@ namespace libtorrent
|
||||||
i = m_files.insert(i, e);
|
i = m_files.insert(i, e);
|
||||||
i->size = pad_size;
|
i->size = pad_size;
|
||||||
i->offset = off;
|
i->offset = off;
|
||||||
i->file_base = 0;
|
char name[30];
|
||||||
char name[10];
|
std::sprintf(name, ".____padding_file/%d", padding_file);
|
||||||
std::sprintf(name, "%d", padding_file);
|
i->set_name(name);
|
||||||
i->path = combine_path("_____padding_file", name);
|
|
||||||
i->pad_file = true;
|
i->pad_file = true;
|
||||||
off += pad_size;
|
off += pad_size;
|
||||||
++padding_file;
|
++padding_file;
|
||||||
|
|
|
@ -245,7 +245,7 @@ namespace libtorrent
|
||||||
m_data.start = start;
|
m_data.start = start;
|
||||||
m_size = length;
|
m_size = length;
|
||||||
m_begin = start - 1 - num_digits(length);
|
m_begin = start - 1 - num_digits(length);
|
||||||
m_end = start + length;
|
m_len = start - m_begin + length;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -400,7 +400,7 @@ namespace libtorrent
|
||||||
std::pair<char const*, int> lazy_entry::data_section() const
|
std::pair<char const*, int> lazy_entry::data_section() const
|
||||||
{
|
{
|
||||||
typedef std::pair<char const*, int> return_t;
|
typedef std::pair<char const*, int> return_t;
|
||||||
return return_t(m_begin, m_end - m_begin);
|
return return_t(m_begin, m_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TORRENT_USE_IOSTREAM
|
#if TORRENT_USE_IOSTREAM
|
||||||
|
|
|
@ -166,7 +166,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
file_status s;
|
file_status s;
|
||||||
error_code ec;
|
error_code ec;
|
||||||
stat_file(combine_path(save_path, i->path), &s, ec);
|
stat_file(combine_path(save_path, storage.file_path(*i)), &s, ec);
|
||||||
|
|
||||||
if (!ec)
|
if (!ec)
|
||||||
{
|
{
|
||||||
|
@ -216,7 +216,7 @@ namespace libtorrent
|
||||||
|
|
||||||
file_status s;
|
file_status s;
|
||||||
error_code ec;
|
error_code ec;
|
||||||
stat_file(combine_path(p, i->path), &s, ec);
|
stat_file(combine_path(p, fs.file_path(*i)), &s, ec);
|
||||||
|
|
||||||
if (!ec)
|
if (!ec)
|
||||||
{
|
{
|
||||||
|
@ -516,7 +516,7 @@ namespace libtorrent
|
||||||
for (file_storage::iterator file_iter = files().begin(),
|
for (file_storage::iterator file_iter = files().begin(),
|
||||||
end_iter = files().end(); file_iter != end_iter; ++file_iter)
|
end_iter = files().end(); file_iter != end_iter; ++file_iter)
|
||||||
{
|
{
|
||||||
std::string file_path = combine_path(m_save_path, file_iter->path);
|
std::string file_path = combine_path(m_save_path, files().file_path(*file_iter));
|
||||||
std::string dir = parent_path(file_path);
|
std::string dir = parent_path(file_path);
|
||||||
|
|
||||||
if (dir != last_path)
|
if (dir != last_path)
|
||||||
|
@ -527,7 +527,7 @@ namespace libtorrent
|
||||||
create_directories(last_path, ec);
|
create_directories(last_path, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
int file_index = file_iter - files().begin();
|
int file_index = files().file_index(*file_iter);
|
||||||
|
|
||||||
// ignore files that have priority 0
|
// ignore files that have priority 0
|
||||||
if (int(m_file_priority.size()) > file_index
|
if (int(m_file_priority.size()) > file_index
|
||||||
|
@ -592,7 +592,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec;
|
||||||
file_status s;
|
file_status s;
|
||||||
stat_file(combine_path(m_save_path, i->path), &s, ec);
|
stat_file(combine_path(m_save_path, files().file_path(*i)), &s, ec);
|
||||||
if (ec) continue;
|
if (ec) continue;
|
||||||
if (s.mode & file_status::regular_file && i->size > 0)
|
if (s.mode & file_status::regular_file && i->size > 0)
|
||||||
return true;
|
return true;
|
||||||
|
@ -603,8 +603,8 @@ namespace libtorrent
|
||||||
bool storage::rename_file(int index, std::string const& new_filename)
|
bool storage::rename_file(int index, std::string const& new_filename)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= m_files.num_files()) return true;
|
if (index < 0 || index >= m_files.num_files()) return true;
|
||||||
std::string old_name = combine_path(m_save_path, files().at(index).path);
|
std::string old_name = combine_path(m_save_path, files().file_path(files().at(index)));
|
||||||
m_pool.release(this, files().at(index));
|
m_pool.release(this, index);
|
||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
rename(old_name, combine_path(m_save_path, new_filename), ec);
|
rename(old_name, combine_path(m_save_path, new_filename), ec);
|
||||||
|
@ -650,8 +650,9 @@ namespace libtorrent
|
||||||
for (file_storage::iterator i = files().begin()
|
for (file_storage::iterator i = files().begin()
|
||||||
, end(files().end()); i != end; ++i)
|
, end(files().end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
std::string p = combine_path(m_save_path, i->path);
|
std::string fp = files().file_path(*i);
|
||||||
std::string bp = parent_path(i->path);
|
std::string p = combine_path(m_save_path, fp);
|
||||||
|
std::string bp = parent_path(fp);
|
||||||
std::pair<iter_t, bool> ret;
|
std::pair<iter_t, bool> ret;
|
||||||
ret.second = true;
|
ret.second = true;
|
||||||
while (ret.second && !bp.empty())
|
while (ret.second && !bp.empty())
|
||||||
|
@ -861,7 +862,7 @@ namespace libtorrent
|
||||||
for (file_storage::iterator i = f.begin()
|
for (file_storage::iterator i = f.begin()
|
||||||
, end(f.end()); i != end; ++i)
|
, end(f.end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
std::string split = split_path(i->path);
|
std::string split = split_path(f.file_path(*i));
|
||||||
to_move.insert(to_move.begin(), split);
|
to_move.insert(to_move.begin(), split);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1178,8 +1179,8 @@ ret:
|
||||||
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 == file_bytes_left);
|
TORRENT_ASSERT(slice_size == file_bytes_left);
|
||||||
TORRENT_ASSERT(files().at(slices[counter].file_index).path
|
TORRENT_ASSERT(&files().at(slices[counter].file_index)
|
||||||
== file_iter->path);
|
== &*file_iter);
|
||||||
++counter;
|
++counter;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1201,7 +1202,7 @@ ret:
|
||||||
file_handle = open_file(*file_iter, op.mode, ec);
|
file_handle = open_file(*file_iter, op.mode, ec);
|
||||||
if (!file_handle || ec)
|
if (!file_handle || ec)
|
||||||
{
|
{
|
||||||
std::string path = combine_path(m_save_path, file_iter->path);
|
std::string path = combine_path(m_save_path, files().file_path(*file_iter));
|
||||||
TORRENT_ASSERT(ec);
|
TORRENT_ASSERT(ec);
|
||||||
set_error(path, ec);
|
set_error(path, ec);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1215,23 +1216,24 @@ ret:
|
||||||
// read is unaligned, we need to fall back on a slow
|
// read is unaligned, we need to fall back on a slow
|
||||||
// special read that reads aligned buffers and copies
|
// special read that reads aligned buffers and copies
|
||||||
// it into the one supplied
|
// it into the one supplied
|
||||||
|
size_type adjusted_offset = files().file_base(*file_iter) + file_offset;
|
||||||
if ((file_handle->open_mode() & file::no_buffer)
|
if ((file_handle->open_mode() & file::no_buffer)
|
||||||
&& (((file_iter->file_base + file_offset) & (file_handle->pos_alignment()-1)) != 0
|
&& ((adjusted_offset & (file_handle->pos_alignment()-1)) != 0
|
||||||
|| (uintptr_t(tmp_bufs->iov_base) & (file_handle->buf_alignment()-1)) != 0))
|
|| (uintptr_t(tmp_bufs->iov_base) & (file_handle->buf_alignment()-1)) != 0))
|
||||||
{
|
{
|
||||||
bytes_transferred = (this->*op.unaligned_op)(file_handle, file_iter->file_base
|
bytes_transferred = (this->*op.unaligned_op)(file_handle, adjusted_offset
|
||||||
+ file_offset, tmp_bufs, num_tmp_bufs, ec);
|
, tmp_bufs, num_tmp_bufs, ec);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bytes_transferred = (int)((*file_handle).*op.regular_op)(file_iter->file_base
|
bytes_transferred = (int)((*file_handle).*op.regular_op)(adjusted_offset
|
||||||
+ file_offset, tmp_bufs, num_tmp_bufs, ec);
|
, tmp_bufs, num_tmp_bufs, ec);
|
||||||
}
|
}
|
||||||
file_offset = 0;
|
file_offset = 0;
|
||||||
|
|
||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
set_error(combine_path(m_save_path, file_iter->path), ec);
|
set_error(combine_path(m_save_path, files().file_path(*file_iter)), ec);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1312,12 +1314,12 @@ ret:
|
||||||
int cache_setting = m_settings ? settings().disk_io_write_mode : 0;
|
int cache_setting = m_settings ? settings().disk_io_write_mode : 0;
|
||||||
if (cache_setting == session_settings::disable_os_cache
|
if (cache_setting == session_settings::disable_os_cache
|
||||||
|| (cache_setting == session_settings::disable_os_cache_for_aligned_files
|
|| (cache_setting == session_settings::disable_os_cache_for_aligned_files
|
||||||
&& ((fe.offset + fe.file_base) & (m_page_size-1)) == 0))
|
&& ((fe.offset + files().file_base(fe)) & (m_page_size-1)) == 0))
|
||||||
mode |= file::no_buffer;
|
mode |= file::no_buffer;
|
||||||
if (!m_allocate_files) mode |= file::sparse;
|
if (!m_allocate_files) mode |= file::sparse;
|
||||||
if (m_settings && settings().no_atime_storage) mode |= file::no_atime;
|
if (m_settings && settings().no_atime_storage) mode |= file::no_atime;
|
||||||
|
|
||||||
return m_pool.open_file(const_cast<storage*>(this), m_save_path, fe, mode, ec);
|
return m_pool.open_file(const_cast<storage*>(this), m_save_path, fe, files(), mode, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
storage_interface* default_storage_constructor(file_storage const& fs
|
storage_interface* default_storage_constructor(file_storage const& fs
|
||||||
|
|
|
@ -4142,7 +4142,7 @@ namespace libtorrent
|
||||||
for (torrent_info::file_iterator i = m_torrent_file->begin_files()
|
for (torrent_info::file_iterator i = m_torrent_file->begin_files()
|
||||||
, end(m_torrent_file->end_files()); i != end; ++i)
|
, end(m_torrent_file->end_files()); i != end; ++i)
|
||||||
{
|
{
|
||||||
fl.push_back(i->path);
|
fl.push_back(m_torrent_file->files().file_path(*i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -184,8 +184,8 @@ namespace libtorrent
|
||||||
|
|
||||||
void verify_encoding(file_entry& target)
|
void verify_encoding(file_entry& target)
|
||||||
{
|
{
|
||||||
std::string p = target.path;
|
std::string p = target.filename();
|
||||||
if (!verify_encoding(p, true)) target.path = p;
|
if (!verify_encoding(p, true)) target.set_name(p.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should this take a char const*?
|
// TODO: should this take a char const*?
|
||||||
|
@ -233,18 +233,17 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
bool extract_single_file(lazy_entry const& dict, file_entry& target
|
bool extract_single_file(lazy_entry const& dict, file_entry& target
|
||||||
, std::string const& root_dir, sha1_hash* filehash, std::string* symlink)
|
, std::string const& root_dir, lazy_entry const** filehash, std::string* symlink
|
||||||
|
, lazy_entry const** filename, time_t* mtime)
|
||||||
{
|
{
|
||||||
if (dict.type() != lazy_entry::dict_t) return false;
|
if (dict.type() != lazy_entry::dict_t) return false;
|
||||||
lazy_entry const* length = dict.dict_find("length");
|
lazy_entry const* length = dict.dict_find("length");
|
||||||
if (length == 0 || length->type() != lazy_entry::int_t)
|
if (length == 0 || length->type() != lazy_entry::int_t)
|
||||||
return false;
|
return false;
|
||||||
target.size = length->int_value();
|
target.size = length->int_value();
|
||||||
target.path = root_dir;
|
|
||||||
target.file_base = 0;
|
|
||||||
|
|
||||||
size_type ts = dict.dict_find_int_value("mtime", -1);
|
size_type ts = dict.dict_find_int_value("mtime", -1);
|
||||||
if (ts >= 0) target.mtime = std::time_t(ts);
|
if (ts > 0) *mtime = std::time_t(ts);
|
||||||
|
|
||||||
// prefer the name.utf-8
|
// prefer the name.utf-8
|
||||||
// because if it exists, it is more
|
// because if it exists, it is more
|
||||||
|
@ -256,21 +255,25 @@ namespace libtorrent
|
||||||
if (p == 0 || p->type() != lazy_entry::list_t)
|
if (p == 0 || p->type() != lazy_entry::list_t)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
std::string path = root_dir;
|
||||||
for (int i = 0, end(p->list_size()); i < end; ++i)
|
for (int i = 0, end(p->list_size()); i < end; ++i)
|
||||||
{
|
{
|
||||||
if (p->list_at(i)->type() != lazy_entry::string_t)
|
if (p->list_at(i)->type() != lazy_entry::string_t)
|
||||||
return false;
|
return false;
|
||||||
std::string path_element = p->list_at(i)->string_value();
|
std::string path_element = p->list_at(i)->string_value();
|
||||||
|
if (i == end - 1) *filename = p->list_at(i);
|
||||||
trim_path_element(path_element);
|
trim_path_element(path_element);
|
||||||
target.path = combine_path(target.path, path_element);
|
path = combine_path(path, path_element);
|
||||||
}
|
}
|
||||||
target.path = sanitize_path(target.path);
|
path = sanitize_path(path);
|
||||||
verify_encoding(target);
|
verify_encoding(target);
|
||||||
|
|
||||||
// bitcomet pad file
|
// bitcomet pad file
|
||||||
if (target.path.find("_____padding_file_") != std::string::npos)
|
if (path.find("_____padding_file_") != std::string::npos)
|
||||||
target.pad_file = true;
|
target.pad_file = true;
|
||||||
|
|
||||||
|
target.set_name(path.c_str());
|
||||||
|
|
||||||
lazy_entry const* attr = dict.dict_find_string("attr");
|
lazy_entry const* attr = dict.dict_find_string("attr");
|
||||||
if (attr)
|
if (attr)
|
||||||
{
|
{
|
||||||
|
@ -288,11 +291,7 @@ namespace libtorrent
|
||||||
|
|
||||||
lazy_entry const* fh = dict.dict_find_string("sha1");
|
lazy_entry const* fh = dict.dict_find_string("sha1");
|
||||||
if (fh && fh->string_length() == 20 && filehash)
|
if (fh && fh->string_length() == 20 && filehash)
|
||||||
{
|
*filehash = fh;
|
||||||
std::memcpy(&(*filehash)[0], fh->string_ptr(), 20);
|
|
||||||
// indicate that the file has a filehash
|
|
||||||
target.filehash_index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_entry const* s_p = dict.dict_find("symlink path");
|
lazy_entry const* s_p = dict.dict_find("symlink path");
|
||||||
if (s_p != 0 && s_p->type() == lazy_entry::list_t && symlink)
|
if (s_p != 0 && s_p->type() == lazy_entry::list_t && symlink)
|
||||||
|
@ -332,16 +331,19 @@ namespace libtorrent
|
||||||
};
|
};
|
||||||
|
|
||||||
bool extract_files(lazy_entry const& list, file_storage& target
|
bool extract_files(lazy_entry const& list, file_storage& target
|
||||||
, std::string const& root_dir)
|
, std::string const& root_dir, ptrdiff_t info_ptr_diff)
|
||||||
{
|
{
|
||||||
if (list.type() != lazy_entry::list_t) return false;
|
if (list.type() != lazy_entry::list_t) return false;
|
||||||
target.reserve(list.list_size());
|
target.reserve(list.list_size());
|
||||||
for (int i = 0, end(list.list_size()); i < end; ++i)
|
for (int i = 0, end(list.list_size()); i < end; ++i)
|
||||||
{
|
{
|
||||||
sha1_hash file_hash;
|
lazy_entry const* file_hash = 0;
|
||||||
|
time_t mtime = 0;
|
||||||
std::string symlink;
|
std::string symlink;
|
||||||
file_entry e;
|
file_entry e;
|
||||||
if (!extract_single_file(*list.list_at(i), e, root_dir, &file_hash, &symlink))
|
lazy_entry const* fee = 0;
|
||||||
|
if (!extract_single_file(*list.list_at(i), e, root_dir
|
||||||
|
, &file_hash, &symlink, &fee, &mtime))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// TODO: this logic should be a separate step
|
// TODO: this logic should be a separate step
|
||||||
|
@ -352,15 +354,31 @@ namespace libtorrent
|
||||||
|
|
||||||
// as long as this file already exists
|
// as long as this file already exists
|
||||||
// increase the counter
|
// increase the counter
|
||||||
while (!files.insert(e.path).second)
|
std::string path = e.filename();
|
||||||
|
while (!files.insert(path).second)
|
||||||
{
|
{
|
||||||
++cnt;
|
++cnt;
|
||||||
char suffix[50];
|
char suffix[50];
|
||||||
snprintf(suffix, sizeof(suffix), ".%d%s", cnt, extension(e.path).c_str());
|
snprintf(suffix, sizeof(suffix), ".%d%s", cnt, extension(path).c_str());
|
||||||
replace_extension(e.path, suffix);
|
replace_extension(path, suffix);
|
||||||
|
}
|
||||||
|
e.set_name(path.c_str());
|
||||||
|
target.add_file(e, file_hash ? file_hash->string_ptr() + info_ptr_diff : 0
|
||||||
|
, e.symlink_index != -1 ? &symlink : 0, mtime);
|
||||||
|
|
||||||
|
// This is a memory optimization! Instead of having
|
||||||
|
// each entry keep a string for its filename, make it
|
||||||
|
// simply point into the info-section buffer
|
||||||
|
file_entry const& fe = target.at(target.num_files() - 1);
|
||||||
|
// TODO: once the filename renaming is removed from here
|
||||||
|
// this check can be removed as well
|
||||||
|
if (fee && fe.filename() == fee->string_value())
|
||||||
|
{
|
||||||
|
// this string pointer does not necessarily point into
|
||||||
|
// the m_info_section buffer.
|
||||||
|
char const* str_ptr = fee->string_ptr() + info_ptr_diff;
|
||||||
|
const_cast<file_entry&>(fe).set_name(str_ptr, fee->string_length());
|
||||||
}
|
}
|
||||||
target.add_file(e, e.filehash_index != -1 ? &file_hash : 0
|
|
||||||
, e.symlink_index != -1 ? &symlink : 0);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -748,6 +766,11 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(section.first[0] == 'd');
|
TORRENT_ASSERT(section.first[0] == 'd');
|
||||||
TORRENT_ASSERT(section.first[m_info_section_size-1] == 'e');
|
TORRENT_ASSERT(section.first[m_info_section_size-1] == 'e');
|
||||||
|
|
||||||
|
// when translating a pointer that points into the 'info' tree's
|
||||||
|
// backing buffer, into a pointer to our copy of the info section,
|
||||||
|
// this is the pointer offset to use.
|
||||||
|
ptrdiff_t info_ptr_diff = m_info_section.get() - section.first;
|
||||||
|
|
||||||
// extract piece length
|
// extract piece length
|
||||||
int piece_length = info.dict_find_int_value("piece length", -1);
|
int piece_length = info.dict_find_int_value("piece length", -1);
|
||||||
if (piece_length <= 0)
|
if (piece_length <= 0)
|
||||||
|
@ -784,12 +807,12 @@ 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 = name;
|
e.set_name(name.c_str());
|
||||||
e.offset = 0;
|
e.offset = 0;
|
||||||
e.size = info.dict_find_int_value("length", -1);
|
e.size = info.dict_find_int_value("length", -1);
|
||||||
size_type ts = info.dict_find_int_value("mtime", -1);
|
size_type ts = info.dict_find_int_value("mtime", -1);
|
||||||
if (ts >= 0)
|
time_t mtime = 0;
|
||||||
e.mtime = std::time_t(ts);
|
if (ts > 0) mtime = std::time_t(ts);
|
||||||
lazy_entry const* attr = info.dict_find_string("attr");
|
lazy_entry const* attr = info.dict_find_string("attr");
|
||||||
if (attr)
|
if (attr)
|
||||||
{
|
{
|
||||||
|
@ -818,29 +841,23 @@ namespace libtorrent
|
||||||
e.symlink_index = 0;
|
e.symlink_index = 0;
|
||||||
}
|
}
|
||||||
lazy_entry const* fh = info.dict_find_string("sha1");
|
lazy_entry const* fh = info.dict_find_string("sha1");
|
||||||
sha1_hash filehash;
|
if (fh && fh->string_length() != 20) fh = 0;
|
||||||
if (fh && fh->string_length() == 20)
|
|
||||||
{
|
|
||||||
std::memcpy(&filehash[0], fh->string_ptr(), 20);
|
|
||||||
e.filehash_index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bitcomet pad file
|
// bitcomet pad file
|
||||||
if (e.path.find("_____padding_file_") != std::string::npos)
|
if (e.filename().find("_____padding_file_") != std::string::npos)
|
||||||
e.pad_file = true;
|
e.pad_file = true;
|
||||||
if (e.size < 0)
|
if (e.size < 0)
|
||||||
{
|
{
|
||||||
ec = errors::torrent_invalid_length;
|
ec = errors::torrent_invalid_length;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool omit_hash = (flags & torrent_info::omit_filehashes) || e.filehash_index == -1;
|
m_files.add_file(e, fh ? fh->string_ptr() + info_ptr_diff : 0
|
||||||
m_files.add_file(e, omit_hash ? 0 : &filehash
|
, e.symlink_index != -1 ? &symlink : 0, mtime);
|
||||||
, e.symlink_index != -1 ? &symlink : 0);
|
|
||||||
m_multifile = false;
|
m_multifile = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!extract_files(*i, m_files, name))
|
if (!extract_files(*i, m_files, name, info_ptr_diff))
|
||||||
{
|
{
|
||||||
ec = errors::torrent_file_parse_failed;
|
ec = errors::torrent_file_parse_failed;
|
||||||
return false;
|
return false;
|
||||||
|
@ -873,7 +890,7 @@ namespace libtorrent
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_piece_hashes = m_info_section.get() + (pieces->string_ptr() - section.first);
|
m_piece_hashes = pieces->string_ptr() + info_ptr_diff;
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -1204,7 +1221,7 @@ namespace libtorrent
|
||||||
os << "piece length: " << piece_length() << "\n";
|
os << "piece length: " << piece_length() << "\n";
|
||||||
os << "files:\n";
|
os << "files:\n";
|
||||||
for (file_storage::iterator i = m_files.begin(); i != m_files.end(); ++i)
|
for (file_storage::iterator i = m_files.begin(); i != m_files.end(); ++i)
|
||||||
os << " " << std::setw(11) << i->size << " " << i->path << "\n";
|
os << " " << std::setw(11) << i->size << " " << m_files.file_path(*i) << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------- end deprecation -------
|
// ------- end deprecation -------
|
||||||
|
|
|
@ -210,7 +210,7 @@ namespace libtorrent
|
||||||
if (using_proxy)
|
if (using_proxy)
|
||||||
{
|
{
|
||||||
request += m_url;
|
request += m_url;
|
||||||
std::string path = info.orig_files().at(f.file_index).path;
|
std::string path = info.orig_files().file_path(info.orig_files().at(f.file_index));
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
convert_path_to_posix(path);
|
convert_path_to_posix(path);
|
||||||
#endif
|
#endif
|
||||||
|
@ -219,7 +219,7 @@ namespace libtorrent
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::string path = m_path;
|
std::string path = m_path;
|
||||||
path += info.orig_files().at(f.file_index).path;
|
path += info.orig_files().file_path(info.orig_files().at(f.file_index));
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
convert_path_to_posix(path);
|
convert_path_to_posix(path);
|
||||||
#endif
|
#endif
|
||||||
|
@ -421,7 +421,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.orig_files().at(file_index).path;
|
std::string path = info.orig_files().file_path(info.orig_files().at(file_index));
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
convert_path_to_posix(path);
|
convert_path_to_posix(path);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -804,7 +804,7 @@ void run_test(std::string const& test_path, bool unbuffered)
|
||||||
file_storage fs;
|
file_storage fs;
|
||||||
fs.add_file("temp_storage/test1.tmp", 3 * piece_size);
|
fs.add_file("temp_storage/test1.tmp", 3 * piece_size);
|
||||||
libtorrent::create_torrent t(fs, piece_size, -1, 0);
|
libtorrent::create_torrent t(fs, piece_size, -1, 0);
|
||||||
TEST_CHECK(fs.begin()->path == "temp_storage/test1.tmp");
|
TEST_CHECK(fs.file_path(*fs.begin()) == "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());
|
||||||
|
|
|
@ -151,7 +151,8 @@ void test_transfer(boost::intrusive_ptr<torrent_info> torrent_file
|
||||||
|
|
||||||
if (proxy) stop_proxy(8002);
|
if (proxy) stop_proxy(8002);
|
||||||
|
|
||||||
TEST_CHECK(exists(combine_path("./tmp2_web_seed", torrent_file->file_at(0).path)));
|
TEST_CHECK(exists(combine_path("./tmp2_web_seed", torrent_file->files().file_path(
|
||||||
|
torrent_file->file_at(0)))));
|
||||||
remove_all("./tmp2_web_seed", ec);
|
remove_all("./tmp2_web_seed", ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,10 +257,11 @@ int run_suite(char const* protocol, bool test_url_seed, bool chunked_encoding)
|
||||||
// verify that the file hashes are correct
|
// verify that the file hashes are correct
|
||||||
for (int i = 0; i < torrent_file->num_files(); ++i)
|
for (int i = 0; i < torrent_file->num_files(); ++i)
|
||||||
{
|
{
|
||||||
TEST_CHECK(torrent_file->file_at(i).filehash_index >= 0);
|
sha1_hash h1 = torrent_file->files().hash(torrent_file->file_at(i));
|
||||||
sha1_hash h1 = torrent_file->files().hash(torrent_file->file_at(i).filehash_index);
|
sha1_hash h2 = file_hash(combine_path("./tmp1_web_seed"
|
||||||
sha1_hash h2 = file_hash(combine_path("./tmp1_web_seed", torrent_file->file_at(i).path));
|
, torrent_file->files().file_path(torrent_file->file_at(i))));
|
||||||
fprintf(stderr, "%s: %s == %s\n", torrent_file->file_at(i).path.c_str()
|
fprintf(stderr, "%s: %s == %s\n"
|
||||||
|
, torrent_file->files().file_path(torrent_file->file_at(i)).c_str()
|
||||||
, to_hex(h1.to_string()).c_str(), to_hex(h2.to_string()).c_str());
|
, to_hex(h1.to_string()).c_str(), to_hex(h2.to_string()).c_str());
|
||||||
TEST_EQUAL(h1, h2);
|
TEST_EQUAL(h1, h2);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue