first version of 'part file' support. Can currently only be set when starting torrent
This commit is contained in:
@@ -918,7 +918,7 @@ The ``torrent_info`` has the following synopsis::
|
|||||||
typedef std::vector<file_entry>::const_reverse_iterator
|
typedef std::vector<file_entry>::const_reverse_iterator
|
||||||
reverse_file_iterator;
|
reverse_file_iterator;
|
||||||
|
|
||||||
bool remap_files(std::vector<std::pair<std::string, libtorrent::size_type> > const& map);
|
bool remap_files(std::vector<file_entry> const& map);
|
||||||
|
|
||||||
file_iterator begin_files(bool storage = false) const;
|
file_iterator begin_files(bool storage = false) const;
|
||||||
file_iterator end_files(bool storage = false) const;
|
file_iterator end_files(bool storage = false) const;
|
||||||
@@ -1052,18 +1052,20 @@ remap_files()
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
bool remap_files(std::vector<std::pair<std::string, libtorrent::size_type> > const& map);
|
bool remap_files(std::vector<file_entry> const& map);
|
||||||
|
|
||||||
This call will create a new mapping of the data in this torrent to other files. The
|
This call will create a new mapping of the data in this torrent to other files. The
|
||||||
``torrent_info`` maintains 2 views of the file storage. One that is true to the torrent
|
``torrent_info`` maintains 2 views of the file storage. One that is true to the torrent
|
||||||
file, and one that represents what is actually saved on disk. This call will change
|
file, and one that represents what is actually saved on disk. This call will change
|
||||||
what the files on disk are called.
|
what the files on disk are called.
|
||||||
|
|
||||||
The each entry in the vector ``map`` is a pair of a (relative) file path and the file's size.
|
The each entry in the vector ``map`` is a ``file_entry``. The only fields in this struct
|
||||||
|
that are used in this case are ``path``, ``size`` and ``file_base``.
|
||||||
|
|
||||||
The return value indicates if the remap was successful or not. True means success and
|
The return value indicates if the remap was successful or not. True means success and
|
||||||
false means failure. The sum of all the files passed in through ``map`` has to be exactly
|
false means failure. The sum of all the files passed in through ``map`` has to be exactly
|
||||||
the same as the total_size of the torrent.
|
the same as the total_size of the torrent. If the number of bytes that are mapped do not
|
||||||
|
match, false will be returned (this is the only case this function may fail).
|
||||||
|
|
||||||
Changing this mapping for an existing torrent will not move or rename files. If some files
|
Changing this mapping for an existing torrent will not move or rename files. If some files
|
||||||
should be renamed, this can be done before the torrent is added.
|
should be renamed, this can be done before the torrent is added.
|
||||||
@@ -1097,6 +1099,7 @@ remapped, they may differ. For more info, see `remap_files()`_.
|
|||||||
boost::filesystem::path path;
|
boost::filesystem::path path;
|
||||||
size_type offset;
|
size_type offset;
|
||||||
size_type size;
|
size_type size;
|
||||||
|
size_type file_base;
|
||||||
boost::shared_ptr<const boost::filesystem::path> orig_path;
|
boost::shared_ptr<const boost::filesystem::path> orig_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1108,6 +1111,13 @@ The filenames are encoded with UTF-8.
|
|||||||
of the file within the torrent. i.e. the sum of all the sizes of the files
|
of the file within the torrent. i.e. the sum of all the sizes of the files
|
||||||
before it in the list.
|
before it in the list.
|
||||||
|
|
||||||
|
``file_base`` is the offset in the file where the storage should start. The normal
|
||||||
|
case is to have this set to 0, so that the storage starts saving data at the start
|
||||||
|
if the file. In cases where multiple files are mapped into the same file though,
|
||||||
|
the ``file_base`` should be set to an offset so that the different regions do
|
||||||
|
not overlap. This is used when mapping "unselected" files into a so-called part
|
||||||
|
file.
|
||||||
|
|
||||||
``orig_path`` is set to 0 in case the path element is an exact copy of that
|
``orig_path`` is set to 0 in case the path element is an exact copy of that
|
||||||
found in the metadata. In case the path in the original metadata was
|
found in the metadata. In case the path in the original metadata was
|
||||||
incorrectly encoded, and had to be fixed in order to be acceptable utf-8,
|
incorrectly encoded, and had to be fixed in order to be acceptable utf-8,
|
||||||
|
@@ -69,9 +69,15 @@ namespace libtorrent
|
|||||||
|
|
||||||
struct TORRENT_EXPORT file_entry
|
struct TORRENT_EXPORT file_entry
|
||||||
{
|
{
|
||||||
|
file_entry(): offset(0), size(0), file_base(0) {}
|
||||||
|
|
||||||
fs::path path;
|
fs::path path;
|
||||||
size_type offset; // the offset of this file inside the torrent
|
size_type offset; // the offset of this file inside the torrent
|
||||||
size_type size; // the size of this file
|
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;
|
||||||
// if the path was incorrectly encoded, this is
|
// if the path was incorrectly encoded, this is
|
||||||
// the original corrupt encoded string. It is
|
// the original corrupt encoded string. It is
|
||||||
// preserved in order to be able to reproduce
|
// preserved in order to be able to reproduce
|
||||||
@@ -117,7 +123,7 @@ namespace libtorrent
|
|||||||
void add_file(fs::path file, size_type size);
|
void add_file(fs::path file, size_type size);
|
||||||
void add_url_seed(std::string const& url);
|
void add_url_seed(std::string const& url);
|
||||||
|
|
||||||
bool remap_files(std::vector<std::pair<std::string, libtorrent::size_type> > const& map);
|
bool remap_files(std::vector<file_entry> const& map);
|
||||||
|
|
||||||
std::vector<file_slice> map_block(int piece, size_type offset
|
std::vector<file_slice> map_block(int piece, size_type offset
|
||||||
, int size, bool storage = false) const;
|
, int size, bool storage = false) const;
|
||||||
@@ -271,7 +277,7 @@ namespace libtorrent
|
|||||||
|
|
||||||
// this vector is typically empty. If it is not
|
// this vector is typically empty. If it is not
|
||||||
// empty, it means the user has re-mapped the
|
// empty, it means the user has re-mapped the
|
||||||
// files in this torrent to diffefrent names
|
// files in this torrent to different names
|
||||||
// on disk. This is only used when reading and
|
// on disk. This is only used when reading and
|
||||||
// writing the disk.
|
// writing the disk.
|
||||||
std::vector<file_entry> m_remapped_files;
|
std::vector<file_entry> m_remapped_files;
|
||||||
|
@@ -768,10 +768,10 @@ namespace libtorrent
|
|||||||
|
|
||||||
TORRENT_ASSERT(file_offset < file_iter->size);
|
TORRENT_ASSERT(file_offset < file_iter->size);
|
||||||
|
|
||||||
TORRENT_ASSERT(slices[0].offset == file_offset);
|
TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base);
|
||||||
|
|
||||||
size_type new_pos = in->seek(file_offset);
|
size_type new_pos = in->seek(file_offset + file_iter->file_base);
|
||||||
if (new_pos != file_offset)
|
if (new_pos != file_offset + file_iter->file_base)
|
||||||
{
|
{
|
||||||
// the file was not big enough
|
// the file was not big enough
|
||||||
if (!fill_zero)
|
if (!fill_zero)
|
||||||
@@ -782,7 +782,7 @@ namespace libtorrent
|
|||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
size_type in_tell = in->tell();
|
size_type in_tell = in->tell();
|
||||||
TORRENT_ASSERT(in_tell == file_offset);
|
TORRENT_ASSERT(in_tell == file_offset + file_iter->file_base);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int left_to_read = size;
|
int left_to_read = size;
|
||||||
@@ -846,7 +846,7 @@ namespace libtorrent
|
|||||||
file_offset = 0;
|
file_offset = 0;
|
||||||
in = m_files.open_file(
|
in = m_files.open_file(
|
||||||
this, path, file::in);
|
this, path, file::in);
|
||||||
in->seek(0);
|
in->seek(file_iter->file_base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -892,11 +892,11 @@ namespace libtorrent
|
|||||||
this, p, file::out | file::in);
|
this, p, file::out | file::in);
|
||||||
|
|
||||||
TORRENT_ASSERT(file_offset < file_iter->size);
|
TORRENT_ASSERT(file_offset < file_iter->size);
|
||||||
TORRENT_ASSERT(slices[0].offset == file_offset);
|
TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base);
|
||||||
|
|
||||||
size_type pos = out->seek(file_offset);
|
size_type pos = out->seek(file_offset + file_iter->file_base);
|
||||||
|
|
||||||
if (pos != file_offset)
|
if (pos != file_offset + file_iter->file_base)
|
||||||
{
|
{
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
s << "no storage for slot " << slot;
|
s << "no storage for slot " << slot;
|
||||||
@@ -962,7 +962,7 @@ namespace libtorrent
|
|||||||
out = m_files.open_file(
|
out = m_files.open_file(
|
||||||
this, p, file::out | file::in);
|
this, p, file::out | file::in);
|
||||||
|
|
||||||
out->seek(0);
|
out->seek(file_iter->file_base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -165,7 +165,7 @@ namespace
|
|||||||
{
|
{
|
||||||
target.size = dict["length"].integer();
|
target.size = dict["length"].integer();
|
||||||
target.path = root_dir;
|
target.path = root_dir;
|
||||||
|
target.file_base = 0;
|
||||||
|
|
||||||
// prefer the name.utf-8
|
// prefer the name.utf-8
|
||||||
// because if it exists, it is more
|
// because if it exists, it is more
|
||||||
@@ -824,20 +824,19 @@ namespace libtorrent
|
|||||||
m_nodes.push_back(node);
|
m_nodes.push_back(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool torrent_info::remap_files(std::vector<std::pair<std::string
|
bool torrent_info::remap_files(std::vector<file_entry> const& map)
|
||||||
, libtorrent::size_type> > const& map)
|
|
||||||
{
|
{
|
||||||
typedef std::vector<std::pair<std::string, size_type> > files_t;
|
|
||||||
|
|
||||||
size_type offset = 0;
|
size_type offset = 0;
|
||||||
m_remapped_files.resize(map.size());
|
m_remapped_files.resize(map.size());
|
||||||
|
|
||||||
for (int i = 0; i < int(map.size()); ++i)
|
for (int i = 0; i < int(map.size()); ++i)
|
||||||
{
|
{
|
||||||
file_entry& fe = m_remapped_files[i];
|
file_entry& fe = m_remapped_files[i];
|
||||||
fe.path = map[i].first;
|
fe.path = map[i].path;
|
||||||
fe.offset = offset;
|
fe.offset = offset;
|
||||||
fe.size = map[i].second;
|
fe.size = map[i].size;
|
||||||
|
fe.file_base = map[i].file_base;
|
||||||
|
fe.orig_path.reset();
|
||||||
offset += fe.size;
|
offset += fe.size;
|
||||||
}
|
}
|
||||||
if (offset != total_size())
|
if (offset != total_size())
|
||||||
@@ -846,6 +845,26 @@ namespace libtorrent
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::vector<file_entry> map2(m_remapped_files);
|
||||||
|
std::sort(map2.begin(), map2.end()
|
||||||
|
, bind(&file_entry::file_base, _1) < bind(&file_entry::file_base, _2));
|
||||||
|
std::stable_sort(map2.begin(), map2.end()
|
||||||
|
, bind(&file_entry::path, _1) < bind(&file_entry::path, _2));
|
||||||
|
fs::path last_path;
|
||||||
|
size_type last_end = 0;
|
||||||
|
for (std::vector<file_entry>::iterator i = map2.begin(), end(map2.end());
|
||||||
|
i != end; ++i)
|
||||||
|
{
|
||||||
|
if (last_path == i->path)
|
||||||
|
{
|
||||||
|
assert(last_end <= i->file_base);
|
||||||
|
}
|
||||||
|
last_end = i->file_base + i->size;
|
||||||
|
last_path = i->path;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -871,7 +890,7 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
file_slice f;
|
file_slice f;
|
||||||
f.file_index = counter;
|
f.file_index = counter;
|
||||||
f.offset = file_offset;
|
f.offset = file_offset + file_iter->file_base;
|
||||||
f.size = (std::min)(file_iter->size - file_offset, (size_type)size);
|
f.size = (std::min)(file_iter->size - file_offset, (size_type)size);
|
||||||
size -= f.size;
|
size -= f.size;
|
||||||
file_offset += f.size;
|
file_offset += f.size;
|
||||||
|
@@ -192,8 +192,17 @@ void run_test(path const& test_path)
|
|||||||
// ==============================================
|
// ==============================================
|
||||||
|
|
||||||
// make sure remap_files works
|
// make sure remap_files works
|
||||||
std::vector<std::pair<std::string, libtorrent::size_type> > map;
|
std::vector<file_entry> map;
|
||||||
map.push_back(std::make_pair(std::string("temp_storage/test.tmp"), 17 + 612 + 1));
|
file_entry fe;
|
||||||
|
fe.path = "temp_storage/test.tmp";
|
||||||
|
fe.size = 17;
|
||||||
|
fe.file_base = 612 + 1;
|
||||||
|
map.push_back(fe);
|
||||||
|
fe.path = "temp_storage/test.tmp";
|
||||||
|
fe.size = 612 + 1;
|
||||||
|
fe.file_base = 0;
|
||||||
|
map.push_back(fe);
|
||||||
|
|
||||||
bool ret = info->remap_files(map);
|
bool ret = info->remap_files(map);
|
||||||
TEST_CHECK(ret);
|
TEST_CHECK(ret);
|
||||||
|
|
||||||
@@ -202,7 +211,7 @@ void run_test(path const& test_path)
|
|||||||
run_storage_tests(info, test_path, storage_mode_compact);
|
run_storage_tests(info, test_path, storage_mode_compact);
|
||||||
|
|
||||||
std::cerr << file_size(test_path / "temp_storage" / "test.tmp") << std::endl;
|
std::cerr << file_size(test_path / "temp_storage" / "test.tmp") << std::endl;
|
||||||
TEST_CHECK(file_size(test_path / "temp_storage" / "test.tmp") == 48);
|
TEST_CHECK(file_size(test_path / "temp_storage" / "test.tmp") == 17 + 612 + 1);
|
||||||
|
|
||||||
remove_all(test_path / "temp_storage");
|
remove_all(test_path / "temp_storage");
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user