diff options
-rw-r--r-- | .SRCINFO | 22 | ||||
-rw-r--r-- | PKGBUILD | 50 | ||||
-rw-r--r-- | backport_lt_all_01-partially_done_and_choke_group_fix.patch | 282 | ||||
-rw-r--r-- | backport_lt_all_02-honor_system_file_allocate_fix.patch | 340 | ||||
-rw-r--r-- | lt-ps_all_02-better-bencode-errors_all.patch | 40 |
5 files changed, 734 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO new file mode 100644 index 000000000000..c06eee3f9619 --- /dev/null +++ b/.SRCINFO @@ -0,0 +1,22 @@ +pkgbase = libtorrent-ps-ch + pkgdesc = BitTorrent library written in C++ for use with rtorrent-ps-ch + pkgver = 1.8.3 + pkgrel = 1 + url = https://github.com/rakshasa/libtorrent + arch = any + license = GPL2 + depends = openssl + provides = libtorrent + conflicts = libtorrent + conflicts = libtorrent-ps + source = https://github.com/rakshasa/libtorrent/archive/v0.13.8.tar.gz + source = backport_lt_all_01-partially_done_and_choke_group_fix.patch + source = backport_lt_all_02-honor_system_file_allocate_fix.patch + source = lt-ps_all_02-better-bencode-errors_all.patch + md5sums = dd184eadb8b449ddc6c3498a93ddd568 + md5sums = 2a8eb09877e81e3e72bd544c27b45dbb + md5sums = 4797c5abf04dca2468178bc85244d076 + md5sums = dfae06b33afa738211619040810be8b4 + +pkgname = libtorrent-ps-ch + diff --git a/PKGBUILD b/PKGBUILD new file mode 100644 index 000000000000..d22e5ec39137 --- /dev/null +++ b/PKGBUILD @@ -0,0 +1,50 @@ +# Maintainer: qdesjardin <qdesjardin gmail com> + +_pkgname=libtorrent +pkgname=libtorrent-ps-ch +_pkgver=0.13.8 +pkgver=1.8.3 +pkgrel=1 +pkgdesc='BitTorrent library written in C++ for use with rtorrent-ps-ch' +license=('GPL2') +arch=('any') +url='https://github.com/rakshasa/libtorrent' +depends=('openssl') +provides=('libtorrent') +conflicts=('libtorrent' 'libtorrent-ps') +source=("https://github.com/rakshasa/$_pkgname/archive/v$_pkgver.tar.gz" + 'backport_lt_all_01-partially_done_and_choke_group_fix.patch' + 'backport_lt_all_02-honor_system_file_allocate_fix.patch' + 'lt-ps_all_02-better-bencode-errors_all.patch') +md5sums=('dd184eadb8b449ddc6c3498a93ddd568' + '2a8eb09877e81e3e72bd544c27b45dbb' + '4797c5abf04dca2468178bc85244d076' + 'dfae06b33afa738211619040810be8b4') + +prepare() { + cd "$srcdir/$_pkgname-$_pkgver" + + for corepatch in "$srcdir"/lt-ps_*.patch; do + test ! -e "$corepatch" || { msg2 "$(basename $corepatch)"; patch -uNp1 -i "$corepatch"; } + done + + for backport in "$srcdir"/{backport,misc}_lt_*.patch; do + test ! -e "$backport" || { msg2 "$(basename $backport)"; patch -uNp1 -i "$backport"; } + done + + ./autogen.sh +} + +build() { + cd "$srcdir/$_pkgname-$_pkgver" + + ./configure \ + --prefix=/usr \ + --disable-debug + make +} + +package() { + cd "$srcdir/$_pkgname-$_pkgver" + make DESTDIR="$pkgdir" install +} diff --git a/backport_lt_all_01-partially_done_and_choke_group_fix.patch b/backport_lt_all_01-partially_done_and_choke_group_fix.patch new file mode 100644 index 000000000000..7c812bdf9e3e --- /dev/null +++ b/backport_lt_all_01-partially_done_and_choke_group_fix.patch @@ -0,0 +1,282 @@ +--- a/src/download/download_wrapper.cc 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/download/download_wrapper.cc 2017-04-30 21:25:15.511379804 +0100 +@@ -228,6 +228,7 @@ DownloadWrapper::receive_hash_done(Chunk + priority_queue_erase(&taskScheduler, &m_main->delay_partially_done()); + priority_queue_erase(&taskScheduler, &m_main->delay_partially_restarted()); + priority_queue_insert(&taskScheduler, &m_main->delay_partially_done(), cachedTime); ++ finished_download(); + } + + if (!m_main->have_queue()->empty() && m_main->have_queue()->front().first >= cachedTime) +@@ -325,8 +326,10 @@ DownloadWrapper::receive_tick(uint32_t t + + void + DownloadWrapper::receive_update_priorities() { +- if (m_main->chunk_selector()->empty()) ++ if (m_main->chunk_selector()->empty()) { ++ file_list()->set_selected_size_bytes(); + return; ++ } + + data()->mutable_high_priority()->clear(); + data()->mutable_normal_priority()->clear(); +@@ -373,11 +376,15 @@ DownloadWrapper::receive_update_prioriti + priority_queue_erase(&taskScheduler, &m_main->delay_partially_done()); + priority_queue_erase(&taskScheduler, &m_main->delay_partially_restarted()); + +- if (was_partial) ++ if (was_partial) { + priority_queue_insert(&taskScheduler, &m_main->delay_partially_done(), cachedTime); +- else ++ finished_download(); ++ } else { + priority_queue_insert(&taskScheduler, &m_main->delay_partially_restarted(), cachedTime); ++ } + } ++ ++ file_list()->set_selected_size_bytes(); + } + + void +--- a/src/manager.cc 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/manager.cc 2017-04-30 21:15:43.000000000 +0100 +@@ -98,7 +98,7 @@ Manager::Manager() : + m_connectionManager->listen()->slot_accepted() = + std::bind(&HandshakeManager::add_incoming, m_handshakeManager, std::placeholders::_1, std::placeholders::_2); + +- m_resourceManager->push_group("default"); ++ m_resourceManager->push_group("default_leech"); + m_resourceManager->group_back()->up_queue()->set_heuristics(choke_queue::HEURISTICS_UPLOAD_LEECH); + m_resourceManager->group_back()->down_queue()->set_heuristics(choke_queue::HEURISTICS_DOWNLOAD_LEECH); + } +--- a/src/protocol/handshake_manager.cc 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/protocol/handshake_manager.cc 2017-04-30 21:15:43.000000000 +0100 +@@ -232,7 +232,7 @@ HandshakeManager::receive_succeeded(Hand + + if (!download->info()->is_active()) + reason = e_handshake_inactive_download; +- else if (download->file_list()->is_done() && handshake->bitfield()->is_all_set()) ++ else if (download->file_list()->data()->is_partially_done() && handshake->bitfield()->is_all_set()) + reason = e_handshake_unwanted_connection; + else + reason = e_handshake_duplicate; +--- a/src/protocol/peer_connection_base.cc 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/protocol/peer_connection_base.cc 2017-04-30 21:15:43.000000000 +0100 +@@ -197,7 +197,7 @@ PeerConnectionBase::initialize(DownloadM + + m_peerChunks.download_cache()->clear(); + +- if (!m_download->file_list()->is_done()) { ++ if (!m_download->file_list()->data()->is_partially_done()) { + m_sendInterested = true; + m_downInterested = true; + } +--- a/src/protocol/peer_connection_leech.cc 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/protocol/peer_connection_leech.cc 2017-04-30 21:15:43.000000000 +0100 +@@ -691,7 +691,7 @@ PeerConnection<type>::read_have_chunk(ui + m_download->choke_group()->up_queue()->set_not_queued(this, &m_upChoke); + } + +- if (type != Download::CONNECTION_LEECH || m_download->file_list()->is_done()) ++ if (type != Download::CONNECTION_LEECH || m_download->file_list()->data()->is_partially_done()) + return; + + if (is_down_interested()) { +--- a/src/torrent/data/file_list.cc 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/torrent/data/file_list.cc 2017-04-30 21:15:43.000000000 +0100 +@@ -86,6 +86,7 @@ FileList::FileList() : + m_isOpen(false), + + m_torrentSize(0), ++ m_selectedSize(0), + m_chunkSize(0), + m_maxFileSize(~uint64_t()) { + } +@@ -98,6 +99,7 @@ FileList::~FileList() { + + base_type::clear(); + m_torrentSize = 0; ++ m_selectedSize = 0; + } + + bool +@@ -193,6 +195,65 @@ FileList::set_max_file_size(uint64_t siz + m_maxFileSize = size; + } + ++// This function should be called from receive_update_priorities(). ++// It offloads continous calculation by updating the m_selectedSize property. ++// Its purpose is to replace size_bytes() with selected_size_bytes() ++// by taking into account partial downloads. ++void ++FileList::set_selected_size_bytes(uint64_t bytes) { ++ if (bytes > 0) { ++ m_selectedSize = bytes; ++ return; ++ } ++ ++ if (is_done()) { ++ m_selectedSize = m_torrentSize; ++ return; ++ } ++ ++ uint64_t completedBytes = completed_bytes(); ++ ++ if (data()->is_partially_done()) { ++ m_selectedSize = completedBytes; ++ return; ++ } ++ ++ uint32_t selectedSizeChunks = 0; ++ uint32_t prevChunk = -1; ++ bool areAllFilesSelected = true; ++ bool isLastFileSelected = false; ++ ++ for (FileList::const_iterator itr = begin(), last = end(); itr != last; itr++) { ++ ++ if ((*itr)->priority() != PRIORITY_OFF) { ++ selectedSizeChunks += (*itr)->size_chunks() - ((*itr)->range_first() == prevChunk ? 1 : 0); ++ prevChunk = (*itr)->range_second() - 1; ++ ++ if (itr == end() - 1) ++ isLastFileSelected = true; ++ } else { ++ areAllFilesSelected = false; ++ } ++ ++ } ++ ++ if (areAllFilesSelected) { ++ m_selectedSize = m_torrentSize; ++ return; ++ } ++ ++ uint64_t selectedSizeBytes = (uint64_t)selectedSizeChunks * (uint64_t)m_chunkSize; ++ ++ // Dealing with size of last chunk as it's usually smaller than the rest. ++ uint64_t remainder = m_torrentSize % (uint64_t)m_chunkSize; ++ ++ if (isLastFileSelected && remainder != 0) ++ selectedSizeBytes = selectedSizeBytes - (uint64_t)m_chunkSize + remainder; ++ ++ // Set completed bytes if some files (e.g. all of them) were set to Off later. ++ m_selectedSize = (selectedSizeBytes < completedBytes ? completedBytes : selectedSizeBytes); ++} ++ + // This function should really ensure that we arn't dealing files + // spread over multiple mount-points. + uint64_t +@@ -376,6 +432,7 @@ FileList::initialize(uint64_t torrentSiz + + m_chunkSize = chunkSize; + m_torrentSize = torrentSize; ++ m_selectedSize = torrentSize; + m_rootDir = "."; + + m_data.mutable_completed_bitfield()->set_size_bits((size_bytes() + chunk_size() - 1) / chunk_size()); +@@ -725,6 +782,7 @@ FileList::reset_filesize(int64_t size) { + close(); + m_chunkSize = size; + m_torrentSize = size; ++ m_selectedSize = size; + (*begin())->set_size_bytes(size); + (*begin())->set_range(m_chunkSize); + +--- a/src/torrent/data/file_list.h 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/torrent/data/file_list.h 2017-04-30 21:15:43.000000000 +0100 +@@ -109,6 +109,9 @@ public: + uint64_t size_bytes() const { return m_torrentSize; } + uint32_t size_chunks() const { return bitfield()->size_bits(); } + ++ uint64_t selected_size_bytes() const { return m_selectedSize; } ++ void set_selected_size_bytes(uint64_t bytes = 0); ++ + uint32_t completed_chunks() const { return bitfield()->size_set(); } + uint64_t completed_bytes() const; + uint64_t left_bytes() const; +@@ -187,6 +190,7 @@ private: + uint64_t m_torrentSize; + uint32_t m_chunkSize; + uint64_t m_maxFileSize; ++ uint64_t m_selectedSize; + + std::string m_rootDir; + +--- a/src/torrent/download.cc 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/torrent/download.cc 2017-04-30 21:15:43.000000000 +0100 +@@ -565,32 +565,6 @@ Download::set_connection_type(Connection + m_ptr->set_connection_type(t); + } + +-Download::HeuristicType +-Download::upload_choke_heuristic() const { +- return (Download::HeuristicType)m_ptr->main()->choke_group()->up_queue()->heuristics(); +-} +- +-void +-Download::set_upload_choke_heuristic(HeuristicType t) { +- if ((choke_queue::heuristics_enum)t >= choke_queue::HEURISTICS_MAX_SIZE) +- throw input_error("Invalid heuristics value."); +- +- m_ptr->main()->choke_group()->up_queue()->set_heuristics((choke_queue::heuristics_enum)t); +-} +- +-Download::HeuristicType +-Download::download_choke_heuristic() const { +- return (Download::HeuristicType)m_ptr->main()->choke_group()->down_queue()->heuristics(); +-} +- +-void +-Download::set_download_choke_heuristic(HeuristicType t) { +- if ((choke_queue::heuristics_enum)t >= choke_queue::HEURISTICS_MAX_SIZE) +- throw input_error("Invalid heuristics value."); +- +- m_ptr->main()->choke_group()->down_queue()->set_heuristics((choke_queue::heuristics_enum)t); +-} +- + void + Download::update_priorities() { + m_ptr->receive_update_priorities(); +--- a/src/torrent/download.h 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/torrent/download.h 2017-04-30 21:15:43.000000000 +0100 +@@ -183,15 +183,6 @@ public: + ConnectionType connection_type() const; + void set_connection_type(ConnectionType t); + +- typedef enum { +- } HeuristicType; +- +- HeuristicType upload_choke_heuristic() const; +- void set_upload_choke_heuristic(HeuristicType t); +- +- HeuristicType download_choke_heuristic() const; +- void set_download_choke_heuristic(HeuristicType t); +- + // Call this when you want the modifications of the download priorities + // in the entries to take effect. It is slightly expensive as it rechecks + // all the peer bitfields to see if we are still interested. +--- a/src/torrent/peer/connection_list.cc 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/torrent/peer/connection_list.cc 2017-04-30 21:15:43.000000000 +0100 +@@ -79,7 +79,7 @@ ConnectionList::clear() { + + bool + ConnectionList::want_connection(PeerInfo* p, Bitfield* bitfield) { +- if (m_download->file_list()->is_done() || m_download->initial_seeding() != NULL) ++ if (m_download->file_list()->data()->is_partially_done() || m_download->initial_seeding() != NULL) + return !bitfield->is_all_set(); + + if (!m_download->info()->is_accepting_seeders()) +--- a/src/torrent/utils/resume.cc 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/torrent/utils/resume.cc 2017-04-30 21:15:43.000000000 +0100 +@@ -254,10 +254,7 @@ resume_save_progress(Download download, + + // } else if ((*listItr)->completed_chunks() == (*listItr)->size_chunks()) { + +- } else if (fileList->bitfield()->is_all_set()) { +- // Currently only checking if we're finished. This needs to be +- // smarter when it comes to downloading partial torrents, etc. +- ++ } else if (download.data()->is_partially_done()) { + // This assumes the syncs are properly called before + // resume_save_progress gets called after finishing a torrent. + filesItr->insert_key("mtime", (int64_t)fs.modified_time()); diff --git a/backport_lt_all_02-honor_system_file_allocate_fix.patch b/backport_lt_all_02-honor_system_file_allocate_fix.patch new file mode 100644 index 000000000000..0029cdc374a7 --- /dev/null +++ b/backport_lt_all_02-honor_system_file_allocate_fix.patch @@ -0,0 +1,340 @@ +--- a/src/download/download_wrapper.cc 2017-04-30 21:25:15.511379804 +0100 ++++ a/src/download/download_wrapper.cc 2017-04-30 22:10:12.910100074 +0100 +@@ -46,6 +46,7 @@ + #include "protocol/handshake_manager.h" + #include "protocol/peer_connection_base.h" + #include "torrent/exceptions.h" ++#include "torrent/download.h" + #include "torrent/object.h" + #include "torrent/tracker_list.h" + #include "torrent/data/file.h" +@@ -103,7 +104,7 @@ DownloadWrapper::~DownloadWrapper() { + } + + void +-DownloadWrapper::initialize(const std::string& hash, const std::string& id) { ++DownloadWrapper::initialize(const std::string& hash, const std::string& id, int flags) { + char hashObfuscated[20]; + sha1_salt("req2", 4, hash.c_str(), hash.length(), hashObfuscated); + +@@ -124,7 +125,7 @@ DownloadWrapper::initialize(const std::s + + // Connect various signals and slots. + m_hashChecker->slot_check_chunk() = std::bind(&DownloadWrapper::check_chunk_hash, this, std::placeholders::_1); +- m_hashChecker->delay_checked().slot() = std::bind(&DownloadWrapper::receive_initial_hash, this); ++ m_hashChecker->delay_checked().slot() = std::bind(&DownloadWrapper::receive_initial_hash, this, flags); + } + + void +@@ -156,7 +157,7 @@ DownloadWrapper::is_stopped() const { + } + + void +-DownloadWrapper::receive_initial_hash() { ++DownloadWrapper::receive_initial_hash(int flags) { + if (info()->is_active()) + throw internal_error("DownloadWrapper::receive_initial_hash() but we're in a bad state."); + +@@ -172,7 +173,7 @@ DownloadWrapper::receive_initial_hash() + // Initialize the ChunkSelector here so that no chunks will be + // marked by HashTorrent that are not accounted for. + m_main->chunk_selector()->initialize(m_main->chunk_statistics()); +- receive_update_priorities(); ++ receive_update_priorities(flags); + } + + if (data()->slot_initial_hash()) +@@ -325,7 +326,7 @@ DownloadWrapper::receive_tick(uint32_t t + } + + void +-DownloadWrapper::receive_update_priorities() { ++DownloadWrapper::receive_update_priorities(int flags) { + if (m_main->chunk_selector()->empty()) { + file_list()->set_selected_size_bytes(); + return; +@@ -335,9 +336,15 @@ DownloadWrapper::receive_update_prioriti + data()->mutable_normal_priority()->clear(); + + for (FileList::iterator itr = m_main->file_list()->begin(); itr != m_main->file_list()->end(); ++itr) { ++ // Unset fallocate flag by default. ++ (*itr)->unset_flags(File::flag_fallocate); ++ + switch ((*itr)->priority()) { + case PRIORITY_NORMAL: + { ++ if (flags & torrent::Download::open_enable_fallocate) ++ (*itr)->set_flags(File::flag_fallocate); ++ + File::range_type range = (*itr)->range(); + + if ((*itr)->has_flags(File::flag_prioritize_first) && range.first != range.second) { +@@ -354,6 +361,9 @@ DownloadWrapper::receive_update_prioriti + break; + } + case PRIORITY_HIGH: ++ if (flags & torrent::Download::open_enable_fallocate) ++ (*itr)->set_flags(File::flag_fallocate); ++ + data()->mutable_high_priority()->insert((*itr)->range().first, (*itr)->range().second); + break; + default: +--- a/src/download/download_wrapper.h 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/download/download_wrapper.h 2017-04-30 22:06:19.000000000 +0100 +@@ -64,7 +64,7 @@ public: + ChunkList* chunk_list() { return m_main->chunk_list(); } + + // Initialize hash checker and various download stuff. +- void initialize(const std::string& hash, const std::string& id); ++ void initialize(const std::string& hash, const std::string& id, int flags = 0); + + void close(); + +@@ -91,7 +91,7 @@ public: + // Internal: + // + +- void receive_initial_hash(); ++ void receive_initial_hash(int flags = 0); + void receive_hash_done(ChunkHandle handle, const char* hash); + + void check_chunk_hash(ChunkHandle handle); +@@ -102,7 +102,7 @@ public: + + void receive_tick(uint32_t ticks); + +- void receive_update_priorities(); ++ void receive_update_priorities(int flags = 0); + + private: + DownloadWrapper(const DownloadWrapper&); +--- a/src/torrent/data/file.cc 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/torrent/data/file.cc 2017-04-30 22:06:19.000000000 +0100 +@@ -184,6 +184,7 @@ File::resize_file() { + if (m_flags & flag_fallocate) { + flags |= SocketFile::flag_fallocate; + flags |= SocketFile::flag_fallocate_blocking; ++ m_flags &= ~flag_fallocate; + } + + return SocketFile(m_fd).set_size(m_size, flags); +--- a/src/torrent/data/file.h 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/torrent/data/file.h 2017-04-30 22:06:19.000000000 +0100 +@@ -68,8 +68,11 @@ public: + + bool is_create_queued() const { return m_flags & flag_create_queued; } + bool is_resize_queued() const { return m_flags & flag_resize_queued; } ++ bool is_fallocatable() const { return m_flags & flag_fallocate; } + bool is_previously_created() const { return m_flags & flag_previously_created; } + ++ bool is_fallocatable_file() { return has_flags(flag_resize_queued) && has_flags(flag_fallocate); } ++ + bool has_flags(int flags) { return m_flags & flags; } + + void set_flags(int flags); +--- a/src/torrent/data/file_list.cc 2017-04-30 21:15:43.000000000 +0100 ++++ a/src/torrent/data/file_list.cc 2017-04-30 22:06:19.000000000 +0100 +@@ -259,9 +259,9 @@ FileList::set_selected_size_bytes() { + uint64_t + FileList::free_diskspace() const { + uint64_t freeDiskspace = std::numeric_limits<uint64_t>::max(); ++ rak::fs_stat stat; + + for (path_list::const_iterator itr = m_indirectLinks.begin(), last = m_indirectLinks.end(); itr != last; ++itr) { +- rak::fs_stat stat; + + if (!stat.update(*itr)) + continue; +@@ -269,9 +269,74 @@ FileList::free_diskspace() const { + freeDiskspace = std::min<uint64_t>(freeDiskspace, stat.bytes_avail()); + } + ++ // Check the base directory of download if files haven't been created yet ++ if (freeDiskspace == std::numeric_limits<uint64_t>::max()) { ++ std::string dirPath = is_multi_file() ? m_rootDir.substr(0, m_rootDir.find_last_of("\\/")) : m_rootDir; ++ ++ if (stat.update(dirPath)) ++ freeDiskspace = std::min<uint64_t>(freeDiskspace, stat.bytes_avail()); ++ } ++ + return freeDiskspace != std::numeric_limits<uint64_t>::max() ? freeDiskspace : 0; + } + ++uint64_t ++FileList::allocatable_size_bytes() const { ++ uint64_t allocatableSizeBytes = 0; ++ ++ if (data()->is_partially_done()) ++ return allocatableSizeBytes; ++ ++ uint32_t allocatableSizeChunks = 0; ++ uint32_t prevChunk = -1; ++ bool areAllFilesAllocatable = true; ++ bool isLastFileAllocatable = false; ++ ++ for (FileList::const_iterator itr = begin(), last = end(); itr != last; itr++) { ++ ++ // Checks flag_fallocate and flag_resize_queued as well, it will take care of restarting client. ++ if ((*itr)->is_fallocatable_file()) { ++ allocatableSizeChunks += (*itr)->size_chunks() - ((*itr)->range_first() == prevChunk ? 1 : 0); ++ prevChunk = (*itr)->range_second() - 1; ++ ++ if (itr == end() - 1) ++ isLastFileAllocatable = true; ++ } else { ++ areAllFilesAllocatable = false; ++ } ++ ++ } ++ ++ if (areAllFilesAllocatable) ++ return m_torrentSize; ++ ++ allocatableSizeBytes = (uint64_t)allocatableSizeChunks * (uint64_t)m_chunkSize; ++ ++ // Dealing with size of last chunk as it's usually smaller than the rest. ++ uint64_t reminder = m_torrentSize % (uint64_t)m_chunkSize; ++ ++ if (isLastFileAllocatable && reminder != 0) ++ allocatableSizeBytes = allocatableSizeBytes - (uint64_t)m_chunkSize + reminder; ++ ++ return allocatableSizeBytes; ++} ++ ++bool ++FileList::is_enough_diskspace() const { ++ uint64_t allocatable_size = allocatable_size_bytes(); ++ ++ if (allocatable_size > 0) { ++ uint64_t free_disk_space = free_diskspace(); ++ ++ if (free_disk_space < allocatable_size) { ++ LT_LOG_FL(INFO, "File allocation is set and not enough disk space to start torrent: allocatable size:%i free space:%i", allocatable_size, free_disk_space); ++ return false; ++ } ++ } ++ ++ return true; ++} ++ + FileList::iterator_range + FileList::split(iterator position, split_type* first, split_type* last) { + if (is_open()) +@@ -642,7 +707,12 @@ FileList::open_file(File* node, const Pa + return false; + } + +- return node->prepare(MemoryChunk::prot_read, 0); ++ // File allocation will be done if fallocate flag is set, ++ // create zero-length file otherwise. ++ if (node->has_flags(File::flag_fallocate)) ++ return node->prepare(MemoryChunk::prot_write, 0); ++ else ++ return node->prepare(MemoryChunk::prot_read, 0); + } + + MemoryChunk +--- a/src/torrent/data/file_list.h 2017-04-30 21:15:43.000000000 +0100 ++++ a/src/torrent/data/file_list.h 2017-04-30 22:06:19.000000000 +0100 +@@ -107,6 +107,7 @@ public: + + size_t size_files() const { return base_type::size(); } + uint64_t size_bytes() const { return m_torrentSize; } ++ uint64_t allocatable_size_bytes() const; + uint32_t size_chunks() const { return bitfield()->size_bits(); } + + uint64_t selected_size_bytes() const { return m_selectedSize; } +@@ -135,6 +136,10 @@ public: + // of free diskspace will be returned. + uint64_t free_diskspace() const; + ++ // Determines whether there is enough disk space for fallocating ++ // selected files. ++ bool is_enough_diskspace() const; ++ + // List of directories in the torrent that might be on different + // volumes as they are links, including the root directory. Used by + // 'free_diskspace()'. +--- a/src/torrent/download.cc 2017-04-30 21:15:43.000000000 +0100 ++++ a/src/torrent/download.cc 2017-05-14 21:28:05.138916583 +0100 +@@ -137,7 +137,13 @@ Download::start(int flags) { + throw internal_error("Tried to start a download with empty bitfield."); + + if (info->is_active()) +- return; ++ throw internal_error("Tried to start an already started download."); ++ ++ // Don't start the download if there's not enough disk space for it ++ // when the open_enable_fallocate was set and at least one of the ++ // files has fallocate flag (libtorrent would crash otherwise) ++ if (flags & open_enable_fallocate && !m_ptr->main()->file_list()->is_enough_diskspace()) ++ throw internal_error("Tried to start a download with not enough disk space for it."); + + LT_LOG_THIS(INFO, "Starting torrent: flags:%0x.", flags); + +@@ -145,9 +151,9 @@ Download::start(int flags) { + + // file_list()->open(flags); + +- // If the FileList::open_no_create flag was not set, our new +- // behavior is to create all zero-length files with +- // flag_queued_create set. ++ // If the open_enable_fallocate or the FileList::open_no_create ++ // flag was not set, then create all zero-length files with ++ // flag_create_queued set. + file_list()->open(flags & ~FileList::open_no_create); + + if (m_ptr->connection_type() == CONNECTION_INITIAL_SEED) { +@@ -566,8 +572,8 @@ Download::set_connection_type(Connection + } + + void +-Download::update_priorities() { +- m_ptr->receive_update_priorities(); ++Download::update_priorities(int flags) { ++ m_ptr->receive_update_priorities(flags); + } + + void +--- a/src/torrent/download.h 2017-04-30 21:15:43.000000000 +0100 ++++ a/src/torrent/download.h 2017-05-14 21:25:52.249636506 +0100 +@@ -186,7 +186,7 @@ public: + // Call this when you want the modifications of the download priorities + // in the entries to take effect. It is slightly expensive as it rechecks + // all the peer bitfields to see if we are still interested. +- void update_priorities(); ++ void update_priorities(int flags = 0); + + void add_peer(const sockaddr* addr, int port); + +--- a/src/torrent/torrent.cc 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/torrent/torrent.cc 2017-04-30 22:06:19.000000000 +0100 +@@ -164,7 +164,7 @@ encoding_list() { + } + + Download +-download_add(Object* object) { ++download_add(Object* object, int flags) { + std::auto_ptr<DownloadWrapper> download(new DownloadWrapper); + + DownloadConstructor ctor; +@@ -190,7 +190,7 @@ download_add(Object* object) { + } + + download->set_hash_queue(manager->hash_queue()); +- download->initialize(infoHash, PEER_NAME + rak::generate_random<std::string>(20 - std::string(PEER_NAME).size())); ++ download->initialize(infoHash, PEER_NAME + rak::generate_random<std::string>(20 - std::string(PEER_NAME).size()), flags); + + // Add trackers, etc, after setting the info hash so that log + // entries look sane. +--- a/src/torrent/torrent.h 2016-12-12 08:49:18.000000000 +0000 ++++ a/src/torrent/torrent.h 2017-04-30 22:06:19.000000000 +0100 +@@ -93,7 +93,7 @@ EncodingList* encoding_list() LIBT + // is done by 'download_remove'. + // + // Might consider redesigning that... +-Download download_add(Object* s) LIBTORRENT_EXPORT; ++Download download_add(Object* s, int flags = 0) LIBTORRENT_EXPORT; + void download_remove(Download d) LIBTORRENT_EXPORT; + + // Add all downloads to dlist. The client is responsible for clearing diff --git a/lt-ps_all_02-better-bencode-errors_all.patch b/lt-ps_all_02-better-bencode-errors_all.patch new file mode 100644 index 000000000000..6cfd192b70cf --- /dev/null +++ b/lt-ps_all_02-better-bencode-errors_all.patch @@ -0,0 +1,40 @@ +diff --git a/src/torrent/object_raw_bencode.h b/src/torrent/object_raw_bencode.h +index 5e82fff8..4f49386a 100644 +--- a/src/torrent/object_raw_bencode.h ++++ b/src/torrent/object_raw_bencode.h +@@ -156,7 +156,7 @@ public: + inline std::string + raw_bencode::as_value_string() const { + if (!is_value()) +- throw bencode_error("Wrong object type."); ++ throw bencode_error("Wrong object type - not a value."); + + return std::string(data() + 1, size() - 2); + } +@@ -164,7 +164,7 @@ raw_bencode::as_value_string() const { + inline raw_string + raw_bencode::as_raw_string() const { + if (!is_raw_string()) +- throw bencode_error("Wrong object type."); ++ throw bencode_error("Wrong object type - not a raw string."); + + const_iterator itr = std::find(begin(), end(), ':'); + +@@ -177,7 +177,7 @@ raw_bencode::as_raw_string() const { + inline raw_list + raw_bencode::as_raw_list() const { + if (!is_raw_list()) +- throw bencode_error("Wrong object type."); ++ throw bencode_error("Wrong object type - not a raw list."); + + return raw_list(m_data + 1, m_size - 2); + } +@@ -185,7 +185,7 @@ raw_bencode::as_raw_list() const { + inline raw_map + raw_bencode::as_raw_map() const { + if (!is_raw_map()) +- throw bencode_error("Wrong object type."); ++ throw bencode_error("Wrong object type - not a raw map."); + + return raw_map(m_data + 1, m_size - 2); + } |