added support for bitcomet padding files. simplified storage read/write code.

This commit is contained in:
Arvid Norberg 2008-10-03 05:49:41 +00:00
parent ff41246c42
commit d4c206841b
5 changed files with 145 additions and 163 deletions

View File

@ -56,7 +56,7 @@ namespace libtorrent
struct TORRENT_EXPORT file_entry struct TORRENT_EXPORT file_entry
{ {
file_entry(): offset(0), size(0), file_base(0) {} file_entry(): offset(0), size(0), file_base(0), pad_file(false) {}
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
@ -65,6 +65,7 @@ namespace libtorrent
// This is always 0 unless parts of the torrent is // This is always 0 unless parts of the torrent is
// compressed into a single file, such as a so-called part file. // compressed into a single file, such as a so-called part file.
size_type file_base; size_type file_base;
bool pad_file:1;
}; };
struct TORRENT_EXPORT file_slice struct TORRENT_EXPORT file_slice
@ -84,7 +85,7 @@ namespace libtorrent
bool is_valid() const { return m_piece_length > 0; } bool is_valid() const { return m_piece_length > 0; }
void add_file(file_entry const& e); void add_file(file_entry const& e);
void add_file(fs::path const& p, size_type size); void add_file(fs::path const& p, size_type size, bool pad_file = false);
void rename_file(int index, std::string const& new_filename); void rename_file(int index, std::string const& new_filename);
std::vector<file_slice> map_block(int piece, size_type offset std::vector<file_slice> map_block(int piece, size_type offset

View File

@ -128,7 +128,7 @@ namespace libtorrent
return ret; return ret;
} }
void file_storage::add_file(fs::path const& file, size_type size) void file_storage::add_file(fs::path const& file, size_type size, bool pad_file)
{ {
TORRENT_ASSERT(size >= 0); TORRENT_ASSERT(size >= 0);
#if BOOST_VERSION < 103600 #if BOOST_VERSION < 103600
@ -151,6 +151,7 @@ namespace libtorrent
} }
TORRENT_ASSERT(m_name == *file.begin()); TORRENT_ASSERT(m_name == *file.begin());
file_entry e; file_entry e;
e.pad_file = pad_file;
m_files.push_back(e); m_files.push_back(e);
m_files.back().size = size; m_files.back().size = size;
m_files.back().path = file; m_files.back().path = file;
@ -160,7 +161,7 @@ namespace libtorrent
void file_storage::add_file(file_entry const& e) void file_storage::add_file(file_entry const& e)
{ {
add_file(e.path, e.size); add_file(e.path, e.size, e.pad_file);
} }
} }

View File

@ -519,9 +519,12 @@ namespace libtorrent
#endif #endif
} }
int file_index = file_iter - files().begin();
// if the file is empty, just create it. But also make sure // if the file is empty, just create it. But also make sure
// the directory exists. // the directory exists.
if (file_iter->size == 0) if (file_iter->size == 0 && (int(m_file_priority.size()) <= file_index
|| m_file_priority[file_index] > 0))
{ {
file(m_save_path / file_iter->path, file::out, ec); file(m_save_path / file_iter->path, file::out, ec);
if (ec) if (ec)
@ -535,9 +538,10 @@ namespace libtorrent
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
try { try {
#endif #endif
// don't allocate files with priority 0 // don't allocate files with priority 0 or files
int file_index = file_iter - files().begin(); // that are pad files
if (allocate_files && (int(m_file_priority.size()) <= file_index if (allocate_files && !file_iter->pad_file
&& (int(m_file_priority.size()) <= file_index
|| m_file_priority[file_index] > 0)) || m_file_priority[file_index] > 0))
{ {
error_code ec; error_code ec;
@ -1023,38 +1027,13 @@ namespace libtorrent
file_offset -= file_iter->size; file_offset -= file_iter->size;
++file_iter; ++file_iter;
TORRENT_ASSERT(file_iter != files().end());
} }
int buf_pos = 0; int buf_pos = 0;
error_code ec; error_code ec;
boost::shared_ptr<file> in(m_pool.open_file(
this, m_save_path / file_iter->path, file::in, ec));
if (!in || ec)
{
set_error(m_save_path / file_iter->path, ec);
return -1;
}
TORRENT_ASSERT(file_offset < file_iter->size);
TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base);
size_type new_pos = in->seek(file_offset + file_iter->file_base, file::begin, ec);
if (new_pos != file_offset + file_iter->file_base || ec)
{
// the file was not big enough
if (!fill_zero)
{
set_error(m_save_path / file_iter->path, ec);
return -1;
}
std::memset(buf + buf_pos, 0, size - buf_pos);
return size;
}
#ifndef NDEBUG
size_type in_tell = in->tell(ec);
TORRENT_ASSERT(in_tell == file_offset + file_iter->file_base && !ec);
#endif
boost::shared_ptr<file> in;
int left_to_read = size; int left_to_read = size;
int slot_size = static_cast<int>(m_files.piece_size(slot)); int slot_size = static_cast<int>(m_files.piece_size(slot));
@ -1069,73 +1048,71 @@ namespace libtorrent
int counter = 0; int counter = 0;
#endif #endif
while (left_to_read > 0) int read_bytes;
for (;left_to_read > 0; ++file_iter, left_to_read -= read_bytes
, buf_pos += read_bytes)
{ {
int read_bytes = left_to_read; TORRENT_ASSERT(file_iter != files().end());
if (file_offset + read_bytes > file_iter->size) TORRENT_ASSERT(buf_pos >= 0);
read_bytes = static_cast<int>(file_iter->size - file_offset);
read_bytes = left_to_read;
if (file_offset + read_bytes > file_iter->size)
read_bytes = std::max(static_cast<int>(file_iter->size - file_offset), 0);
if (read_bytes == 0) continue;
if (read_bytes > 0)
{
#ifndef NDEBUG #ifndef NDEBUG
TORRENT_ASSERT(int(slices.size()) > counter); TORRENT_ASSERT(int(slices.size()) > counter);
size_type slice_size = slices[counter].size; size_type slice_size = slices[counter].size;
TORRENT_ASSERT(slice_size == read_bytes); TORRENT_ASSERT(slice_size == read_bytes);
TORRENT_ASSERT(files().at(slices[counter].file_index).path TORRENT_ASSERT(files().at(slices[counter].file_index).path
== file_iter->path); == file_iter->path);
++counter;
#endif #endif
int actual_read = int(in->read(buf + buf_pos, read_bytes, ec)); if (file_iter->pad_file)
{
if (read_bytes != actual_read || ec) std::memset(buf + buf_pos, 0, read_bytes);
{ continue;
// the file was not big enough
if (actual_read > 0) buf_pos += actual_read;
if (!fill_zero)
{
set_error(m_save_path / file_iter->path, ec);
return -1;
}
std::memset(buf + buf_pos, 0, size - buf_pos);
return size;
}
left_to_read -= read_bytes;
buf_pos += read_bytes;
TORRENT_ASSERT(buf_pos >= 0);
file_offset += read_bytes;
} }
if (left_to_read > 0) fs::path path = m_save_path / file_iter->path;
{
++file_iter;
#ifndef NDEBUG
// empty files are not returned by map_block, so if
// this file was empty, don't increment the slice counter
if (read_bytes > 0) ++counter;
#endif
fs::path path = m_save_path / file_iter->path;
file_offset = 0; error_code ec;
error_code ec; in = m_pool.open_file(this, path, file::in, ec);
in = m_pool.open_file( this, path, file::in, ec); if (!in || ec)
if (!in || ec) {
set_error(path, ec);
return -1;
}
size_type pos = in->seek(file_iter->file_base + file_offset, file::begin, ec);
if (pos != file_iter->file_base + file_offset || ec)
{
if (!fill_zero)
{ {
set_error(path, ec); set_error(m_save_path / file_iter->path, ec);
return -1; return -1;
} }
size_type pos = in->seek(file_iter->file_base, file::begin, ec); std::memset(buf + buf_pos, 0, size - buf_pos);
if (pos != file_iter->file_base || ec) return size;
{
if (!fill_zero)
{
set_error(m_save_path / file_iter->path, ec);
return -1;
}
std::memset(buf + buf_pos, 0, size - buf_pos);
return size;
}
} }
file_offset = 0;
int actual_read = int(in->read(buf + buf_pos, read_bytes, ec));
if (read_bytes != actual_read || ec)
{
// the file was not big enough
if (actual_read > 0) buf_pos += actual_read;
if (!fill_zero)
{
set_error(m_save_path / file_iter->path, ec);
return -1;
}
std::memset(buf + buf_pos, 0, size - buf_pos);
return size;
}
} }
return result; return result;
} }
@ -1159,6 +1136,7 @@ namespace libtorrent
#endif #endif
size_type start = slot * (size_type)m_files.piece_length() + offset; size_type start = slot * (size_type)m_files.piece_length() + offset;
TORRENT_ASSERT(start + size <= m_files.total_size());
// find the file iterator and file offset // find the file iterator and file offset
size_type file_offset = start; size_type file_offset = start;
@ -1174,27 +1152,10 @@ namespace libtorrent
TORRENT_ASSERT(file_iter != files().end()); TORRENT_ASSERT(file_iter != files().end());
} }
fs::path p(m_save_path / file_iter->path); int buf_pos = 0;
error_code ec; error_code ec;
boost::shared_ptr<file> out = m_pool.open_file(
this, p, file::out | file::in, ec);
if (!out || ec)
{
set_error(p, ec);
return -1;
}
TORRENT_ASSERT(file_offset < file_iter->size);
TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base);
size_type pos = out->seek(file_offset + file_iter->file_base, file::begin, ec);
if (pos != file_offset + file_iter->file_base || ec)
{
set_error(p, ec);
return -1;
}
boost::shared_ptr<file> out;
int left_to_write = size; int left_to_write = size;
int slot_size = static_cast<int>(m_files.piece_size(slot)); int slot_size = static_cast<int>(m_files.piece_size(slot));
@ -1203,72 +1164,62 @@ namespace libtorrent
TORRENT_ASSERT(left_to_write >= 0); TORRENT_ASSERT(left_to_write >= 0);
int buf_pos = 0;
#ifndef NDEBUG #ifndef NDEBUG
int counter = 0; int counter = 0;
#endif #endif
while (left_to_write > 0)
int write_bytes;
for (;left_to_write > 0; ++file_iter, left_to_write -= write_bytes
, buf_pos += write_bytes)
{ {
int write_bytes = left_to_write; TORRENT_ASSERT(file_iter != files().end());
TORRENT_ASSERT(buf_pos >= 0);
write_bytes = left_to_write;
if (file_offset + write_bytes > file_iter->size) if (file_offset + write_bytes > file_iter->size)
{ write_bytes = std::max(static_cast<int>(file_iter->size - file_offset), 0);
TORRENT_ASSERT(file_iter->size >= file_offset);
write_bytes = static_cast<int>(file_iter->size - file_offset);
}
if (write_bytes > 0) if (write_bytes == 0) continue;
{
TORRENT_ASSERT(int(slices.size()) > counter);
TORRENT_ASSERT(slices[counter].size == write_bytes);
TORRENT_ASSERT(files().at(slices[counter].file_index).path
== file_iter->path);
TORRENT_ASSERT(buf_pos >= 0);
TORRENT_ASSERT(write_bytes >= 0);
error_code ec;
size_type written = out->write(buf + buf_pos, write_bytes, ec);
if (written != write_bytes || ec)
{
set_error(m_save_path / file_iter->path, ec);
return -1;
}
left_to_write -= write_bytes;
buf_pos += write_bytes;
TORRENT_ASSERT(buf_pos >= 0);
file_offset += write_bytes;
TORRENT_ASSERT(file_offset <= file_iter->size);
}
if (left_to_write > 0)
{
#ifndef NDEBUG #ifndef NDEBUG
if (write_bytes > 0) ++counter; TORRENT_ASSERT(int(slices.size()) > counter);
size_type slice_size = slices[counter].size;
TORRENT_ASSERT(slice_size == write_bytes);
TORRENT_ASSERT(files().at(slices[counter].file_index).path
== file_iter->path);
++counter;
#endif #endif
++file_iter;
TORRENT_ASSERT(file_iter != files().end()); if (file_iter->pad_file)
fs::path p = m_save_path / file_iter->path; continue;
file_offset = 0;
error_code ec;
out = m_pool.open_file(
this, p, file::out | file::in, ec);
if (!out || ec) fs::path path = m_save_path / file_iter->path;
{
set_error(p, ec);
return -1;
}
size_type pos = out->seek(file_iter->file_base, file::begin, ec); error_code ec;
out = m_pool.open_file(this, path, file::in | file::out, ec);
if (pos != file_iter->file_base || ec) if (!out || ec)
{ {
set_error(p, ec); set_error(path, ec);
return -1; return -1;
}
} }
size_type pos = out->seek(file_iter->file_base + file_offset, file::begin, ec);
if (pos != file_iter->file_base + file_offset || ec)
{
set_error(m_save_path / file_iter->path, ec);
return -1;
}
file_offset = 0;
int actual_written = int(out->write(buf + buf_pos, write_bytes, ec));
if (write_bytes != actual_written || ec)
{
// the file was not big enough
if (actual_written > 0) buf_pos += actual_written;
set_error(m_save_path / file_iter->path, ec);
return -1;
}
} }
return size; return size;
} }

View File

@ -506,6 +506,27 @@ namespace libtorrent
} }
} }
TORRENT_ASSERT(m_block_size > 0);
int file = 0;
for (file_storage::iterator i = m_torrent_file->files().begin()
, end(m_torrent_file->files().end()); i != end; ++i, ++file)
{
if (!i->pad_file) continue;
peer_request pr = m_torrent_file->map_file(file, 0, m_torrent_file->file_at(file).size);
int off = pr.start % m_block_size;
if (off != 0) { pr.length -= m_block_size - off; pr.start += m_block_size - off; }
TORRENT_ASSERT((pr.start % m_block_size) == 0);
int blocks_per_piece = m_torrent_file->piece_length() / m_block_size;
piece_block pb(pr.piece, pr.start / m_block_size);
for (; pr.length >= m_block_size; pr.length -= m_block_size, ++pb.block_index)
{
if (pb.block_index == blocks_per_piece) { pb.block_index = 0; ++pb.piece_index; }
m_picker->mark_as_finished(pb, 0);
}
}
m_storage->async_check_fastresume(&m_resume_entry m_storage->async_check_fastresume(&m_resume_entry
, bind(&torrent::on_resume_data_checked , bind(&torrent::on_resume_data_checked
, shared_from_this(), _1, _2)); , shared_from_this(), _1, _2));

View File

@ -187,6 +187,11 @@ namespace
verify_encoding(target); verify_encoding(target);
if (target.path.is_complete()) if (target.path.is_complete())
return false; return false;
// bitcomet pad file
if (target.path.filename().substr(0, 18) == "_____padding_file_")
target.pad_file = true;
return true; return true;
} }
@ -416,6 +421,9 @@ namespace libtorrent
e.path = name; e.path = name;
e.offset = 0; e.offset = 0;
e.size = info.dict_find_int_value("length", -1); e.size = info.dict_find_int_value("length", -1);
// bitcomet pad file
if (e.path.filename().substr(0, 18) == "_____padding_file_")
e.pad_file = true;
if (e.size < 0) if (e.size < 0)
{ {
error = "invalid length of torrent"; error = "invalid length of torrent";