diff --git a/ChangeLog b/ChangeLog index 73cf537c3..4c230d948 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/bindings/python/src/create_torrent.cpp b/bindings/python/src/create_torrent.cpp index 9938b28a8..048b633c4 100644 --- a/bindings/python/src/create_torrent.cpp +++ b/bindings/python/src/create_torrent.cpp @@ -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) diff --git a/bindings/python/src/torrent_info.cpp b/bindings/python/src/torrent_info.cpp index bbca0a214..64439b37c 100644 --- a/bindings/python/src/torrent_info.cpp +++ b/bindings/python/src/torrent_info.cpp @@ -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") - .add_property("path" - , make_getter( - &file_entry::path, return_value_policy() - ) - ) - .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", init()) diff --git a/docs/make_torrent.rst b/docs/make_torrent.rst index 68549d6ae..b622fa4fa 100644 --- a/docs/make_torrent.rst +++ b/docs/make_torrent.rst @@ -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 ============== diff --git a/docs/manual.rst b/docs/manual.rst index 61005ad7c..2c251366c 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -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 diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 18b929d5e..2e8737eeb 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -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; } diff --git a/examples/dump_torrent.cpp b/examples/dump_torrent.cpp index ceba6e02d..ccc3e2aa5 100644 --- a/examples/dump_torrent.cpp +++ b/examples/dump_torrent.cpp @@ -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().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; diff --git a/examples/fragmentation_test.cpp b/examples/fragmentation_test.cpp index 56c60f14f..73ca35d3b 100644 --- a/examples/fragmentation_test.cpp +++ b/examples/fragmentation_test.cpp @@ -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; } diff --git a/include/libtorrent/file_pool.hpp b/include/libtorrent/file_pool.hpp index 84ba43aef..ddb673cd4 100644 --- a/include/libtorrent/file_pool.hpp +++ b/include/libtorrent/file_pool.hpp @@ -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 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; } diff --git a/include/libtorrent/file_storage.hpp b/include/libtorrent/file_storage.hpp index 9af262126..f42c1b20a 100644 --- a/include/libtorrent/file_storage.hpp +++ b/include/libtorrent/file_storage.hpp @@ -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 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 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 m_file_hashes; // for files that are symlinks, the symlink // path_index in the file_entry indexes // this vector of strings std::vector 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 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 m_file_base; + + // all unique paths files have. The file_entry::path_index + // points into this array + std::vector m_paths; + // name of torrent. For multi-file torrents // this is always the root directory std::string m_name; diff --git a/include/libtorrent/lazy_entry.hpp b/include/libtorrent/lazy_entry.hpp index f7825a363..bfb6e1cb5 100644 --- a/include/libtorrent/lazy_entry.hpp +++ b/include/libtorrent/lazy_entry.hpp @@ -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&); diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index bf9738adb..1075aad1e 100644 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -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); diff --git a/src/create_torrent.cpp b/src/create_torrent.cpp index dacd4fd95..93b816f92 100644 --- a/src/create_torrent.cpp +++ b/src/create_torrent.cpp @@ -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)); } diff --git a/src/file_pool.cpp b/src/file_pool.cpp index e82a4baf0..1cf2ad589 100644 --- a/src/file_pool.cpp +++ b/src/file_pool.cpp @@ -41,14 +41,14 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { boost::intrusive_ptr 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(); 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); } diff --git a/src/file_storage.cpp b/src/file_storage.cpp index edc3fbf5e..61dd953b8 100644 --- a/src/file_storage.cpp +++ b/src/file_storage.cpp @@ -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::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::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; diff --git a/src/lazy_bdecode.cpp b/src/lazy_bdecode.cpp index aebb0c804..ee0f96fb6 100644 --- a/src/lazy_bdecode.cpp +++ b/src/lazy_bdecode.cpp @@ -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 lazy_entry::data_section() const { typedef std::pair return_t; - return return_t(m_begin, m_end - m_begin); + return return_t(m_begin, m_len); } #if TORRENT_USE_IOSTREAM diff --git a/src/storage.cpp b/src/storage.cpp index faa950725..58307e63f 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -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 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(this), m_save_path, fe, mode, ec); + return m_pool.open_file(const_cast(this), m_save_path, fe, files(), mode, ec); } storage_interface* default_storage_constructor(file_storage const& fs diff --git a/src/torrent.cpp b/src/torrent.cpp index e9ba2e19f..a3f9ec405 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -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)); } } diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 892159ab1..a23f7e180 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -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(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 ------- diff --git a/src/web_peer_connection.cpp b/src/web_peer_connection.cpp index 9e2ee31a5..fe856a906 100644 --- a/src/web_peer_connection.cpp +++ b/src/web_peer_connection.cpp @@ -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 diff --git a/test/test_storage.cpp b/test/test_storage.cpp index 46a857966..68742bea5 100644 --- a/test/test_storage.cpp +++ b/test/test_storage.cpp @@ -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()); diff --git a/test/test_web_seed.cpp b/test/test_web_seed.cpp index 02d2923d9..4fece66ae 100644 --- a/test/test_web_seed.cpp +++ b/test/test_web_seed.cpp @@ -151,7 +151,8 @@ void test_transfer(boost::intrusive_ptr 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); }