diff --git a/docs/manual.html b/docs/manual.html index 1534e6c3e..a6b364b78 100755 --- a/docs/manual.html +++ b/docs/manual.html @@ -47,71 +47,72 @@
save_path() returns the path that was given to add_torrent() when this torrent was started.
+++bool move_storage(boost::filsystem::path const& save_path); ++
Moves the file(s) that this torrent are currently seeding from or downloading to. This +operation will only have the desired effect if the given save_path is located on +the same drive as the original save path. If the move operation fails, this function +returns false, otherwise true. Post condition for successful operation is: +save_path() == save_path.
+diff --git a/docs/manual.rst b/docs/manual.rst index 7ca2c1f6b..a6fe60a68 100755 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -768,6 +768,7 @@ Its declaration looks like this:: bool is_paused() const; boost::filsystem::path save_path() const; + bool move_storage(boost::filesystem::path const& save_path); sha1_hash info_hash() const; @@ -791,6 +792,19 @@ save_path() ``save_path()`` returns the path that was given to `add_torrent()`_ when this torrent was started. +move_storage() +-------------- + + :: + + bool move_storage(boost::filsystem::path const& save_path); + +Moves the file(s) that this torrent are currently seeding from or downloading to. This +operation will only have the desired effect if the given ``save_path`` is located on +the same drive as the original save path. If the move operation fails, this function +returns false, otherwise true. Post condition for successful operation is: +``save_path() == save_path``. + force_reannounce() ------------------ diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 9e7d6acb2..9d5be5dee 100755 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -39,7 +39,6 @@ POSSIBILITY OF SUCH DAMAGE. #pragma warning(push, 1) #endif -#include#include #include #include @@ -244,7 +243,7 @@ int main(int argc, char* argv[]) session ses(fingerprint("LT", 0, 1, 0, 0)); ses.listen_on(std::make_pair(6881, 6889)); - ses.set_upload_rate_limit(1000); +// ses.set_upload_rate_limit(1000); // ses.set_download_rate_limit(50000); ses.set_http_settings(settings); ses.set_severity_level(alert::debug); @@ -369,6 +368,10 @@ int main(int argc, char* argv[]) p->handle.set_max_connections(10); p->handle.set_max_uploads(5); p->handle.set_upload_limit(10000); + + // all finished downloades are + // moved into this directory + p->handle.move_storage("finished"); events.push_back( p->handle.get_torrent_info().name() + ": " + a->msg()); } @@ -445,42 +448,40 @@ int main(int argc, char* argv[]) out << "next announce: " << boost::posix_time::to_simple_string(t) << "\n"; out << "tracker: " << s.current_tracker << "\n"; -// out << "___________________________________\n"; + out << "___________________________________\n"; + + out << " down up q r flags block\n"; for (std::vector ::iterator i = peers.begin(); i != peers.end(); ++i) { - out << "d:" << add_suffix(i->down_speed) << "/s " + out.fill(' '); + out.width(2); + out << add_suffix(i->down_speed) << "/s " // << "(" << add_suffix(i->total_download) << ") " - << "u:" << add_suffix(i->up_speed) << "/s " + << add_suffix(i->up_speed) << "/s " // << "(" << add_suffix(i->total_upload) << ") " // << "ul:" << add_suffix(i->upload_limit) << "/s " // << "uc:" << add_suffix(i->upload_ceiling) << "/s " // << "df:" << ratio(i->total_download, i->total_upload) << " " - << "q:" << i->download_queue_length << " " - << "r:" << i->upload_queue_length << " " - << "f:" + << i->download_queue_length << " " + << i->upload_queue_length << " " << static_cast ((i->flags & peer_info::interesting)?"I":"_") << static_cast ((i->flags & peer_info::choked)?"C":"_") << static_cast ((i->flags & peer_info::remote_interested)?"i":"_") << static_cast ((i->flags & peer_info::remote_choked)?"c":"_") << static_cast ((i->flags & peer_info::supports_extensions)?"e":"_") - << static_cast ((i->flags & peer_info::local_connection)?"l":"r") - << "\n"; + << static_cast ((i->flags & peer_info::local_connection)?"l":"r"); if (i->downloading_piece_index >= 0) { - out.width(5); - out.fill('0'); - out << i->downloading_piece_index << ";" - << i->downloading_block_index << ": "; - out << progress_bar( + out << " " << progress_bar( i->downloading_progress / static_cast (i->downloading_total) - , 50); - out << "\n"; + , 15); } + out << "\n"; } out << "___________________________________\n"; diff --git a/include/libtorrent/storage.hpp b/include/libtorrent/storage.hpp index eef7ff2d9..792a0f591 100755 --- a/include/libtorrent/storage.hpp +++ b/include/libtorrent/storage.hpp @@ -93,6 +93,8 @@ namespace libtorrent // may throw file_error if storage for slot hasn't been allocated void write(const char* buf, int slot, int offset, int size); + bool move_storage(boost::filesystem::path const& save_path); + #ifndef NDEBUG // overwrites some slots with the // contents of others @@ -140,7 +142,8 @@ namespace libtorrent , int offset , int size); - const boost::filesystem::path& save_path() const; + boost::filesystem::path const& save_path() const; + bool move_storage(boost::filesystem::path const&); // fills the vector that maps all allocated // slots to the piece that is stored (or diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 65cb0dd26..f5d0ee674 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -324,6 +324,7 @@ namespace libtorrent void set_upload_limit(int limit); void set_download_limit(int limit); + bool move_storage(boost::filesystem::path const& save_path); bool valid_metadata() const { return m_storage.get() != 0; } std::vector const& metadata() const { return m_metadata; } diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index d774703d6..f8f0fdd0b 100755 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -207,6 +207,9 @@ namespace libtorrent void set_tracker_login(std::string const& name, std::string const& password); + // post condition: save_path() == save_path if true is returned + bool move_storage(boost::filesystem::path const& save_path); + const sha1_hash& info_hash() const { return m_info_hash; } diff --git a/src/identify_client.cpp b/src/identify_client.cpp index 65be8d944..92eb60b7a 100755 --- a/src/identify_client.cpp +++ b/src/identify_client.cpp @@ -58,6 +58,12 @@ namespace using namespace libtorrent; + int decode_digit(char c) + { + if (std::isdigit(c)) return c - '0'; + return std::toupper(c) - 'A' + 10; + } + // takes a peer id and returns a valid boost::optional // object if the peer id matched the azureus style encoding // the returned fingerprint contains information about the @@ -77,20 +83,20 @@ namespace ++i; } - if (*i < '0') return boost::optional (); - ret.major_version = *i - '0'; + if (!std::isalnum(*i)) return boost::optional (); + ret.major_version = decode_digit(*i); ++i; - if (*i < '0') return boost::optional (); - ret.minor_version = *i - '0'; + if (!std::isalnum(*i)) return boost::optional (); + ret.minor_version = decode_digit(*i); ++i; - if (*i < '0') return boost::optional (); - ret.revision_version = *i - '0'; + if (!std::isalnum(*i)) return boost::optional (); + ret.revision_version = decode_digit(*i); ++i; - if (*i < '0') return boost::optional (); - ret.tag_version = *i - '0'; + if (!std::isalnum(*i)) return boost::optional (); + ret.tag_version = decode_digit(*i); ++i; if (*i != '-') return boost::optional (); @@ -105,23 +111,23 @@ namespace fingerprint ret("..", 0, 0, 0, 0); peer_id::const_iterator i = id.begin(); - if (*i < '0') return boost::optional (); + if (!std::isalnum(*i)) return boost::optional (); ret.id[0] = *i; ret.id[1] = 0; ++i; if (std::equal(id.begin()+4, id.begin()+8, "----")) { - if (*i < '0') return boost::optional (); - ret.major_version = *i - '0'; + if (!std::isalnum(*i)) return boost::optional (); + ret.major_version = decode_digit(*i); ++i; - if (*i < '0') return boost::optional (); - ret.minor_version = *i - '0'; + if (!std::isalnum(*i)) return boost::optional (); + ret.minor_version = decode_digit(*i); ++i; - if (*i < '0') return boost::optional (); - ret.revision_version = *i - '0'; + if (!std::isalnum(*i)) return boost::optional (); + ret.revision_version = decode_digit(*i); } else if (id[8] == 0) { @@ -139,7 +145,6 @@ namespace else return boost::optional (); - ret.tag_version = 0; return boost::optional (ret); } @@ -156,22 +161,22 @@ namespace ret.id[1] = 0; ++i; - if (*i < '0') return boost::optional (); - ret.major_version = *i - '0'; + if (!std::isalnum(*i)) return boost::optional (); + ret.major_version = decode_digit(*i); ++i; if (*i != '-') return boost::optional (); ++i; - if (*i < '0') return boost::optional (); - ret.minor_version = *i - '0'; + if (!std::isalnum(*i)) return boost::optional (); + ret.minor_version = decode_digit(*i); ++i; if (*i != '-') return boost::optional (); ++i; - if (*i < '0') return boost::optional (); - ret.revision_version = *i - '0'; + if (!std::isalnum(*i)) return boost::optional (); + ret.revision_version = decode_digit(*i); ++i; if (!std::equal(i, i+1, "--")) return boost::optional (); @@ -190,7 +195,7 @@ namespace libtorrent peer_id::const_iterator PID = p.begin(); boost::optional f; - if (p.is_all_zeros()) return "Unkown"; + if (p.is_all_zeros()) return "Unknown"; // look for azureus style id f = parse_az_style(p); @@ -338,7 +343,10 @@ namespace libtorrent return "SimpleBT"; } - if (std::equal(PID, PID + 7, "turbobt")) + if (std::equal(PID, PID + 7, "turbobt") + && std::isalnum(PID[8]) + && std::isalnum(PID[10]) + && std::isalnum(PID[12])) { std::stringstream s; s << "TurboBT " << PID[8] << "." << PID[10] << "." << PID[12]; diff --git a/src/session.cpp b/src/session.cpp index 43014e47e..a1f442a05 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -127,6 +127,12 @@ namespace libtorrent { namespace detail m_ses.m_torrents.insert( std::make_pair(t->info_hash, t->torrent_ptr)).first; + if (t->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info)) + { + m_ses.m_alerts.post_alert(torrent_finished_alert( + t->torrent_ptr->get_handle() + , "torrent is complete")); + } peer_id id; std::fill(id.begin(), id.end(), 0); @@ -197,7 +203,7 @@ namespace libtorrent { namespace detail m_key = rand() + (rand() << 15) + (rand() << 30); std::string print = cl_fprint.to_string(); - assert(print.length() == 8); + assert(print.length() <= 20); // the client's fingerprint std::copy( diff --git a/src/storage.cpp b/src/storage.cpp index d5a36a834..28524332a 100755 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include #include @@ -68,39 +69,6 @@ namespace std } #endif -/* -namespace -{ - struct lazy_hash - { - mutable libtorrent::sha1_hash digest; - mutable libtorrent::hasher h; - mutable const char* data; - std::size_t size; - - lazy_hash(const char* data_, std::size_t size_) - : data(data_) - , size(size_) - { - assert(data_ != 0); - assert(size_ > 0); - } - - const libtorrent::sha1_hash& get() const - { - if (data) - { - h.update(data, size); - digest = h.final(); - data = 0; - } - return digest; - } - }; - -} // namespace unnamed -*/ - namespace fs = boost::filesystem; namespace @@ -113,9 +81,9 @@ namespace log.flush(); } - boost::filesystem::path get_filename( + fs::path get_filename( libtorrent::torrent_info const& t - , boost::filesystem::path const& p) + , fs::path const& p) { assert(t.num_files() > 0); if (t.num_files() == 1) @@ -130,7 +98,7 @@ namespace libtorrent std::vector get_filesizes( const torrent_info& t - , const boost::filesystem::path& p) + , const fs::path& p) { std::vector sizes; for (torrent_info::file_iterator i = t.begin_files(); @@ -155,7 +123,7 @@ namespace libtorrent bool match_filesizes( const torrent_info& t - , const boost::filesystem::path& p + , const fs::path& p , const std::vector & sizes) { if ((int)sizes.size() != t.num_files()) return false; @@ -232,7 +200,7 @@ namespace libtorrent {} torrent_info const& info; - const boost::filesystem::path save_path; + fs::path save_path; }; storage::storage(const torrent_info& info, const fs::path& path) @@ -246,6 +214,38 @@ namespace libtorrent m_pimpl.swap(other.m_pimpl); } + // returns true on success + bool storage::move_storage(fs::path const& save_path) + { + std::string old_path; + std::string new_path; + + if (m_pimpl->info.num_files() == 1) + { + old_path = (m_pimpl->save_path / m_pimpl->info.begin_files()->path) + .native_file_string(); + new_path = (save_path / m_pimpl->info.begin_files()->path) + .native_file_string(); + } + else + { + assert(m_pimpl->info.num_files() > 1); + old_path = (m_pimpl->save_path / m_pimpl->info.name()) + .native_directory_string(); + new_path = (save_path / m_pimpl->info.name()) + .native_directory_string(); + } + + fs::create_directory(save_path); + int ret = std::rename(old_path.c_str(), new_path.c_str()); + if (ret == 0) + { + m_pimpl->save_path = save_path; + return true; + } + return false; + } + #ifndef NDEBUG void storage::shuffle() @@ -489,7 +489,7 @@ namespace libtorrent impl( const torrent_info& info - , const boost::filesystem::path& path); + , const fs::path& path); void check_pieces( boost::mutex& mutex @@ -517,9 +517,19 @@ namespace libtorrent , int offset , int size); - const boost::filesystem::path& save_path() const + fs::path const& save_path() const { return m_save_path; } + bool move_storage(fs::path const& save_path) + { + if (m_storage.move_storage(save_path)) + { + m_save_path = save_path; + return true; + } + return false; + } + void export_piece_map(std::vector & p) const; private: @@ -570,7 +580,7 @@ namespace libtorrent // it can either be 'unassigned' or 'unallocated' std::vector m_slot_to_piece; - boost::filesystem::path m_save_path; + fs::path m_save_path; mutable boost::recursive_mutex m_mutex; @@ -1397,7 +1407,7 @@ namespace libtorrent INVARIANT_CHECK; - namespace fs = boost::filesystem; + namespace fs = fs; assert(!m_unallocated_slots.empty()); @@ -1436,11 +1446,16 @@ namespace libtorrent m_pimpl->allocate_slots(num_slots); } - const boost::filesystem::path& piece_manager::save_path() const + fs::path const& piece_manager::save_path() const { return m_pimpl->save_path(); } + bool piece_manager::move_storage(fs::path const& save_path) + { + return m_pimpl->move_storage(save_path); + } + #ifndef NDEBUG void piece_manager::impl::check_invariant() const { diff --git a/src/torrent.cpp b/src/torrent.cpp index 805ede47f..7de5f19f7 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -665,6 +665,11 @@ namespace libtorrent return m_storage->save_path(); } + bool torrent::move_storage(boost::filesystem::path const& save_path) + { + return m_storage->move_storage(save_path); + } + piece_manager& torrent::filesystem() { assert(m_storage.get()); diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index b842de590..8964f4e2c 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -222,6 +222,14 @@ namespace libtorrent , boost::bind(&torrent::set_download_limit, _1, limit)); } + bool torrent_handle::move_storage(boost::filesystem::path const& save_path) + { + INVARIANT_CHECK; + + return call_member (m_ses, m_chk, m_info_hash + , boost::bind(&torrent::move_storage, _1, save_path)); + } + bool torrent_handle::is_paused() const { INVARIANT_CHECK;