first version of 'part file' support. Can currently only be set when starting torrent

This commit is contained in:
Arvid Norberg 2007-11-25 10:47:05 +00:00
parent b00096ad33
commit 769d8aefe2
5 changed files with 70 additions and 26 deletions

View File

@ -918,7 +918,7 @@ The ``torrent_info`` has the following synopsis::
typedef std::vector<file_entry>::const_reverse_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 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
``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
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
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
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;
size_type offset;
size_type size;
size_type file_base;
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
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
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,

View File

@ -69,9 +69,15 @@ namespace libtorrent
struct TORRENT_EXPORT file_entry
{
file_entry(): offset(0), size(0), file_base(0) {}
fs::path 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;
// if the path was incorrectly encoded, this is
// the original corrupt encoded string. It is
// 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_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
, int size, bool storage = false) const;
@ -271,7 +277,7 @@ namespace libtorrent
// this vector is typically empty. If it is not
// 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
// writing the disk.
std::vector<file_entry> m_remapped_files;

View File

@ -768,10 +768,10 @@ namespace libtorrent
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);
if (new_pos != file_offset)
size_type new_pos = in->seek(file_offset + file_iter->file_base);
if (new_pos != file_offset + file_iter->file_base)
{
// the file was not big enough
if (!fill_zero)
@ -782,7 +782,7 @@ namespace libtorrent
#ifndef NDEBUG
size_type in_tell = in->tell();
TORRENT_ASSERT(in_tell == file_offset);
TORRENT_ASSERT(in_tell == file_offset + file_iter->file_base);
#endif
int left_to_read = size;
@ -846,7 +846,7 @@ namespace libtorrent
file_offset = 0;
in = m_files.open_file(
this, path, file::in);
in->seek(0);
in->seek(file_iter->file_base);
}
}
return result;
@ -892,11 +892,11 @@ namespace libtorrent
this, p, file::out | file::in);
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;
s << "no storage for slot " << slot;
@ -962,7 +962,7 @@ namespace libtorrent
out = m_files.open_file(
this, p, file::out | file::in);
out->seek(0);
out->seek(file_iter->file_base);
}
}
}

View File

@ -165,7 +165,7 @@ namespace
{
target.size = dict["length"].integer();
target.path = root_dir;
target.file_base = 0;
// prefer the name.utf-8
// because if it exists, it is more
@ -824,20 +824,19 @@ namespace libtorrent
m_nodes.push_back(node);
}
bool torrent_info::remap_files(std::vector<std::pair<std::string
, libtorrent::size_type> > const& map)
bool torrent_info::remap_files(std::vector<file_entry> const& map)
{
typedef std::vector<std::pair<std::string, size_type> > files_t;
size_type offset = 0;
m_remapped_files.resize(map.size());
for (int i = 0; i < int(map.size()); ++i)
{
file_entry& fe = m_remapped_files[i];
fe.path = map[i].first;
fe.path = map[i].path;
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;
}
if (offset != total_size())
@ -846,6 +845,26 @@ namespace libtorrent
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;
}
@ -871,7 +890,7 @@ namespace libtorrent
{
file_slice f;
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);
size -= f.size;
file_offset += f.size;

View File

@ -192,8 +192,17 @@ void run_test(path const& test_path)
// ==============================================
// make sure remap_files works
std::vector<std::pair<std::string, libtorrent::size_type> > map;
map.push_back(std::make_pair(std::string("temp_storage/test.tmp"), 17 + 612 + 1));
std::vector<file_entry> map;
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);
TEST_CHECK(ret);
@ -202,7 +211,7 @@ void run_test(path const& test_path)
run_storage_tests(info, test_path, storage_mode_compact);
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");