diff --git a/include/libtorrent/file_storage.hpp b/include/libtorrent/file_storage.hpp index 47fcb92eb..f70583df7 100644 --- a/include/libtorrent/file_storage.hpp +++ b/include/libtorrent/file_storage.hpp @@ -56,7 +56,7 @@ namespace libtorrent 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; 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 // compressed into a single file, such as a so-called part file. size_type file_base; + bool pad_file:1; }; struct TORRENT_EXPORT file_slice @@ -84,7 +85,7 @@ namespace libtorrent bool is_valid() const { return m_piece_length > 0; } 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); std::vector map_block(int piece, size_type offset diff --git a/src/file_storage.cpp b/src/file_storage.cpp index dd732bef1..fd38c4204 100644 --- a/src/file_storage.cpp +++ b/src/file_storage.cpp @@ -128,7 +128,7 @@ namespace libtorrent 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); #if BOOST_VERSION < 103600 @@ -151,6 +151,7 @@ namespace libtorrent } TORRENT_ASSERT(m_name == *file.begin()); file_entry e; + e.pad_file = pad_file; m_files.push_back(e); m_files.back().size = size; m_files.back().path = file; @@ -160,7 +161,7 @@ namespace libtorrent void file_storage::add_file(file_entry const& e) { - add_file(e.path, e.size); + add_file(e.path, e.size, e.pad_file); } } diff --git a/src/storage.cpp b/src/storage.cpp index 82ed21ffc..32c8e9baf 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -519,9 +519,12 @@ namespace libtorrent #endif } + int file_index = file_iter - files().begin(); + // if the file is empty, just create it. But also make sure // 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); if (ec) @@ -535,9 +538,10 @@ namespace libtorrent #ifndef BOOST_NO_EXCEPTIONS try { #endif - // don't allocate files with priority 0 - int file_index = file_iter - files().begin(); - if (allocate_files && (int(m_file_priority.size()) <= file_index + // don't allocate files with priority 0 or files + // that are pad files + if (allocate_files && !file_iter->pad_file + && (int(m_file_priority.size()) <= file_index || m_file_priority[file_index] > 0)) { error_code ec; @@ -1023,38 +1027,13 @@ namespace libtorrent file_offset -= file_iter->size; ++file_iter; + TORRENT_ASSERT(file_iter != files().end()); } - + int buf_pos = 0; error_code ec; - boost::shared_ptr 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 in; int left_to_read = size; int slot_size = static_cast(m_files.piece_size(slot)); @@ -1069,73 +1048,71 @@ namespace libtorrent int counter = 0; #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; - if (file_offset + read_bytes > file_iter->size) - read_bytes = static_cast(file_iter->size - file_offset); + TORRENT_ASSERT(file_iter != files().end()); + TORRENT_ASSERT(buf_pos >= 0); + + read_bytes = left_to_read; + if (file_offset + read_bytes > file_iter->size) + read_bytes = std::max(static_cast(file_iter->size - file_offset), 0); + + if (read_bytes == 0) continue; - if (read_bytes > 0) - { #ifndef NDEBUG - TORRENT_ASSERT(int(slices.size()) > counter); - size_type slice_size = slices[counter].size; - TORRENT_ASSERT(slice_size == read_bytes); - TORRENT_ASSERT(files().at(slices[counter].file_index).path - == file_iter->path); + TORRENT_ASSERT(int(slices.size()) > counter); + size_type slice_size = slices[counter].size; + TORRENT_ASSERT(slice_size == read_bytes); + TORRENT_ASSERT(files().at(slices[counter].file_index).path + == file_iter->path); + ++counter; #endif - 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; - } - - left_to_read -= read_bytes; - buf_pos += read_bytes; - TORRENT_ASSERT(buf_pos >= 0); - file_offset += read_bytes; + if (file_iter->pad_file) + { + std::memset(buf + buf_pos, 0, read_bytes); + continue; } - if (left_to_read > 0) - { - ++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; + fs::path path = m_save_path / file_iter->path; - file_offset = 0; - error_code ec; - in = m_pool.open_file( this, path, file::in, ec); - if (!in || ec) + error_code ec; + in = m_pool.open_file(this, path, file::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; } - size_type pos = in->seek(file_iter->file_base, file::begin, ec); - if (pos != file_iter->file_base || ec) - { - 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; - } + 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; } @@ -1159,6 +1136,7 @@ namespace libtorrent #endif 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 size_type file_offset = start; @@ -1174,27 +1152,10 @@ namespace libtorrent TORRENT_ASSERT(file_iter != files().end()); } - fs::path p(m_save_path / file_iter->path); + int buf_pos = 0; error_code ec; - boost::shared_ptr 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 out; int left_to_write = size; int slot_size = static_cast(m_files.piece_size(slot)); @@ -1203,72 +1164,62 @@ namespace libtorrent TORRENT_ASSERT(left_to_write >= 0); - int buf_pos = 0; #ifndef NDEBUG int counter = 0; #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) - { - TORRENT_ASSERT(file_iter->size >= file_offset); - write_bytes = static_cast(file_iter->size - file_offset); - } + write_bytes = std::max(static_cast(file_iter->size - file_offset), 0); - if (write_bytes > 0) - { - 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); + if (write_bytes == 0) continue; - 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 - 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 - ++file_iter; - TORRENT_ASSERT(file_iter != files().end()); - fs::path p = m_save_path / file_iter->path; - file_offset = 0; - error_code ec; - out = m_pool.open_file( - this, p, file::out | file::in, ec); + if (file_iter->pad_file) + continue; - if (!out || ec) - { - set_error(p, ec); - return -1; - } + fs::path path = m_save_path / file_iter->path; - size_type pos = out->seek(file_iter->file_base, file::begin, ec); - - if (pos != file_iter->file_base || ec) - { - set_error(p, ec); - return -1; - } + error_code ec; + out = m_pool.open_file(this, path, file::in | file::out, ec); + if (!out || ec) + { + set_error(path, ec); + 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; } diff --git a/src/torrent.cpp b/src/torrent.cpp index 7a590f994..b8f81a06a 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -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 , bind(&torrent::on_resume_data_checked , shared_from_this(), _1, _2)); diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 6fb5fa992..f9ff2c8d3 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -187,6 +187,11 @@ namespace verify_encoding(target); if (target.path.is_complete()) return false; + + // bitcomet pad file + if (target.path.filename().substr(0, 18) == "_____padding_file_") + target.pad_file = true; + return true; } @@ -416,6 +421,9 @@ namespace libtorrent e.path = name; e.offset = 0; 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) { error = "invalid length of torrent";