From ef794b8eda3802e7c4e7d44cac9ef616b48bdfd5 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Tue, 7 Aug 2007 15:14:57 +0000 Subject: [PATCH] * Added a default low_diskspace check for 500MB. * Properly catch the exceptions being thrown by the 'in_*' events. * Expand ~ in ExecFile. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@950 e378c898-3ddf-0310-93e7-cc216c733640 --- configure.ac | 2 +- rak/path.h | 15 +++++++++++++++ src/command_events.cc | 8 ++++---- src/command_local.cc | 4 ++-- src/core/download_list.cc | 9 ++++++++- src/main.cc | 1 + src/rpc/exec_file.cc | 34 +++++++++++++++++++++++----------- src/rpc/exec_file.h | 9 +++++++-- src/utils/socket_fd.cc | 2 +- 9 files changed, 62 insertions(+), 22 deletions(-) diff --git a/configure.ac b/configure.ac index bc7e0920..444ece61 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(rtorrent, 0.7.6, jaris@ifi.uio.no) +AC_INIT(rtorrent, 0.7.7, jaris@ifi.uio.no) AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) diff --git a/rak/path.h b/rak/path.h index 9e22b404..08adaa1b 100644 --- a/rak/path.h +++ b/rak/path.h @@ -58,6 +58,21 @@ path_expand(const std::string& path) { return home + path.substr(1); } +inline char* +path_expand(const char* src, char* first, char* last) { + if (*src == '~') { + char* home = std::getenv("HOME"); + + if (home == NULL) + return first; + + first += strlcpy(first, home, std::distance(first, last)); + src++; + } + + return first + strlcpy(first, src, std::distance(first, last)); +} + } #endif diff --git a/src/command_events.cc b/src/command_events.cc index cb18ce7a..672967aa 100644 --- a/src/command_events.cc +++ b/src/command_events.cc @@ -62,18 +62,18 @@ torrent::Object apply_on_state_change(core::DownloadList::slot_map* slotMap, const torrent::Object& rawArgs) { const torrent::Object::list_type& args = rawArgs.as_list(); - if (args.size() < 2) - throw torrent::input_error("Too few arguments."); + if (args.size() == 0 || args.size() > 2) + throw torrent::input_error("Wrong number of arguments."); if (args.front().as_string().empty()) throw torrent::input_error("Empty key."); std::string key = "1_state_" + args.front().as_string(); - if (args.back().as_string().empty()) + if (args.size() == 1) slotMap->erase(key); else - (*slotMap)[key] = sigc::bind(sigc::ptr_fun(&rpc::parse_command_d_multiple_std), rpc::convert_list_to_command(++args.begin(), args.end())); + (*slotMap)[key] = sigc::bind(sigc::ptr_fun(&rpc::parse_command_d_multiple_std), args.back().as_string()); return torrent::Object(); } diff --git a/src/command_local.cc b/src/command_local.cc index 45b5b126..cee3fd88 100644 --- a/src/command_local.cc +++ b/src/command_local.cc @@ -59,7 +59,7 @@ initialize_command_local() { core::DownloadList* dList = control->core()->download_list(); core::DownloadStore* dStore = control->core()->download_store(); - ADD_VARIABLE_C_STRING("client_version", PACKAGE_VERSION); + ADD_VARIABLE_C_STRING("client_version", PACKAGE_VERSION); ADD_VARIABLE_C_STRING("library_version", torrent::version()); ADD_VARIABLE_VALUE("max_file_size", -1); @@ -83,5 +83,5 @@ initialize_command_local() { ADD_COMMAND_VALUE_TRI_OCT("umask", rak::make_mem_fun(control, &Control::set_umask), rak::make_mem_fun(control, &Control::umask)); ADD_COMMAND_STRING_TRI("working_directory", rak::make_mem_fun(control, &Control::set_working_directory), rak::make_mem_fun(control, &Control::working_directory)); - ADD_COMMAND_LIST("execute", rak::mem_fn(&rpc::execFile, &rpc::ExecFile::execute_object)); + ADD_COMMAND_LIST("execute", rak::bind2_mem_fn(&rpc::execFile, &rpc::ExecFile::execute_object, rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde)); } diff --git a/src/core/download_list.cc b/src/core/download_list.cc index c2c82b15..377ea4eb 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -73,7 +73,11 @@ struct download_list_call { download_list_call(Download* d) : m_download(d) {} void operator () (const DownloadList::slot_map::value_type& s) { - s.second(m_download); + try { + s.second(m_download); + } catch (torrent::input_error& e) { + control->core()->push_log((std::string("Download event action failed: ") + e.what()).c_str()); + } } Download* m_download; @@ -561,6 +565,9 @@ DownloadList::confirm_finished(Download* download) { // up/downloaded baseline. download->download()->tracker_list().send_completed(); + // Close before calling on_finished to ensure the user can do stuff + // like change move the downloaded files and change the directory. + close_throw(download); std::for_each(slot_map_finished().begin(), slot_map_finished().end(), download_list_call(download)); if (!download->is_active() && rpc::call_command_d_value("get_d_state", download) == 1) diff --git a/src/main.cc b/src/main.cc index ba4b1a9a..e74f27f7 100644 --- a/src/main.cc +++ b/src/main.cc @@ -220,6 +220,7 @@ main(int argc, char** argv) { //"schedule = scheduler,10,10,download_scheduler=\n" "schedule = session_save,1800,1800,session_save=\n" + "schedule = low_diskspace,5,60,close_low_diskspace=500M\n" // Changing these will bork the (non-existant) scheduler. "view_add = scheduler\n" diff --git a/src/rpc/exec_file.cc b/src/rpc/exec_file.cc index 361f58ef..9b91be7b 100644 --- a/src/rpc/exec_file.cc +++ b/src/rpc/exec_file.cc @@ -37,6 +37,7 @@ #include "config.h" #include +#include #include #include @@ -73,12 +74,12 @@ ExecFile::execute(const char* file, char* const* argv) { } torrent::Object -ExecFile::execute_object(const torrent::Object& rawArgs) { - char* argsBuffer[128]; +ExecFile::execute_object(const torrent::Object& rawArgs, int flags) { + char* argsBuffer[max_args]; char** argsCurrent = argsBuffer; - // Size of strings are less than 24. - char valueBuffer[3072]; + // Size of value strings are less than 24. + char valueBuffer[buffer_size]; char* valueCurrent = valueBuffer; const torrent::Object::list_type& args = rawArgs.as_list(); @@ -87,18 +88,27 @@ ExecFile::execute_object(const torrent::Object& rawArgs) { throw torrent::input_error("Too few arguments."); for (torrent::Object::list_type::const_iterator itr = args.begin(), last = args.end(); itr != last; itr++, argsCurrent++) { - if (argsCurrent == argsBuffer + 128 - 1) + if (argsCurrent == argsBuffer + max_args - 1) throw torrent::input_error("Too many arguments."); switch (itr->type()) { case torrent::Object::TYPE_STRING: - *argsCurrent = const_cast(itr->as_string().c_str()); - break; + { + const std::string& str = itr->as_string(); + if ((flags & flag_expand_tilde) && *str.c_str() == '~') { + *argsCurrent = valueCurrent; + valueCurrent = rak::path_expand(str.c_str(), valueCurrent, valueBuffer + buffer_size) + 1; + } else { + *argsCurrent = const_cast(str.c_str()); + } + + break; + } case torrent::Object::TYPE_VALUE: *argsCurrent = valueCurrent; - valueCurrent += std::max(snprintf(valueCurrent, valueBuffer + 3072 - valueCurrent, "%lli", itr->as_value()), 0); + valueCurrent += snprintf(valueCurrent, valueBuffer + buffer_size - valueCurrent, "%lli", itr->as_value()) + 1; break; default: @@ -108,12 +118,14 @@ ExecFile::execute_object(const torrent::Object& rawArgs) { *argsCurrent = NULL; + // Check if we overflowed the valueBuffer. + int status = execute(argsBuffer[0], argsBuffer); - if (status != 0) - throw torrent::input_error("ExecFile::execute_object(...) status != 0."); + if ((flags & flag_throw) && status != 0) + throw torrent::input_error("Bad return code."); - return torrent::Object(); + return torrent::Object((int64_t)status); } } diff --git a/src/rpc/exec_file.h b/src/rpc/exec_file.h index 899af63c..8f25a8c7 100644 --- a/src/rpc/exec_file.h +++ b/src/rpc/exec_file.h @@ -43,10 +43,15 @@ namespace rpc { class ExecFile { public: - + static const unsigned int max_args = 128; + static const unsigned int buffer_size = 4096; + + static const int flag_throw = 0x1; + static const int flag_expand_tilde = 0x2; + int execute(const char* file, char* const* argv); - torrent::Object execute_object(const torrent::Object& rawArgs); + torrent::Object execute_object(const torrent::Object& rawArgs, int flags); private: diff --git a/src/utils/socket_fd.cc b/src/utils/socket_fd.cc index ca4ada8e..969b51f4 100644 --- a/src/utils/socket_fd.cc +++ b/src/utils/socket_fd.cc @@ -94,7 +94,7 @@ SocketFd::set_dont_route(bool state) { // SocketFd::set_bind_to_device(const char* device) { // check_valid(); // struct ifreq ifr; -// strncpy(ifr.ifr_name, device, IFNAMSIZ); +// strlcpy(ifr.ifr_name, device, IFNAMSIZ); // return setsockopt(m_fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == 0; // }