reverted part of the file_storage API to match the previous one more closly

This commit is contained in:
Arvid Norberg 2010-11-29 05:44:29 +00:00
parent f82321c1dd
commit 2e69366b02
13 changed files with 232 additions and 195 deletions

View File

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

View File

@ -55,10 +55,10 @@ namespace
list files(torrent_info const& ti, bool storage) {
list result;
typedef std::vector<file_entry> 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>("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)

View File

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

View File

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

View File

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

View File

@ -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<file_entry>::const_iterator iterator;
typedef std::vector<file_entry>::const_reverse_iterator reverse_iterator;
typedef std::vector<internal_file_entry>::const_iterator iterator;
typedef std::vector<internal_file_entry>::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<file_entry> m_files;
std::vector<internal_file_entry> 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<char const*> 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<std::string> m_symlinks;
@ -231,7 +269,7 @@ namespace libtorrent
// offsets)
std::vector<size_type> 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<std::string> m_paths;

View File

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

View File

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

View File

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

View File

@ -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<file_entry>::const_iterator file_iter = std::upper_bound(
std::vector<internal_file_entry>::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<file_entry>::const_iterator file_iter = std::upper_bound(
std::vector<internal_file_entry>::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<file_entry>::iterator i = std::max_element(m_files.begin(), m_files.end()
std::vector<internal_file_entry>::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<file_entry>::iterator i = m_files.begin();
for (std::vector<internal_file_entry>::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<file_entry>::iterator best_match = m_files.end();
for (std::vector<file_entry>::iterator j = i+1; j < m_files.end(); ++j)
std::vector<internal_file_entry>::iterator best_match = m_files.end();
for (std::vector<internal_file_entry>::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;

View File

@ -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<file> open_file(file_entry const& fe, int mode, error_code& ec) const;
boost::intrusive_ptr<file> open_file(file_storage::iterator fe, int mode
, error_code& ec) const;
std::vector<boost::uint8_t> 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<file> f = open_file(*file_iter, file::read_write, ec);
boost::intrusive_ptr<file> 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<file> f = open_file(files().at(index), file::read_write, ec);
boost::intrusive_ptr<file> 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<file_entry>::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> file_handle = open_file(*file_iter, file::read_only, ec);
boost::intrusive_ptr<file> 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<file> f = open_file(*file_iter, file::read_only, ec);
boost::intrusive_ptr<file> 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<file_entry>::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<file> storage::open_file(file_entry const& fe, int mode, error_code& ec) const
boost::intrusive_ptr<file> 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;

View File

@ -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<file_entry&>(fe).set_name(str_ptr, fee->string_length());
const_cast<internal_file_entry&>(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

View File

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