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
|
||||
* graceful peer disconnect mode which finishes transactions before disconnecting peers
|
||||
* support chunked encoding for web seeds
|
||||
|
@ -48,12 +48,12 @@ namespace
|
||||
ct.add_node(std::make_pair(addr, port));
|
||||
}
|
||||
|
||||
void add_file(file_storage& ct, file_entry const& fe
|
||||
, std::string const& hash, std::string const& linkpath)
|
||||
{
|
||||
ct.add_file(fe, hash.empty() ? 0 : &sha1_hash(hash)
|
||||
, linkpath.empty() ? 0 : &linkpath);
|
||||
}
|
||||
void add_file(file_storage& ct, file_entry const& fe
|
||||
, std::string const& hash, std::string const& linkpath)
|
||||
{
|
||||
ct.add_file(fe, hash.empty() ? 0 : hash.c_str()
|
||||
, linkpath.empty() ? 0 : &linkpath);
|
||||
}
|
||||
}
|
||||
|
||||
void bind_create_torrent()
|
||||
@ -82,6 +82,12 @@ void bind_create_torrent()
|
||||
#endif
|
||||
.def("num_files", &file_storage::num_files)
|
||||
.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("set_num_pieces", &file_storage::set_num_pieces)
|
||||
.def("num_pieces", &file_storage::num_pieces)
|
||||
|
@ -102,6 +102,20 @@ namespace
|
||||
bool get_send_stats(announce_entry const& ae)
|
||||
{ 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
|
||||
|
||||
void bind_torrent_info()
|
||||
@ -168,14 +182,14 @@ void bind_torrent_info()
|
||||
;
|
||||
|
||||
class_<file_entry>("file_entry")
|
||||
.add_property("path"
|
||||
, make_getter(
|
||||
&file_entry::path, return_value_policy<copy_non_const_reference>()
|
||||
)
|
||||
)
|
||||
.def_readonly("offset", &file_entry::offset)
|
||||
.def_readonly("size", &file_entry::size)
|
||||
.def_readonly("file_base", &file_entry::file_base)
|
||||
.def("filename", &file_entry::filename)
|
||||
.def("set_name", &file_entry::set_name)
|
||||
.add_property("pad_file", &get_pad_file)
|
||||
.add_property("executable_attribute", &get_executable_attribute)
|
||||
.add_property("hidden_attribute", &get_hidden_attribute)
|
||||
.add_property("symlink_attribute", &get_symlink_attribute)
|
||||
.add_property("offset", &get_offset)
|
||||
.add_property("size", &get_size)
|
||||
;
|
||||
|
||||
class_<announce_entry>("announce_entry", init<std::string const&>())
|
||||
|
@ -172,8 +172,12 @@ file structure. Its synopsis::
|
||||
int piece_length() const;
|
||||
int piece_size(int index) const;
|
||||
|
||||
sha1_hash const& hash(int index) const;
|
||||
std::string const& symlink(int index) const;
|
||||
sha1_hash const& hash(file_entry const& fe) 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::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
|
||||
make sure this requirement is fulfilled.
|
||||
|
||||
hash() symlink()
|
||||
----------------
|
||||
hash() symlink() mtime() file_index()
|
||||
-------------------------------------
|
||||
|
||||
::
|
||||
|
||||
sha1_hash const& hash(int index) const;
|
||||
std::string const& symlink(int index) const;
|
||||
sha1_hash hash(file_entry const& fe) 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
|
||||
index in ``file_entry``.
|
||||
These functions are used to query the symlink, file hash,
|
||||
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
|
||||
==============
|
||||
|
@ -1350,9 +1350,6 @@ The ``torrent_info`` has the following synopsis::
|
||||
{
|
||||
public:
|
||||
|
||||
// flags for torrent_info constructor
|
||||
enum flags_t { omit_filehashes = 1 };
|
||||
|
||||
// these constructors throws exceptions on error
|
||||
torrent_info(sha1_hash const& info_hash, 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
|
||||
exception support.
|
||||
|
||||
The ``flags`` argument can be used to disable loading of potentially unnecessary hashes
|
||||
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.
|
||||
The ``flags`` argument is currently unused.
|
||||
|
||||
|
||||
add_tracker()
|
||||
@ -1547,7 +1541,7 @@ iterators with the type ``file_entry``.
|
||||
|
||||
struct file_entry
|
||||
{
|
||||
std::string path;
|
||||
std::string filename();
|
||||
size_type offset;
|
||||
size_type size;
|
||||
size_type file_base;
|
||||
@ -1560,9 +1554,9 @@ iterators with the type ``file_entry``.
|
||||
bool symlink_attribute:1;
|
||||
};
|
||||
|
||||
The ``path`` is the full (relative) path of each file. i.e. if it is a multi-file
|
||||
torrent, all the files starts with a directory with the same name as ``torrent_info::name()``.
|
||||
The filenames are encoded with UTF-8.
|
||||
The ``filename`` function returns the filename of this file. It does not include the
|
||||
path, just the leaf name. To get the full path name, use ``file_storage::file_path()``.
|
||||
The filenames are unicode strings encoded in UTF-8.
|
||||
|
||||
``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
|
||||
@ -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
|
||||
-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.
|
||||
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.
|
||||
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"):""
|
||||
, progress / 10.f
|
||||
, 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"):"");
|
||||
out += str;
|
||||
}
|
||||
|
@ -40,6 +40,8 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
using namespace libtorrent;
|
||||
|
||||
printf("sizeof(file_entry): %d\n", int(sizeof(file_entry)));
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
fputs("usage: dump_torrent torrent-file\n", stderr);
|
||||
@ -70,7 +72,7 @@ int main(int argc, char* argv[])
|
||||
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);
|
||||
if (ec)
|
||||
@ -78,6 +80,8 @@ int main(int argc, char* argv[])
|
||||
fprintf(stderr, "%s\n", ec.message().c_str());
|
||||
return 1;
|
||||
}
|
||||
e.clear();
|
||||
std::vector<char>().swap(buf);
|
||||
|
||||
// print info about torrent
|
||||
printf("\n\n----- torrent file info -----\n\n"
|
||||
@ -106,6 +110,7 @@ int main(int argc, char* argv[])
|
||||
"created by: %s\n"
|
||||
"magnet link: %s\n"
|
||||
"name: %s\n"
|
||||
"number of files: %d\n"
|
||||
"files:\n"
|
||||
, t.num_pieces()
|
||||
, t.piece_length()
|
||||
@ -113,24 +118,26 @@ int main(int argc, char* argv[])
|
||||
, t.comment().c_str()
|
||||
, t.creator().c_str()
|
||||
, make_magnet_uri(t).c_str()
|
||||
, t.name().c_str());
|
||||
, t.name().c_str()
|
||||
, t.num_files());
|
||||
int index = 0;
|
||||
for (torrent_info::file_iterator i = t.begin_files();
|
||||
i != t.end_files(); ++i, ++index)
|
||||
{
|
||||
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;
|
||||
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->pad_file?'p':'-')
|
||||
, (i->executable_attribute?'x':'-')
|
||||
, (i->hidden_attribute?'h':'-')
|
||||
, (i->symlink_attribute?'l':'-')
|
||||
, first, last
|
||||
, i->filehash_index != -1 ? to_hex(t.files().hash(i->filehash_index).to_string()).c_str() : ""
|
||||
, i->path.c_str()
|
||||
, boost::uint32_t(t.files().mtime(*i))
|
||||
, 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_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;
|
||||
|
@ -84,7 +84,7 @@ int main(int argc, char const* argv[])
|
||||
{
|
||||
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"
|
||||
, 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;
|
||||
}
|
||||
|
||||
|
@ -51,15 +51,16 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
namespace libtorrent
|
||||
{
|
||||
struct file_entry;
|
||||
struct file_storage;
|
||||
|
||||
struct TORRENT_EXPORT file_pool : boost::noncopyable
|
||||
{
|
||||
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
|
||||
, 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, file_entry const& fe);
|
||||
void release(void* st, int file_index);
|
||||
void resize(int size);
|
||||
int size_limit() const { return m_size; }
|
||||
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/peer_request.hpp"
|
||||
#include "libtorrent/peer_id.hpp"
|
||||
#include "libtorrent/copy_ptr.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
@ -49,43 +48,59 @@ namespace libtorrent
|
||||
|
||||
struct TORRENT_EXPORT file_entry
|
||||
{
|
||||
friend class file_storage;
|
||||
file_entry()
|
||||
: offset(0)
|
||||
, size(0)
|
||||
, file_base(0)
|
||||
, mtime(0)
|
||||
, file_index(0)
|
||||
, filehash_index(-1)
|
||||
: name(0)
|
||||
, offset(0)
|
||||
, symlink_index(-1)
|
||||
, size(0)
|
||||
, name_len(0)
|
||||
, pad_file(false)
|
||||
, hidden_attribute(false)
|
||||
, executable_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
|
||||
size_type offset;
|
||||
// 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;
|
||||
size_type offset:48;
|
||||
|
||||
// index into file_storage::m_symlinks or -1
|
||||
// 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 hidden_attribute:1;
|
||||
bool executable_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
|
||||
@ -114,11 +129,12 @@ namespace libtorrent
|
||||
|
||||
void reserve(int num_files);
|
||||
|
||||
void add_file(file_entry const& e, sha1_hash const* filehash = 0
|
||||
, std::string const* symlink = 0);
|
||||
void add_file(file_entry const& e, char const* filehash = 0
|
||||
, std::string const* symlink = 0, time_t mtime = 0);
|
||||
|
||||
void add_file(std::string const& p, size_type size, int flags = 0
|
||||
, std::time_t mtime = 0, std::string const& s_p = "");
|
||||
|
||||
void rename_file(int index, std::string const& new_filename);
|
||||
|
||||
#if TORRENT_USE_WSTRING
|
||||
@ -149,17 +165,14 @@ namespace libtorrent
|
||||
return m_files[index];
|
||||
}
|
||||
|
||||
sha1_hash const& hash(int index) const
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0 && index < int(m_file_hashes.size()));
|
||||
return m_file_hashes[index];
|
||||
}
|
||||
|
||||
std::string const& symlink(int index) const
|
||||
{
|
||||
TORRENT_ASSERT(index >= 0 && index < int(m_symlinks.size()));
|
||||
return m_symlinks[index];
|
||||
}
|
||||
sha1_hash hash(file_entry const& fe) 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);
|
||||
|
||||
std::string file_path(file_entry const& fe) const;
|
||||
|
||||
size_type total_size() const { return m_total_size; }
|
||||
void set_num_pieces(int n) { m_num_pieces = n; }
|
||||
@ -188,19 +201,40 @@ namespace libtorrent
|
||||
|
||||
private:
|
||||
|
||||
void update_path_index(file_entry& e);
|
||||
void reorder_file(int index, int dst);
|
||||
|
||||
// the list of files that this torrent consists of
|
||||
std::vector<file_entry> m_files;
|
||||
|
||||
// if there are sha1 hashes for each individual file
|
||||
// each file_entry has an index into this vector
|
||||
// and the actual hashes are in here
|
||||
std::vector<sha1_hash> m_file_hashes;
|
||||
// there are as many entries in this array as the
|
||||
// m_files array. Each entry in m_files has a corresponding
|
||||
// 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
|
||||
// path_index in the file_entry indexes
|
||||
// this vector of strings
|
||||
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
|
||||
// this is always the root directory
|
||||
std::string m_name;
|
||||
|
@ -78,7 +78,7 @@ namespace libtorrent
|
||||
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; }
|
||||
|
||||
entry_type_t type() const { return (entry_type_t)m_type; }
|
||||
@ -92,7 +92,7 @@ namespace libtorrent
|
||||
m_data.start = start;
|
||||
m_size = length;
|
||||
m_begin = start - 1; // include 'i'
|
||||
m_end = start + length + 1; // include 'e'
|
||||
m_len = length + 2; // include 'e'
|
||||
}
|
||||
|
||||
size_type int_value() const;
|
||||
@ -202,7 +202,7 @@ namespace libtorrent
|
||||
void set_end(char const* end)
|
||||
{
|
||||
TORRENT_ASSERT(end > m_begin);
|
||||
m_end = end;
|
||||
m_len = end - m_begin;
|
||||
}
|
||||
|
||||
void clear();
|
||||
@ -235,7 +235,7 @@ namespace libtorrent
|
||||
swap(m_data.start, e.m_data.start);
|
||||
swap(m_size, e.m_size);
|
||||
swap(m_begin, e.m_begin);
|
||||
swap(m_end, e.m_end);
|
||||
swap(m_len, e.m_len);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -250,11 +250,16 @@ namespace libtorrent
|
||||
// used for dictionaries and lists to record the range
|
||||
// in the original buffer they are based on
|
||||
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
|
||||
boost::uint32_t m_capacity:29; // if list or dictionary, allocated number of items
|
||||
unsigned int m_type:3;
|
||||
// if list or dictionary, the number of items
|
||||
boost::uint32_t m_size;
|
||||
// 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
|
||||
lazy_entry(lazy_entry const&);
|
||||
|
@ -227,8 +227,6 @@ namespace libtorrent
|
||||
{
|
||||
public:
|
||||
|
||||
enum flags_t { omit_filehashes = 1 };
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
torrent_info(lazy_entry const& torrent_file, 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
|
||||
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
|
||||
if (piece_size == 0 && !m_merkle_torrent)
|
||||
@ -301,7 +301,7 @@ namespace libtorrent
|
||||
|
||||
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;
|
||||
if (m_files.at(0).pad_file
|
||||
|| m_files.at(0).hidden_attribute
|
||||
@ -320,7 +320,7 @@ namespace libtorrent
|
||||
{
|
||||
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))
|
||||
sympath_e.list().push_back(entry(e));
|
||||
}
|
||||
@ -340,13 +340,13 @@ namespace libtorrent
|
||||
{
|
||||
files.list().push_back(entry());
|
||||
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;
|
||||
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());
|
||||
|
||||
for (char const* e = next_path_element(split.c_str());
|
||||
@ -370,7 +370,7 @@ namespace libtorrent
|
||||
{
|
||||
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))
|
||||
sympath_e.list().push_back(entry(e));
|
||||
}
|
||||
|
@ -41,14 +41,14 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
namespace libtorrent
|
||||
{
|
||||
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(is_complete(p));
|
||||
TORRENT_ASSERT((m & file::rw_mask) == file::read_only
|
||||
|| (m & file::rw_mask) == file::read_write);
|
||||
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())
|
||||
{
|
||||
lru_file_entry& e = i->second;
|
||||
@ -77,7 +77,7 @@ namespace libtorrent
|
||||
// the new read/write privilages
|
||||
TORRENT_ASSERT(e.file_ptr->refcount() == 1);
|
||||
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))
|
||||
{
|
||||
m_files.erase(i);
|
||||
@ -115,12 +115,12 @@ namespace libtorrent
|
||||
ec = error_code(ENOMEM, get_posix_category());
|
||||
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))
|
||||
return boost::intrusive_ptr<file>();
|
||||
e.mode = m;
|
||||
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());
|
||||
return e.file_ptr;
|
||||
}
|
||||
@ -134,10 +134,10 @@ namespace libtorrent
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,88 @@ namespace libtorrent
|
||||
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
|
||||
void file_storage::set_name(std::wstring const& n)
|
||||
{
|
||||
@ -80,7 +162,8 @@ namespace libtorrent
|
||||
TORRENT_ASSERT(index >= 0 && index < int(m_files.size()));
|
||||
std::string 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
|
||||
@ -95,7 +178,8 @@ namespace libtorrent
|
||||
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;
|
||||
m_files[index].set_name(new_filename.c_str());
|
||||
update_path_index(m_files[index]);
|
||||
}
|
||||
|
||||
namespace
|
||||
@ -149,7 +233,7 @@ namespace libtorrent
|
||||
{
|
||||
file_slice f;
|
||||
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);
|
||||
size -= f.size;
|
||||
file_offset += f.size;
|
||||
@ -161,6 +245,13 @@ namespace libtorrent
|
||||
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
|
||||
, int size) const
|
||||
{
|
||||
@ -196,9 +287,8 @@ namespace libtorrent
|
||||
TORRENT_ASSERT(m_name == split_path(file).c_str());
|
||||
m_files.push_back(file_entry());
|
||||
file_entry& e = m_files.back();
|
||||
e.file_index = m_files.size() - 1;
|
||||
e.set_name(file.c_str());
|
||||
e.size = size;
|
||||
e.path = file;
|
||||
e.offset = m_total_size;
|
||||
e.pad_file = (flags & pad_file) != 0;
|
||||
e.hidden_attribute = (flags & attribute_hidden) != 0;
|
||||
@ -208,45 +298,137 @@ namespace libtorrent
|
||||
{
|
||||
e.symlink_index = m_symlinks.size();
|
||||
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;
|
||||
}
|
||||
|
||||
void file_storage::add_file(file_entry const& ent, sha1_hash const* filehash
|
||||
, std::string const* symlink)
|
||||
void file_storage::add_file(file_entry const& ent, char const* filehash
|
||||
, 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
|
||||
// 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 = ent.path;
|
||||
m_name = ent.filename();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_files.empty())
|
||||
m_name = *ent.path.begin();
|
||||
m_name = split_path(ent.filename()).c_str();
|
||||
}
|
||||
m_files.push_back(ent);
|
||||
file_entry& e = m_files.back();
|
||||
e.offset = m_total_size;
|
||||
e.file_index = m_files.size() - 1;
|
||||
m_total_size += ent.size;
|
||||
if (filehash)
|
||||
{
|
||||
e.filehash_index = m_file_hashes.size();
|
||||
m_file_hashes.push_back(*filehash);
|
||||
if (m_file_hashes.size() < m_files.size()) m_file_hashes.resize(m_files.size());
|
||||
m_file_hashes[m_files.size() - 1] = filehash;
|
||||
}
|
||||
|
||||
if (symlink)
|
||||
{
|
||||
e.symlink_index = m_symlinks.size();
|
||||
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)
|
||||
@ -263,10 +445,10 @@ namespace libtorrent
|
||||
// put the largest file at the front, to make sure
|
||||
// it's aligned
|
||||
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;
|
||||
iter_swap(i, m_files.begin());
|
||||
int index = file_index(*i);
|
||||
reorder_file(index, 0);
|
||||
|
||||
size_type off = 0;
|
||||
int padding_file = 0;
|
||||
@ -296,9 +478,9 @@ namespace libtorrent
|
||||
if (best_match != m_files.end())
|
||||
{
|
||||
// we found one
|
||||
file_entry e = *best_match;
|
||||
m_files.erase(best_match);
|
||||
i = m_files.insert(i, e);
|
||||
int index = file_index(*best_match);
|
||||
reorder_file(index, file_index(*i));
|
||||
|
||||
i->offset = off;
|
||||
off += i->size;
|
||||
continue;
|
||||
@ -311,10 +493,9 @@ namespace libtorrent
|
||||
i = m_files.insert(i, e);
|
||||
i->size = pad_size;
|
||||
i->offset = off;
|
||||
i->file_base = 0;
|
||||
char name[10];
|
||||
std::sprintf(name, "%d", padding_file);
|
||||
i->path = combine_path("_____padding_file", name);
|
||||
char name[30];
|
||||
std::sprintf(name, ".____padding_file/%d", padding_file);
|
||||
i->set_name(name);
|
||||
i->pad_file = true;
|
||||
off += pad_size;
|
||||
++padding_file;
|
||||
|
@ -245,7 +245,7 @@ namespace libtorrent
|
||||
m_data.start = start;
|
||||
m_size = length;
|
||||
m_begin = start - 1 - num_digits(length);
|
||||
m_end = start + length;
|
||||
m_len = start - m_begin + length;
|
||||
}
|
||||
|
||||
namespace
|
||||
@ -400,7 +400,7 @@ namespace libtorrent
|
||||
std::pair<char const*, int> lazy_entry::data_section() const
|
||||
{
|
||||
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
|
||||
|
@ -166,7 +166,7 @@ namespace libtorrent
|
||||
{
|
||||
file_status s;
|
||||
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)
|
||||
{
|
||||
@ -216,7 +216,7 @@ namespace libtorrent
|
||||
|
||||
file_status s;
|
||||
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)
|
||||
{
|
||||
@ -516,7 +516,7 @@ namespace libtorrent
|
||||
for (file_storage::iterator file_iter = files().begin(),
|
||||
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);
|
||||
|
||||
if (dir != last_path)
|
||||
@ -527,7 +527,7 @@ namespace libtorrent
|
||||
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
|
||||
if (int(m_file_priority.size()) > file_index
|
||||
@ -592,7 +592,7 @@ namespace libtorrent
|
||||
{
|
||||
error_code ec;
|
||||
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 (s.mode & file_status::regular_file && i->size > 0)
|
||||
return true;
|
||||
@ -603,8 +603,8 @@ namespace libtorrent
|
||||
bool storage::rename_file(int index, std::string const& new_filename)
|
||||
{
|
||||
if (index < 0 || index >= m_files.num_files()) return true;
|
||||
std::string old_name = combine_path(m_save_path, files().at(index).path);
|
||||
m_pool.release(this, files().at(index));
|
||||
std::string old_name = combine_path(m_save_path, files().file_path(files().at(index)));
|
||||
m_pool.release(this, index);
|
||||
|
||||
error_code 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()
|
||||
, end(files().end()); i != end; ++i)
|
||||
{
|
||||
std::string p = combine_path(m_save_path, i->path);
|
||||
std::string bp = parent_path(i->path);
|
||||
std::string fp = files().file_path(*i);
|
||||
std::string p = combine_path(m_save_path, fp);
|
||||
std::string bp = parent_path(fp);
|
||||
std::pair<iter_t, bool> ret;
|
||||
ret.second = true;
|
||||
while (ret.second && !bp.empty())
|
||||
@ -861,7 +862,7 @@ namespace libtorrent
|
||||
for (file_storage::iterator i = f.begin()
|
||||
, 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);
|
||||
}
|
||||
|
||||
@ -1178,8 +1179,8 @@ ret:
|
||||
TORRENT_ASSERT(int(slices.size()) > counter);
|
||||
size_type slice_size = slices[counter].size;
|
||||
TORRENT_ASSERT(slice_size == file_bytes_left);
|
||||
TORRENT_ASSERT(files().at(slices[counter].file_index).path
|
||||
== file_iter->path);
|
||||
TORRENT_ASSERT(&files().at(slices[counter].file_index)
|
||||
== &*file_iter);
|
||||
++counter;
|
||||
#endif
|
||||
|
||||
@ -1201,7 +1202,7 @@ ret:
|
||||
file_handle = open_file(*file_iter, op.mode, 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);
|
||||
set_error(path, ec);
|
||||
return -1;
|
||||
@ -1215,23 +1216,24 @@ ret:
|
||||
// read is unaligned, we need to fall back on a slow
|
||||
// special read that reads aligned buffers and copies
|
||||
// it into the one supplied
|
||||
size_type adjusted_offset = files().file_base(*file_iter) + file_offset;
|
||||
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))
|
||||
{
|
||||
bytes_transferred = (this->*op.unaligned_op)(file_handle, file_iter->file_base
|
||||
+ file_offset, tmp_bufs, num_tmp_bufs, ec);
|
||||
bytes_transferred = (this->*op.unaligned_op)(file_handle, adjusted_offset
|
||||
, tmp_bufs, num_tmp_bufs, ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes_transferred = (int)((*file_handle).*op.regular_op)(file_iter->file_base
|
||||
+ file_offset, tmp_bufs, num_tmp_bufs, ec);
|
||||
bytes_transferred = (int)((*file_handle).*op.regular_op)(adjusted_offset
|
||||
, tmp_bufs, num_tmp_bufs, ec);
|
||||
}
|
||||
file_offset = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1312,12 +1314,12 @@ ret:
|
||||
int cache_setting = m_settings ? settings().disk_io_write_mode : 0;
|
||||
if (cache_setting == session_settings::disable_os_cache
|
||||
|| (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;
|
||||
if (!m_allocate_files) mode |= file::sparse;
|
||||
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
|
||||
|
@ -4142,7 +4142,7 @@ namespace libtorrent
|
||||
for (torrent_info::file_iterator i = m_torrent_file->begin_files()
|
||||
, 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)
|
||||
{
|
||||
std::string p = target.path;
|
||||
if (!verify_encoding(p, true)) target.path = p;
|
||||
std::string p = target.filename();
|
||||
if (!verify_encoding(p, true)) target.set_name(p.c_str());
|
||||
}
|
||||
|
||||
// TODO: should this take a char const*?
|
||||
@ -233,18 +233,17 @@ namespace libtorrent
|
||||
}
|
||||
|
||||
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;
|
||||
lazy_entry const* length = dict.dict_find("length");
|
||||
if (length == 0 || length->type() != lazy_entry::int_t)
|
||||
return false;
|
||||
target.size = length->int_value();
|
||||
target.path = root_dir;
|
||||
target.file_base = 0;
|
||||
|
||||
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
|
||||
// because if it exists, it is more
|
||||
@ -256,21 +255,25 @@ namespace libtorrent
|
||||
if (p == 0 || p->type() != lazy_entry::list_t)
|
||||
return false;
|
||||
|
||||
std::string path = root_dir;
|
||||
for (int i = 0, end(p->list_size()); i < end; ++i)
|
||||
{
|
||||
if (p->list_at(i)->type() != lazy_entry::string_t)
|
||||
return false;
|
||||
std::string path_element = p->list_at(i)->string_value();
|
||||
if (i == end - 1) *filename = p->list_at(i);
|
||||
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);
|
||||
|
||||
// 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.set_name(path.c_str());
|
||||
|
||||
lazy_entry const* attr = dict.dict_find_string("attr");
|
||||
if (attr)
|
||||
{
|
||||
@ -288,11 +291,7 @@ namespace libtorrent
|
||||
|
||||
lazy_entry const* fh = dict.dict_find_string("sha1");
|
||||
if (fh && fh->string_length() == 20 && filehash)
|
||||
{
|
||||
std::memcpy(&(*filehash)[0], fh->string_ptr(), 20);
|
||||
// indicate that the file has a filehash
|
||||
target.filehash_index = 0;
|
||||
}
|
||||
*filehash = fh;
|
||||
|
||||
lazy_entry const* s_p = dict.dict_find("symlink path");
|
||||
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
|
||||
, std::string const& root_dir)
|
||||
, std::string const& root_dir, ptrdiff_t info_ptr_diff)
|
||||
{
|
||||
if (list.type() != lazy_entry::list_t) return false;
|
||||
target.reserve(list.list_size());
|
||||
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;
|
||||
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;
|
||||
|
||||
// TODO: this logic should be a separate step
|
||||
@ -352,15 +354,31 @@ namespace libtorrent
|
||||
|
||||
// as long as this file already exists
|
||||
// increase the counter
|
||||
while (!files.insert(e.path).second)
|
||||
std::string path = e.filename();
|
||||
while (!files.insert(path).second)
|
||||
{
|
||||
++cnt;
|
||||
char suffix[50];
|
||||
snprintf(suffix, sizeof(suffix), ".%d%s", cnt, extension(e.path).c_str());
|
||||
replace_extension(e.path, suffix);
|
||||
snprintf(suffix, sizeof(suffix), ".%d%s", cnt, extension(path).c_str());
|
||||
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;
|
||||
}
|
||||
@ -748,6 +766,11 @@ namespace libtorrent
|
||||
TORRENT_ASSERT(section.first[0] == 'd');
|
||||
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
|
||||
int piece_length = info.dict_find_int_value("piece length", -1);
|
||||
if (piece_length <= 0)
|
||||
@ -784,12 +807,12 @@ namespace libtorrent
|
||||
// if there's no list of files, there has to be a length
|
||||
// field.
|
||||
file_entry e;
|
||||
e.path = name;
|
||||
e.set_name(name.c_str());
|
||||
e.offset = 0;
|
||||
e.size = info.dict_find_int_value("length", -1);
|
||||
size_type ts = info.dict_find_int_value("mtime", -1);
|
||||
if (ts >= 0)
|
||||
e.mtime = std::time_t(ts);
|
||||
time_t mtime = 0;
|
||||
if (ts > 0) mtime = std::time_t(ts);
|
||||
lazy_entry const* attr = info.dict_find_string("attr");
|
||||
if (attr)
|
||||
{
|
||||
@ -818,29 +841,23 @@ namespace libtorrent
|
||||
e.symlink_index = 0;
|
||||
}
|
||||
lazy_entry const* fh = info.dict_find_string("sha1");
|
||||
sha1_hash filehash;
|
||||
if (fh && fh->string_length() == 20)
|
||||
{
|
||||
std::memcpy(&filehash[0], fh->string_ptr(), 20);
|
||||
e.filehash_index = 0;
|
||||
}
|
||||
if (fh && fh->string_length() != 20) fh = 0;
|
||||
|
||||
// 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;
|
||||
if (e.size < 0)
|
||||
{
|
||||
ec = errors::torrent_invalid_length;
|
||||
return false;
|
||||
}
|
||||
bool omit_hash = (flags & torrent_info::omit_filehashes) || e.filehash_index == -1;
|
||||
m_files.add_file(e, omit_hash ? 0 : &filehash
|
||||
, e.symlink_index != -1 ? &symlink : 0);
|
||||
m_files.add_file(e, fh ? fh->string_ptr() + info_ptr_diff : 0
|
||||
, e.symlink_index != -1 ? &symlink : 0, mtime);
|
||||
m_multifile = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!extract_files(*i, m_files, name))
|
||||
if (!extract_files(*i, m_files, name, info_ptr_diff))
|
||||
{
|
||||
ec = errors::torrent_file_parse_failed;
|
||||
return false;
|
||||
@ -873,7 +890,7 @@ namespace libtorrent
|
||||
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() + m_info_section_size);
|
||||
}
|
||||
@ -1204,7 +1221,7 @@ namespace libtorrent
|
||||
os << "piece length: " << piece_length() << "\n";
|
||||
os << "files:\n";
|
||||
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 -------
|
||||
|
@ -210,7 +210,7 @@ namespace libtorrent
|
||||
if (using_proxy)
|
||||
{
|
||||
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
|
||||
convert_path_to_posix(path);
|
||||
#endif
|
||||
@ -219,7 +219,7 @@ namespace libtorrent
|
||||
else
|
||||
{
|
||||
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
|
||||
convert_path_to_posix(path);
|
||||
#endif
|
||||
@ -421,7 +421,7 @@ namespace libtorrent
|
||||
int file_index = m_file_requests.front();
|
||||
|
||||
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
|
||||
convert_path_to_posix(path);
|
||||
#endif
|
||||
|
@ -804,7 +804,7 @@ void run_test(std::string const& test_path, bool unbuffered)
|
||||
file_storage fs;
|
||||
fs.add_file("temp_storage/test1.tmp", 3 * piece_size);
|
||||
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(1, hasher(piece1, 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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -256,10 +257,11 @@ int run_suite(char const* protocol, bool test_url_seed, bool chunked_encoding)
|
||||
// verify that the file hashes are correct
|
||||
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).filehash_index);
|
||||
sha1_hash h2 = file_hash(combine_path("./tmp1_web_seed", torrent_file->file_at(i).path));
|
||||
fprintf(stderr, "%s: %s == %s\n", torrent_file->file_at(i).path.c_str()
|
||||
sha1_hash h1 = torrent_file->files().hash(torrent_file->file_at(i));
|
||||
sha1_hash h2 = file_hash(combine_path("./tmp1_web_seed"
|
||||
, torrent_file->files().file_path(torrent_file->file_at(i))));
|
||||
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());
|
||||
TEST_EQUAL(h1, h2);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user