From 2e69366b02a8f0dfc45416506fd1813009260638 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 29 Nov 2010 05:44:29 +0000 Subject: [PATCH] reverted part of the file_storage API to match the previous one more closly --- bindings/python/src/create_torrent.cpp | 24 +++--- bindings/python/src/torrent_info.cpp | 14 ++-- docs/make_torrent.rst | 44 +++++------ docs/manual.rst | 27 ++++--- include/libtorrent/file_pool.hpp | 6 +- include/libtorrent/file_storage.hpp | 90 +++++++++++++++------- include/libtorrent/torrent_info.hpp | 2 +- src/create_torrent.cpp | 28 +++---- src/file_pool.cpp | 10 +-- src/file_storage.cpp | 101 +++++++++++++++---------- src/storage.cpp | 26 ++++--- src/torrent_info.cpp | 49 ++++-------- test/test_web_seed.cpp | 6 +- 13 files changed, 232 insertions(+), 195 deletions(-) diff --git a/bindings/python/src/create_torrent.cpp b/bindings/python/src/create_torrent.cpp index 048b633c4..e522c999a 100644 --- a/bindings/python/src/create_torrent.cpp +++ b/bindings/python/src/create_torrent.cpp @@ -48,11 +48,9 @@ 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) + void add_file(file_storage& ct, file_entry const& fe) { - ct.add_file(fe, hash.empty() ? 0 : hash.c_str() - , linkpath.empty() ? 0 : &linkpath); + ct.add_file(fe); } } @@ -73,21 +71,23 @@ void bind_create_torrent() #endif void (*add_files0)(file_storage&, std::string const&, boost::uint32_t) = add_files; + file_entry (file_storage::*at)(int) const = &file_storage::at; + class_("file_storage") .def("is_valid", &file_storage::is_valid) - .def("add_file", add_file, (arg("entry"), arg("hash") = std::string(), arg("symlink") = std::string())) + .def("add_file", add_file, arg("entry")) .def("add_file", add_file0, (arg("path"), arg("size"), arg("flags") = 0, arg("mtime") = 0, arg("linkpath") = "")) #if TORRENT_USE_WSTRING .def("add_file", add_file1, (arg("path"), arg("size"), arg("flags") = 0, arg("mtime") = 0, arg("linkpath") = "")) #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("at", at) +// .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 64439b37c..ee56f6ec0 100644 --- a/bindings/python/src/torrent_info.cpp +++ b/bindings/python/src/torrent_info.cpp @@ -55,10 +55,10 @@ namespace list files(torrent_info const& ti, bool storage) { list result; - typedef std::vector list_type; + typedef torrent_info::file_iterator iter; - for (list_type::const_iterator i = ti.begin_files(); i != ti.end_files(); ++i) - result.append(*i); + for (iter i = ti.begin_files(); i != ti.end_files(); ++i) + result.append(ti.files().at(i)); return result; } @@ -160,7 +160,7 @@ void bind_torrent_info() .def("piece_size", &torrent_info::piece_size) .def("num_files", &torrent_info::num_files, (arg("storage")=false)) - .def("file_at", &torrent_info::file_at, return_internal_reference<>()) + .def("file_at", &torrent_info::file_at) .def("file_at_offset", &torrent_info::file_at_offset) .def("files", &files, (arg("storage")=false)) .def("rename_file", rename_file0) @@ -182,8 +182,10 @@ void bind_torrent_info() ; class_("file_entry") - .def("filename", &file_entry::filename) - .def("set_name", &file_entry::set_name) + .def_readwrite("path", &file_entry::path) + .def_readwrite("symlink_path", &file_entry::symlink_path) + .def_readwrite("filehash", &file_entry::filehash) + .def_readwrite("mtime", &file_entry::mtime) .add_property("pad_file", &get_pad_file) .add_property("executable_attribute", &get_executable_attribute) .add_property("hidden_attribute", &get_hidden_attribute) diff --git a/docs/make_torrent.rst b/docs/make_torrent.rst index 9ff28d8c5..76c36e1f8 100644 --- a/docs/make_torrent.rst +++ b/docs/make_torrent.rst @@ -173,12 +173,12 @@ file structure. Its synopsis:: int piece_length() const; int piece_size(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); + sha1_hash const& hash(internal_file_entry const& fe) const; + std::string const& symlink(internal_file_entry const& fe) const; + time_t mtime(internal_file_entry const& fe) const; + int file_index(internal_file_entry const& fe) const; + size_type file_base(internal_file_entry const& fe) const; + void set_file_base(internal_file_entry const& fe, size_type off); void set_name(std::string const& n); void set_name(std::wstring const& n); @@ -193,8 +193,8 @@ add_file() :: void add_file(file_entry const& e); - void add_file(fs::path const& p, size_type size, int flags = 0); - void add_file(fs::wpath const& p, size_type size, int flags = 0); + void add_file(std::string const& p, size_type size, int flags = 0); + void add_file(std::wstring const& p, size_type size, int flags = 0); Adds a file to the file storage. The ``flags`` argument sets attributes on the file. The file attributes is an extension and may not work in all bittorrent clients. @@ -204,17 +204,8 @@ The possible arreibutes are:: attribute_hidden attribute_executable -add_file --------- - - :: - - void add_file(file_entry const& e); - void add_file(fs::path const& p, size_type size); - -Adds a file to the file storage. If more files than one are added, -certain restrictions to their paths apply. In a multi-file file -storage (torrent), all files must share the same root directory. +If more files than one are added, certain restrictions to their paths apply. +In a multi-file file storage (torrent), all files must share the same root directory. That is, the first path element of all files must be the same. This shared path element is also set to the name of the torrent. It @@ -228,13 +219,14 @@ hash() symlink() mtime() file_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; + sha1_hash hash(internal_file_entry const& fe) const; + std::string const& symlink(internal_file_entry const& fe) const; + time_t mtime(internal_file_entry const& fe) const; + int file_index(internal_file_entry const& fe) const; These functions are used to query the symlink, file hash, -modification time and the file-index from a ``file_entry``. +modification time and the file-index from a ``internal_file_entry``, +which typically would be acquired from an iterator. For these functions to function, the file entry must be an actual object from this same ``file_storage`` object. It may @@ -255,8 +247,8 @@ 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); + size_type file_base(internal_file_entry const& fe) const; + void set_file_base(internal_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 diff --git a/docs/manual.rst b/docs/manual.rst index b35afa729..ff8c6676a 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -1546,28 +1546,29 @@ begin_files() end_files() rbegin_files() rend_files() This class will need some explanation. First of all, to get a list of all files in the torrent, you can use ``begin_files()``, ``end_files()``, ``rbegin_files()`` and ``rend_files()``. These will give you standard vector -iterators with the type ``file_entry``. +iterators with the type ``internal_file_entry``, which is an internal type. + +You can resolve it into the public representation of a file (``file_entry``) +using the ``file_storage::at`` function, which takes an index and an iterator; :: struct file_entry { - std::string filename(); + std::string path; size_type offset; size_type size; size_type file_base; time_t mtime; - int symlink_index; - int filehash_index; + sha1_hash filehash; bool pad_file:1; bool hidden_attribute:1; bool executable_attribute:1; bool symlink_attribute:1; }; -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. +The ``path`` is the full path of this file. The paths 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 @@ -1582,14 +1583,12 @@ file. ``mtime`` is the modification time of this file specified in posix time. -``symlink_index`` is an index into an array of paths in ``file_storage``, or --1 if this file is not a symlink. This field is only used if the ``symlink_attribute`` -is set. To resolve the symlink, call ``file_storage::symlink(e.symlink_index)``. +``symlink_path`` is the path which this is a symlink to, or empty if this is +not a symlink. This field is only used if the ``symlink_attribute`` is set. -``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`` is a sha-1 hash of the content of the file, or zeroes, if no +file hash was present in the torrent file. It can be used to potentially +find alternative sources for the file. ``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/include/libtorrent/file_pool.hpp b/include/libtorrent/file_pool.hpp index ddb673cd4..f0a98425a 100644 --- a/include/libtorrent/file_pool.hpp +++ b/include/libtorrent/file_pool.hpp @@ -47,18 +47,16 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/file.hpp" #include "libtorrent/ptime.hpp" #include "libtorrent/thread.hpp" +#include "libtorrent/file_storage.hpp" 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, file_storage const& fs, int m, error_code& ec); + , file_storage::iterator fe, file_storage const& fs, int m, error_code& ec); void release(void* st); void release(void* st, int file_index); void resize(int size); diff --git a/include/libtorrent/file_storage.hpp b/include/libtorrent/file_storage.hpp index f42c1b20a..da50fa07a 100644 --- a/include/libtorrent/file_storage.hpp +++ b/include/libtorrent/file_storage.hpp @@ -47,9 +47,37 @@ namespace libtorrent struct file; struct TORRENT_EXPORT file_entry + { + file_entry(): offset(0), size(0), file_base(0) + , mtime(0), pad_file(false), hidden_attribute(false) + , executable_attribute(false) + , symlink_attribute(false) + {} + + std::string path; + size_type offset; // the offset of this file inside the torrent + size_type size; // the size of this file + // the offset in the file where the storage starts. + // This is always 0 unless parts of the torrent is + // compressed into a single file, such as a so-called part file. + size_type file_base; + std::time_t mtime; + sha1_hash filehash; + bool pad_file:1; + bool hidden_attribute:1; + bool executable_attribute:1; + bool symlink_attribute:1; + std::string symlink_path; + }; + + // this is used internally to hold the file entry + // it's smaller and optimized for smaller memory + // footprint, as opposed to file_entry, which is + // optimized for convenience + struct internal_file_entry { friend class file_storage; - file_entry() + internal_file_entry() : name(0) , offset(0) , symlink_index(-1) @@ -62,10 +90,25 @@ namespace libtorrent , path_index(-1) {} - file_entry(file_entry const& fe); - file_entry& operator=(file_entry const& fe); + internal_file_entry(file_entry const& e) + : name(0) + , offset(e.offset) + , symlink_index(-1) + , size(e.size) + , name_len(0) + , pad_file(e.pad_file) + , hidden_attribute(e.hidden_attribute) + , executable_attribute(e.executable_attribute) + , symlink_attribute(e.symlink_attribute) + , path_index(-1) + { + set_name(e.path.c_str()); + } - ~file_entry(); + internal_file_entry(internal_file_entry const& fe); + internal_file_entry& operator=(internal_file_entry const& fe); + + ~internal_file_entry(); void set_name(char const* n, int borrow_chars = 0); std::string filename() const; @@ -129,8 +172,7 @@ namespace libtorrent void reserve(int num_files); - void add_file(file_entry const& e, char const* filehash = 0 - , std::string const* symlink = 0, time_t mtime = 0); + void add_file(file_entry const& e, char const* filehash = 0); void add_file(std::string const& p, size_type size, int flags = 0 , std::time_t mtime = 0, std::string const& s_p = ""); @@ -148,8 +190,8 @@ namespace libtorrent , int size) const; peer_request map_file(int file, size_type offset, int size) const; - typedef std::vector::const_iterator iterator; - typedef std::vector::const_reverse_iterator reverse_iterator; + typedef std::vector::const_iterator iterator; + typedef std::vector::const_reverse_iterator reverse_iterator; iterator file_at_offset(size_type offset) const; iterator begin() const { return m_files.begin(); } @@ -159,20 +201,8 @@ namespace libtorrent int num_files() const { return int(m_files.size()); } - file_entry const& at(int index) const - { - TORRENT_ASSERT(index >= 0 && index < int(m_files.size())); - return m_files[index]; - } - - 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; + file_entry at(int index) const; + file_entry at(iterator i) const; size_type total_size() const { return m_total_size; } void set_num_pieces(int n) { m_num_pieces = n; } @@ -199,13 +229,21 @@ namespace libtorrent // not add any padding void optimize(int pad_file_limit = -1); + sha1_hash hash(internal_file_entry const& fe) const; + std::string const& symlink(internal_file_entry const& fe) const; + time_t mtime(internal_file_entry const& fe) const; + int file_index(internal_file_entry const& fe) const; + size_type file_base(internal_file_entry const& fe) const; + void set_file_base(internal_file_entry const& fe, size_type off); + std::string file_path(internal_file_entry const& fe) const; + private: - void update_path_index(file_entry& e); + void update_path_index(internal_file_entry& e); void reorder_file(int index, int dst); // the list of files that this torrent consists of - std::vector m_files; + std::vector m_files; // if there are sha1 hashes for each individual file // there are as many entries in this array as the @@ -216,7 +254,7 @@ namespace libtorrent std::vector m_file_hashes; // for files that are symlinks, the symlink - // path_index in the file_entry indexes + // path_index in the internal_file_entry indexes // this vector of strings std::vector m_symlinks; @@ -231,7 +269,7 @@ namespace libtorrent // offsets) std::vector m_file_base; - // all unique paths files have. The file_entry::path_index + // all unique paths files have. The internal_file_entry::path_index // points into this array std::vector m_paths; diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index 1075aad1e..7273f2508 100644 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -302,7 +302,7 @@ namespace libtorrent reverse_file_iterator rbegin_files() const { return m_files.rbegin(); } reverse_file_iterator rend_files() const { return m_files.rend(); } int num_files() const { return m_files.num_files(); } - file_entry const& file_at(int index) const { return m_files.at(index); } + file_entry file_at(int index) const { return m_files.at(index); } file_iterator file_at_offset(size_type offset) const { return m_files.file_at_offset(offset); } diff --git a/src/create_torrent.cpp b/src/create_torrent.cpp index 93b816f92..a70ce8bdf 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.file_path(m_files.at(0)))) m_multifile = true; + if (!m_multifile && has_parent_path(m_files.file_path(*m_files.begin()))) m_multifile = true; // a piece_size of 0 means automatic if (piece_size == 0 && !m_merkle_torrent) @@ -301,26 +301,26 @@ namespace libtorrent if (!m_multifile) { - 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 - || m_files.at(0).executable_attribute - || m_files.at(0).symlink_attribute) + file_entry e = m_files.at(0); + if (m_include_mtime) info["mtime"] = e.mtime; + info["length"] = e.size; + if (e.pad_file + || e.hidden_attribute + || e.executable_attribute + || e.symlink_attribute) { std::string& attr = info["attr"].string(); - if (m_files.at(0).pad_file) attr += 'p'; - if (m_files.at(0).hidden_attribute) attr += 'h'; - if (m_files.at(0).executable_attribute) attr += 'x'; - if (m_include_symlinks && m_files.at(0).symlink_attribute) attr += 'l'; + if (e.pad_file) attr += 'p'; + if (e.hidden_attribute) attr += 'h'; + if (e.executable_attribute) attr += 'x'; + if (m_include_symlinks && e.symlink_attribute) attr += 'l'; } if (m_include_symlinks - && m_files.at(0).symlink_attribute - && m_files.at(0).symlink_index != -1) + && e.symlink_attribute) { entry& sympath_e = info["symlink path"]; - std::string split = split_path(m_files.symlink(m_files.at(0))); + std::string split = split_path(e.symlink_path); 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 1cf2ad589..f540c3a89 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, file_storage const& fs, int m, error_code& ec) + , file_storage::iterator 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, fs.file_index(fe))); + 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, fs.file_path(fe)); + 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, fs.file_path(fe)); + 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, fs.file_index(fe)), 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; } diff --git a/src/file_storage.cpp b/src/file_storage.cpp index 2520f1d30..f2f08e90f 100644 --- a/src/file_storage.cpp +++ b/src/file_storage.cpp @@ -67,7 +67,7 @@ namespace libtorrent return piece_length(); } - void file_storage::update_path_index(file_entry& e) + void file_storage::update_path_index(internal_file_entry& e) { std::string parent = parent_path(e.filename()); if (parent.empty()) @@ -95,9 +95,9 @@ namespace libtorrent } } - file_entry::~file_entry() { if (name_len == 0) free((void*)name); } + internal_file_entry::~internal_file_entry() { if (name_len == 0) free((void*)name); } - file_entry::file_entry(file_entry const& fe) + internal_file_entry::internal_file_entry(internal_file_entry const& fe) : name(0) , offset(fe.offset) , symlink_index(fe.symlink_index) @@ -112,7 +112,7 @@ namespace libtorrent set_name(fe.name, fe.name_len); } - file_entry& file_entry::operator=(file_entry const& fe) + internal_file_entry& internal_file_entry::operator=(internal_file_entry const& fe) { offset = fe.offset; size = fe.size; @@ -126,7 +126,7 @@ namespace libtorrent return *this; } - void file_entry::set_name(char const* n, int borrow_chars) + void internal_file_entry::set_name(char const* n, int borrow_chars) { TORRENT_ASSERT(borrow_chars >= 0); if (borrow_chars > 1023) borrow_chars = 1023; @@ -143,7 +143,7 @@ namespace libtorrent name_len = borrow_chars; } - std::string file_entry::filename() const + std::string internal_file_entry::filename() const { if (name_len) return std::string(name, name_len); return name ? name : ""; @@ -184,7 +184,7 @@ namespace libtorrent namespace { - bool compare_file_offset(file_entry const& lhs, file_entry const& rhs) + bool compare_file_offset(internal_file_entry const& lhs, internal_file_entry const& rhs) { return lhs.offset < rhs.offset; } @@ -193,11 +193,11 @@ namespace libtorrent file_storage::iterator file_storage::file_at_offset(size_type offset) const { // find the file iterator and file offset - file_entry target; + internal_file_entry target; target.offset = offset; TORRENT_ASSERT(!compare_file_offset(target, m_files.front())); - std::vector::const_iterator file_iter = std::upper_bound( + std::vector::const_iterator file_iter = std::upper_bound( begin(), end(), target, compare_file_offset); TORRENT_ASSERT(file_iter != begin()); @@ -214,12 +214,12 @@ namespace libtorrent if (m_files.empty()) return ret; // find the file iterator and file offset - file_entry target; + internal_file_entry target; target.offset = piece * (size_type)m_piece_length + offset; TORRENT_ASSERT(target.offset + size <= m_total_size); TORRENT_ASSERT(!compare_file_offset(target, m_files.front())); - std::vector::const_iterator file_iter = std::upper_bound( + std::vector::const_iterator file_iter = std::upper_bound( begin(), end(), target, compare_file_offset); TORRENT_ASSERT(file_iter != begin()); @@ -244,8 +244,30 @@ namespace libtorrent } return ret; } - - std::string file_storage::file_path(file_entry const& fe) const + + file_entry file_storage::at(file_storage::iterator i) const + { return at(i - begin()); } + + file_entry file_storage::at(int index) const + { + TORRENT_ASSERT(index >= 0 && index < int(m_files.size())); + file_entry ret; + internal_file_entry const& ife = m_files[index]; + ret.path = file_path(ife); + ret.offset = ife.offset; + ret.size = ife.size; + ret.file_base = file_base(ife); + ret.mtime = mtime(ife); + ret.pad_file = ife.pad_file; + ret.hidden_attribute = ife.hidden_attribute; + ret.executable_attribute = ife.executable_attribute; + ret.symlink_attribute = ife.symlink_attribute; + if (ife.symlink_index >= 0) ret.symlink_path = symlink(ife); + ret.filehash = hash(ife); + return ret; + } + + std::string file_storage::file_path(internal_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(); @@ -285,8 +307,8 @@ namespace libtorrent m_name = split_path(file).c_str(); } TORRENT_ASSERT(m_name == split_path(file).c_str()); - m_files.push_back(file_entry()); - file_entry& e = m_files.back(); + m_files.push_back(internal_file_entry()); + internal_file_entry& e = m_files.back(); e.set_name(file.c_str()); e.size = size; e.offset = m_total_size; @@ -309,25 +331,25 @@ namespace libtorrent m_total_size += size; } - void file_storage::add_file(file_entry const& ent, char const* filehash - , std::string const* symlink, time_t mtime) + void file_storage::add_file(file_entry const& ent, char const* filehash) { - if (!has_parent_path(ent.filename())) + if (!has_parent_path(ent.path)) { // you have already added at least one file with a // path to the file (branch_path), which means that // all the other files need to be in the same top // directory as the first file. TORRENT_ASSERT(m_files.empty()); - m_name = ent.filename(); + m_name = ent.path; } else { if (m_files.empty()) - m_name = split_path(ent.filename()).c_str(); + m_name = split_path(ent.path).c_str(); } - m_files.push_back(ent); - file_entry& e = m_files.back(); + internal_file_entry ife(ent); + m_files.push_back(ife); + internal_file_entry& e = m_files.back(); e.offset = m_total_size; m_total_size += ent.size; if (filehash) @@ -335,47 +357,48 @@ namespace libtorrent 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) + if (!ent.symlink_path.empty()) { e.symlink_index = m_symlinks.size(); - m_symlinks.push_back(*symlink); + m_symlinks.push_back(ent.symlink_path); } - if (mtime) + if (ent.mtime) { if (m_mtime.size() < m_files.size()) m_mtime.resize(m_files.size()); - m_mtime[m_files.size() - 1] = mtime; + m_mtime[m_files.size() - 1] = ent.mtime; } + if (ent.file_base) set_file_base(e, ent.file_base); update_path_index(e); } - sha1_hash file_storage::hash(file_entry const& fe) const + sha1_hash file_storage::hash(internal_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 + std::string const& file_storage::symlink(internal_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 + time_t file_storage::mtime(internal_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 file_storage::file_index(internal_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) + void file_storage::set_file_base(internal_file_entry const& fe, size_type off) { int index = &fe - &m_files[0]; TORRENT_ASSERT(index >= 0 && index < m_files.size()); @@ -383,19 +406,19 @@ namespace libtorrent m_file_base[index] = off; } - size_type file_storage::file_base(file_entry const& fe) const + size_type file_storage::file_base(internal_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) + bool compare_file_entry_size(internal_file_entry const& fe1, internal_file_entry const& fe2) { return fe1.size < fe2.size; } void file_storage::reorder_file(int index, int dst) { - file_entry e = m_files[index]; + internal_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()) @@ -443,7 +466,7 @@ 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() + std::vector::iterator i = std::max_element(m_files.begin(), m_files.end() , &compare_file_entry_size); int index = file_index(*i); @@ -451,7 +474,7 @@ namespace libtorrent size_type off = 0; int padding_file = 0; - for (std::vector::iterator i = m_files.begin(); + for (std::vector::iterator i = m_files.begin(); i != m_files.end(); ++i) { if (pad_file_limit >= 0 @@ -466,8 +489,8 @@ namespace libtorrent int pad_size = alignment - (off & (alignment-1)); // find the largest file that fits in pad_size - std::vector::iterator best_match = m_files.end(); - for (std::vector::iterator j = i+1; j < m_files.end(); ++j) + std::vector::iterator best_match = m_files.end(); + for (std::vector::iterator j = i+1; j < m_files.end(); ++j) { if (j->size > pad_size) continue; if (best_match == m_files.end() || j->size > best_match->size) @@ -488,7 +511,7 @@ namespace libtorrent // we could not find a file that fits in pad_size // add a padding file - file_entry e; + internal_file_entry e; i = m_files.insert(i, e); i->size = pad_size; i->offset = off; diff --git a/src/storage.cpp b/src/storage.cpp index 140269dbe..321e031d1 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -409,7 +409,8 @@ namespace libtorrent file_storage const& m_files; // helper function to open a file in the file pool with the right mode - boost::intrusive_ptr open_file(file_entry const& fe, int mode, error_code& ec) const; + boost::intrusive_ptr open_file(file_storage::iterator fe, int mode + , error_code& ec) const; std::vector m_file_priority; std::string m_save_path; @@ -553,7 +554,7 @@ namespace libtorrent if (ec || s.file_size > file_iter->size || file_iter->size == 0) { ec.clear(); - boost::intrusive_ptr f = open_file(*file_iter, file::read_write, ec); + boost::intrusive_ptr f = open_file(file_iter, file::read_write, ec); if (ec) set_error(file_path, ec); else if (f) { @@ -577,7 +578,7 @@ namespace libtorrent if (index < 0 || index >= m_files.num_files()) return; error_code ec; - boost::intrusive_ptr f = open_file(files().at(index), file::read_write, ec); + boost::intrusive_ptr f = open_file(files().begin() + index, file::read_write, ec); if (ec || !f) return; f->finalize(); @@ -702,7 +703,7 @@ namespace libtorrent TORRENT_ASSERT(slot < m_files.num_pieces()); size_type file_offset = (size_type)slot * m_files.piece_length(); - std::vector::const_iterator file_iter; + file_storage::iterator file_iter; for (file_iter = files().begin();;) { @@ -715,7 +716,7 @@ namespace libtorrent } error_code ec; - boost::intrusive_ptr file_handle = open_file(*file_iter, file::read_only, ec); + boost::intrusive_ptr file_handle = open_file(file_iter, file::read_only, ec); if (!file_handle || ec) return slot; size_type data_start = file_handle->sparse_end(file_offset); @@ -1057,7 +1058,7 @@ ret: // open the file read only to avoid re-opening // it in case it's already opened in read-only mode error_code ec; - boost::intrusive_ptr f = open_file(*file_iter, file::read_only, ec); + boost::intrusive_ptr f = open_file(file_iter, file::read_only, ec); size_type ret = 0; if (f && !ec) ret = f->phys_offset(file_offset); @@ -1130,7 +1131,7 @@ ret: // find the file iterator and file offset size_type file_offset = start; - std::vector::const_iterator file_iter; + file_storage::iterator file_iter; for (file_iter = files().begin();;) { @@ -1179,8 +1180,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) - == &*file_iter); + TORRENT_ASSERT((files().begin() + slices[counter].file_index) + == file_iter); ++counter; #endif @@ -1199,7 +1200,7 @@ ret: } error_code ec; - file_handle = open_file(*file_iter, op.mode, ec); + file_handle = open_file(file_iter, op.mode, ec); if (!file_handle || ec) { std::string path = combine_path(m_save_path, files().file_path(*file_iter)); @@ -1309,12 +1310,13 @@ ret: return readv(&b, slot, offset, 1); } - boost::intrusive_ptr storage::open_file(file_entry const& fe, int mode, error_code& ec) const + boost::intrusive_ptr storage::open_file(file_storage::iterator fe, int mode + , error_code& ec) const { 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 + files().file_base(fe)) & (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; diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index a23f7e180..173a62d03 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -182,12 +182,6 @@ namespace libtorrent return valid_encoding; } - void verify_encoding(file_entry& target) - { - std::string p = target.filename(); - if (!verify_encoding(p, true)) target.set_name(p.c_str()); - } - // TODO: should this take a char const*? bool valid_path_element(std::string const& element) { @@ -233,7 +227,7 @@ namespace libtorrent } bool extract_single_file(lazy_entry const& dict, file_entry& target - , std::string const& root_dir, lazy_entry const** filehash, std::string* symlink + , std::string const& root_dir, lazy_entry const** filehash , lazy_entry const** filename, time_t* mtime) { if (dict.type() != lazy_entry::dict_t) return false; @@ -266,13 +260,13 @@ namespace libtorrent path = combine_path(path, path_element); } path = sanitize_path(path); - verify_encoding(target); + verify_encoding(path, true); // bitcomet pad file if (path.find("_____padding_file_") != std::string::npos) target.pad_file = true; - target.set_name(path.c_str()); + target.path = path; lazy_entry const* attr = dict.dict_find_string("attr"); if (attr) @@ -300,10 +294,8 @@ namespace libtorrent { std::string path_element = s_p->list_at(i)->string_value(); trim_path_element(path_element); - *symlink = combine_path(*symlink, path_element); + target.symlink_path = combine_path(target.symlink_path, path_element); } - // indeicate that we have a symlink - target.symlink_index = 0; } return true; @@ -339,11 +331,10 @@ namespace libtorrent { lazy_entry const* file_hash = 0; time_t mtime = 0; - std::string symlink; file_entry e; lazy_entry const* fee = 0; if (!extract_single_file(*list.list_at(i), e, root_dir - , &file_hash, &symlink, &fee, &mtime)) + , &file_hash, &fee, &mtime)) return false; // TODO: this logic should be a separate step @@ -354,22 +345,19 @@ namespace libtorrent // as long as this file already exists // increase the counter - std::string path = e.filename(); - while (!files.insert(path).second) + while (!files.insert(e.path).second) { ++cnt; char suffix[50]; - snprintf(suffix, sizeof(suffix), ".%d%s", cnt, extension(path).c_str()); - replace_extension(path, suffix); + snprintf(suffix, sizeof(suffix), ".%d%s", cnt, extension(e.path).c_str()); + replace_extension(e.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); + target.add_file(e, file_hash ? file_hash->string_ptr() + info_ptr_diff : 0); // 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); + internal_file_entry const& fe = *target.rbegin(); // TODO: once the filename renaming is removed from here // this check can be removed as well if (fee && fe.filename() == fee->string_value()) @@ -377,7 +365,7 @@ namespace libtorrent // 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()); + const_cast(fe).set_name(str_ptr, fee->string_length()); } } return true; @@ -807,12 +795,10 @@ namespace libtorrent // if there's no list of files, there has to be a length // field. file_entry e; - e.set_name(name.c_str()); + e.path = name; e.offset = 0; e.size = info.dict_find_int_value("length", -1); - size_type ts = info.dict_find_int_value("mtime", -1); - time_t mtime = 0; - if (ts > 0) mtime = std::time_t(ts); + e.mtime = info.dict_find_int_value("mtime", 0); lazy_entry const* attr = info.dict_find_string("attr"); if (attr) { @@ -829,30 +815,27 @@ namespace libtorrent } lazy_entry const* s_p = info.dict_find("symlink path"); - std::string symlink; if (s_p != 0 && s_p->type() == lazy_entry::list_t) { for (int i = 0, end(s_p->list_size()); i < end; ++i) { std::string path_element = s_p->list_at(i)->string_value(); trim_path_element(path_element); - symlink = combine_path(symlink, path_element); + e.symlink_path = combine_path(e.symlink_path, path_element); } - e.symlink_index = 0; } lazy_entry const* fh = info.dict_find_string("sha1"); if (fh && fh->string_length() != 20) fh = 0; // bitcomet pad file - if (e.filename().find("_____padding_file_") != std::string::npos) + if (e.path.find("_____padding_file_") != std::string::npos) e.pad_file = true; if (e.size < 0) { ec = errors::torrent_invalid_length; return false; } - m_files.add_file(e, fh ? fh->string_ptr() + info_ptr_diff : 0 - , e.symlink_index != -1 ? &symlink : 0, mtime); + m_files.add_file(e, fh ? fh->string_ptr() + info_ptr_diff : 0); m_multifile = false; } else diff --git a/test/test_web_seed.cpp b/test/test_web_seed.cpp index 4fece66ae..6e776720e 100644 --- a/test/test_web_seed.cpp +++ b/test/test_web_seed.cpp @@ -257,11 +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) { - sha1_hash h1 = torrent_file->files().hash(torrent_file->file_at(i)); + sha1_hash h1 = torrent_file->file_at(i).filehash; sha1_hash h2 = file_hash(combine_path("./tmp1_web_seed" - , torrent_file->files().file_path(torrent_file->file_at(i)))); + , torrent_file->file_at(i).path)); fprintf(stderr, "%s: %s == %s\n" - , torrent_file->files().file_path(torrent_file->file_at(i)).c_str() + , torrent_file->file_at(i).path.c_str() , to_hex(h1.to_string()).c_str(), to_hex(h2.to_string()).c_str()); TEST_EQUAL(h1, h2); }