diff --git a/src/command_scheduler.cc b/src/command_scheduler.cc index 4dc0a316..c7536203 100644 --- a/src/command_scheduler.cc +++ b/src/command_scheduler.cc @@ -40,6 +40,7 @@ #include #include #include +#include #include #include "command_scheduler.h" @@ -114,6 +115,27 @@ CommandScheduler::call_item(value_type item) { item->enable(next); } +void +CommandScheduler::parse(const std::string& arg) { + char key[21]; + char bufAbsolute[21]; + char bufInterval[21]; + char command[2048]; + + if (std::sscanf(arg.c_str(), "%20[^,],%20[^,],%20[^,],%2047[^\n]", key, bufAbsolute, bufInterval, command) != 4) + throw torrent::input_error("Invalid arguments to command."); + + uint32_t absolute = parse_absolute(bufAbsolute); + uint32_t interval = parse_interval(bufInterval); + + CommandSchedulerItem* item = *insert(rak::trim(std::string(key))); + + item->set_command(rak::trim(std::string(command))); + item->set_interval(interval); + + item->enable((cachedTime + rak::timer(absolute) * 1000000).round_seconds()); +} + uint32_t CommandScheduler::parse_absolute(const char* str) { Time result = parse_time(str); diff --git a/src/command_scheduler.h b/src/command_scheduler.h index 1f550614..954297f9 100644 --- a/src/command_scheduler.h +++ b/src/command_scheduler.h @@ -69,6 +69,8 @@ public: void erase(iterator itr); void erase(const std::string& key) { erase(find(key)); } + void parse(const std::string& arg); + static uint32_t parse_absolute(const char* str); static uint32_t parse_interval(const char* str); diff --git a/src/control.cc b/src/control.cc index 38fca7e4..ba209955 100644 --- a/src/control.cc +++ b/src/control.cc @@ -67,7 +67,7 @@ Control::Control() : m_inputStdin->slot_pressed(sigc::mem_fun(m_input, &input::Manager::pressed)); - m_taskShutdown.set_slot(rak::mem_fn(this, &Control::receive_shutdown)); + m_taskShutdown.set_slot(rak::mem_fn(this, &Control::handle_shutdown)); m_commandScheduler->set_slot_command(rak::mem_fn(m_variables, &utils::VariableMap::process_command)); m_commandScheduler->set_slot_error_message(rak::mem_fn(m_core, &core::Manager::push_log)); @@ -98,6 +98,7 @@ Control::initialize() { m_core->initialize_second(); m_core->listen_open(); + m_core->download_store().enable(m_variables->get_string("session_lock") == "yes"); m_ui->init(this); @@ -110,6 +111,8 @@ Control::cleanup() { m_inputStdin->remove(m_core->get_poll_manager()->get_torrent_poll()); + m_core->download_store().disable(); + m_ui->cleanup(); m_core->cleanup(); @@ -119,15 +122,11 @@ Control::cleanup() { display::Canvas::cleanup(); } -// I think it should be safe to initiate the shutdown from anywhere, -// but if it isn't, use a delay task. void -Control::receive_shutdown() { - if (!m_shutdownReceived) { +Control::handle_shutdown() { + if (!m_shutdownQuick) { torrent::listen_close(); - m_core->shutdown(false); - m_shutdownReceived = true; if (!m_taskShutdown.is_queued()) priority_queue_insert(&taskScheduler, &m_taskShutdown, cachedTime + 5 * 1000000); @@ -135,4 +134,7 @@ Control::receive_shutdown() { } else { m_core->shutdown(true); } + + m_shutdownQuick = true; + m_shutdownReceived = false; } diff --git a/src/control.h b/src/control.h index 17436e27..6d53f094 100644 --- a/src/control.h +++ b/src/control.h @@ -70,13 +70,16 @@ public: Control(); ~Control(); - bool is_shutdown_completed() { return m_shutdownReceived && torrent::is_inactive(); } + bool is_shutdown_completed() { return m_shutdownQuick && torrent::is_inactive(); } bool is_shutdown_received() { return m_shutdownReceived; } void initialize(); void cleanup(); - void receive_shutdown(); + void handle_shutdown(); + + void receive_normal_shutdown() { m_shutdownReceived = true; } + void receive_quick_shutdown() { m_shutdownReceived = true; m_shutdownQuick = true; } ui::Root* ui() { return m_ui; } core::Manager* core() { return m_core; } @@ -95,6 +98,7 @@ private: void operator = (const Control&); bool m_shutdownReceived; + bool m_shutdownQuick; ui::Root* m_ui; core::Manager* m_core; diff --git a/src/core/download_factory.cc b/src/core/download_factory.cc index eacc6ffe..360ceeba 100644 --- a/src/core/download_factory.cc +++ b/src/core/download_factory.cc @@ -99,7 +99,7 @@ DownloadFactory::receive_load() { if (std::strncmp(m_uri.c_str(), "http://", 7) == 0) { // Http handling here. m_stream = new std::stringstream; - HttpQueue::iterator itr = m_manager->get_http_queue().insert(m_uri, m_stream); + HttpQueue::iterator itr = m_manager->http_queue().insert(m_uri, m_stream); (*itr)->signal_done().slots().push_front(sigc::mem_fun(*this, &DownloadFactory::receive_loaded)); (*itr)->signal_failed().slots().push_front(sigc::mem_fun(*this, &DownloadFactory::receive_failed)); @@ -139,7 +139,7 @@ DownloadFactory::receive_success() { Manager::DListItr itr = m_manager->insert(m_stream, m_printLog); - if (itr == m_manager->get_download_list().end()) { + if (itr == m_manager->download_list().end()) { // core::Manager should already have added the error message to // the log. m_slotFinished(); @@ -206,7 +206,7 @@ DownloadFactory::receive_success() { if (m_start) m_manager->start(*itr, m_printLog); - m_manager->get_download_store().save(*itr); + m_manager->download_store().save(*itr); } m_slotFinished(); diff --git a/src/core/download_store.cc b/src/core/download_store.cc index 1599bed4..29a8fb5b 100644 --- a/src/core/download_store.cc +++ b/src/core/download_store.cc @@ -52,16 +52,44 @@ namespace core { void -DownloadStore::use(const std::string& path) { - m_path = path; +DownloadStore::enable(bool lock) { + if (is_enabled()) + throw torrent::input_error("Session directory already enabled."); - if (!m_path.empty() && *m_path.rbegin() != '/') - m_path += '/'; + if (m_path.empty()) + return; + + if (lock) + m_lockfile.set_path(m_path + "rtorrent.lock"); + else + m_lockfile.set_path(std::string()); + + if (!m_lockfile.try_lock()) + throw torrent::input_error("Could not lock session directory: \"" + m_path + "\"."); +} + +void +DownloadStore::disable() { + if (!is_enabled()) + return; + + m_lockfile.unlock(); +} + +void +DownloadStore::set_path(const std::string& path) { + if (is_enabled()) + throw torrent::input_error("Tried to change session directory while it is enabled."); + + if (!path.empty() && *path.rbegin() != '/') + m_path = path + '/'; + else + m_path = path; } void DownloadStore::save(Download* d) { - if (!is_active()) + if (!is_enabled()) return; std::fstream f((create_filename(d) + ".new").c_str(), std::ios::out | std::ios::trunc); @@ -92,7 +120,7 @@ DownloadStore::save(Download* d) { void DownloadStore::remove(Download* d) { - if (!is_active()) + if (!is_enabled()) return; ::unlink(create_filename(d).c_str()); @@ -100,7 +128,7 @@ DownloadStore::remove(Download* d) { utils::Directory DownloadStore::get_formated_entries() { - if (!is_active()) + if (!is_enabled()) return utils::Directory(); utils::Directory d(m_path); diff --git a/src/core/download_store.h b/src/core/download_store.h index fd44215a..1ebdcb5e 100644 --- a/src/core/download_store.h +++ b/src/core/download_store.h @@ -40,6 +40,7 @@ #include #include "utils/directory.h" +#include "utils/lockfile.h" namespace core { @@ -48,22 +49,26 @@ class Download; class DownloadStore { public: - // Disable by passing an empty string. - void use(const std::string& path); + bool is_enabled() { return m_lockfile.is_locked(); } - bool is_active() { return !m_path.empty(); } + void enable(bool lock); + void disable(); - void save(Download* d); - void remove(Download* d); + const std::string& path() const { return m_path; } + void set_path(const std::string& path); + + void save(Download* d); + void remove(Download* d); // Currently shows all entries in the correct format. - utils::Directory get_formated_entries(); + utils::Directory get_formated_entries(); private: - static bool is_correct_format(std::string f); - std::string create_filename(Download* d); + static bool is_correct_format(std::string f); + std::string create_filename(Download* d); - std::string m_path; + std::string m_path; + utils::Lockfile m_lockfile; }; } diff --git a/src/core/manager.cc b/src/core/manager.cc index 8cd8ad75..dfa30a61 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -107,6 +107,7 @@ Manager::initialize_first() { torrent::initialize(m_pollManager->get_torrent_poll()); } +// Most of this should be possible to move out. void Manager::initialize_second() { torrent::Http::set_factory(m_pollManager->get_http_stack()->get_http_factory()); @@ -116,11 +117,8 @@ Manager::initialize_second() { // Register slots to be called when a download is inserted/erased, // opened or closed. - // m_downloadList.slot_map_insert()["0_initialize_bencode"] = sigc::mem_fun(*this, &Manager::initialize_bencode); m_downloadList.slot_map_insert()["1_connect_network_log"] = sigc::bind(sigc::ptr_fun(&connect_signal_network_log), sigc::mem_fun(m_logComplete, &Log::push_front)); -// m_downloadList.slot_map_insert()["1_connect_tracker_log"] = sigc::bind(sigc::ptr_fun(&connect_signal_tracker_log), sigc::mem_fun(m_logComplete, &Log::push_front)); m_downloadList.slot_map_insert()["1_connect_storage_log"] = sigc::bind(sigc::ptr_fun(&connect_signal_storage_log), sigc::mem_fun(m_logComplete, &Log::push_front)); - //m_downloadList.slot_map_insert()["1_enable_udp_trackers"] = sigc::bind(sigc::mem_fun(&core::Download::enable_udp_trackers), true); m_downloadList.slot_map_erase()["1_hash_queue_remove"] = sigc::mem_fun(m_hashQueue, &HashQueue::remove); m_downloadList.slot_map_erase()["1_store_remove"] = sigc::mem_fun(m_downloadStore, &DownloadStore::remove); @@ -319,9 +317,12 @@ Manager::receive_download_done_hash_checked(Download* d) { if (!d->get_download().is_active()) m_downloadList.start(d); + if (control->variables()->get_string("session_on_completion") == "yes") + m_downloadStore.save(d); + // Don't send if we did a hash check and found incompelete chunks. - //if (d->is_done()) - d->get_download().tracker_send_completed(); + if (d->is_done()) + d->get_download().tracker_send_completed(); } void diff --git a/src/core/manager.h b/src/core/manager.h index ce0cc40d..ad9e9c22 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -60,10 +60,10 @@ public: Manager(); - DownloadList& get_download_list() { return m_downloadList; } - DownloadStore& get_download_store() { return m_downloadStore; } - HashQueue& get_hash_queue() { return m_hashQueue; } - HttpQueue& get_http_queue() { return m_httpQueue; } + DownloadList& download_list() { return m_downloadList; } + DownloadStore& download_store() { return m_downloadStore; } + HashQueue& hash_queue() { return m_hashQueue; } + HttpQueue& http_queue() { return m_httpQueue; } PollManager* get_poll_manager() { return m_pollManager; } Log& get_log_important() { return m_logImportant; } diff --git a/src/main.cc b/src/main.cc index 32900ada..ee52ddfc 100644 --- a/src/main.cc +++ b/src/main.cc @@ -77,19 +77,6 @@ void do_panic(int signum); void print_help(); -bool -is_resized() { - static int x = 0; - static int y = 0; - - bool r = display::Canvas::get_screen_width() != x || display::Canvas::get_screen_height() != y; - - x = display::Canvas::get_screen_width(); - y = display::Canvas::get_screen_height(); - - return r; -} - int parse_options(Control* c, utils::VariableMap* optionHandler, int argc, char** argv) { try { @@ -116,7 +103,7 @@ parse_options(Control* c, utils::VariableMap* optionHandler, int argc, char** ar void load_session_torrents(Control* c) { // Load session torrents. - std::list l = c->core()->get_download_store().get_formated_entries().make_list(); + std::list l = c->core()->download_store().get_formated_entries().make_list(); for (std::list::iterator first = l.begin(), last = l.end(); first != last; ++first) { core::DownloadFactory* f = new core::DownloadFactory(*first, c->core()); @@ -170,7 +157,8 @@ main(int argc, char** argv) { initialize_option_handler(control); SignalHandler::set_ignore(SIGPIPE); - SignalHandler::set_handler(SIGINT, sigc::mem_fun(control, &Control::receive_shutdown)); + SignalHandler::set_handler(SIGINT, sigc::mem_fun(control, &Control::receive_normal_shutdown)); + SignalHandler::set_handler(SIGTERM, sigc::mem_fun(control, &Control::receive_quick_shutdown)); SignalHandler::set_handler(SIGWINCH, sigc::mem_fun(control->display(), &display::Manager::force_redraw)); SignalHandler::set_handler(SIGSEGV, sigc::bind(sigc::ptr_fun(&do_panic), SIGSEGV)); SignalHandler::set_handler(SIGBUS, sigc::bind(sigc::ptr_fun(&do_panic), SIGBUS)); @@ -198,6 +186,9 @@ main(int argc, char** argv) { control->display()->adjust_layout(); while (!control->is_shutdown_completed()) { + if (control->is_shutdown_received()) + control->handle_shutdown(); + control->inc_tick(); cachedTime = rak::timer::current(); diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc index fcc55123..c4caaf4b 100644 --- a/src/option_handler_rules.cc +++ b/src/option_handler_rules.cc @@ -37,9 +37,7 @@ #include "config.h" #include -#include -#include -#include +#include #include #include #include @@ -59,38 +57,18 @@ #include "control.h" #include "option_handler_rules.h" #include "command_scheduler.h" -#include "command_scheduler_item.h" - -// void -// OptionHandlerInt::process(const std::string& key, const std::string& arg) { -// int a; - -// if (std::sscanf(arg.c_str(), "%i", &a) != 1) -// throw torrent::input_error("Invalid argument for \"" + key + "\": \"" + arg + "\", must be an integer."); - -// m_apply(m_control, a); -// } - -// void -// OptionHandlerOctal::process(const std::string& key, const std::string& arg) { -// int a; - -// if (std::sscanf(arg.c_str(), "%o", &a) != 1) -// throw torrent::input_error("Invalid argument for \"" + key + "\": \"" + arg + "\", must be an octal."); - -// m_apply(m_control, a); -// } - -// void -// OptionHandlerString::process(const std::string& key, const std::string& arg) { -// m_apply(m_control, arg); -// } void apply_umask(int arg) { umask(arg); } +void +apply_working_directory(const std::string& path) { + if (chdir(path.c_str()) != 0) + throw torrent::input_error("Could not change working directory."); +} + void apply_hash_read_ahead(Control* m, int arg) { torrent::set_hash_read_ahead(arg << 20); @@ -129,12 +107,12 @@ apply_load_start(Control* m, const std::string& arg) { void apply_stop_untied(Control* m, const std::string& arg) { - core::Manager::DListItr itr = m->core()->get_download_list().begin(); + core::Manager::DListItr itr = m->core()->download_list().begin(); - while ((itr = std::find_if(itr, m->core()->get_download_list().end(), + while ((itr = std::find_if(itr, m->core()->download_list().end(), rak::on(rak::bind2nd(std::mem_fun(&core::Download::variable_string), "tied_to_file"), std::not1(std::mem_fun_ref(&std::string::empty))))) - != m->core()->get_download_list().end()) { + != m->core()->download_list().end()) { rak::file_stat fs; if (!fs.update((*itr)->variable_string("tied_to_file"))) { @@ -148,12 +126,12 @@ apply_stop_untied(Control* m, const std::string& arg) { void apply_remove_untied(Control* m, const std::string& arg) { - core::Manager::DListItr itr = m->core()->get_download_list().begin(); + core::Manager::DListItr itr = m->core()->download_list().begin(); - while ((itr = std::find_if(itr, m->core()->get_download_list().end(), + while ((itr = std::find_if(itr, m->core()->download_list().end(), rak::on(rak::bind2nd(std::mem_fun(&core::Download::variable_string), "tied_to_file"), std::not1(std::mem_fun_ref(&std::string::empty))))) - != m->core()->get_download_list().end()) { + != m->core()->download_list().end()) { rak::file_stat fs; if (!fs.update((*itr)->variable_string("tied_to_file"))) { @@ -172,41 +150,23 @@ apply_encoding_list(Control* m, const std::string& arg) { torrent::encoding_list()->push_back(arg); } -void -apply_schedule(Control* m, const std::string& arg) { - char key[21]; - char bufAbsolute[21]; - char bufInterval[21]; - char command[2048]; - - if (std::sscanf(arg.c_str(), "%20[^,],%20[^,],%20[^,],%2047[^\n]", key, bufAbsolute, bufInterval, command) != 4) - throw torrent::input_error("Invalid arguments to command."); - - uint32_t absolute = CommandScheduler::parse_absolute(bufAbsolute); - uint32_t interval = CommandScheduler::parse_interval(bufInterval); - - CommandSchedulerItem* item = *m->command_scheduler()->insert(rak::trim(std::string(key))); - - item->set_command(rak::trim(std::string(command))); - item->set_interval(interval); - - item->enable((cachedTime + rak::timer(absolute) * 1000000).round_seconds()); -} - void initialize_option_handler(Control* c) { utils::VariableMap* variables = control->variables(); // Cleaned up. - variables->insert("check_hash", new utils::VariableAny("yes")); - variables->insert("use_udp_trackers", new utils::VariableAny("yes")); - variables->insert("port_random", new utils::VariableAny("yes")); - variables->insert("session", new utils::VariableSlotString<>(NULL, rak::mem_fn(&control->core()->get_download_store(), &core::DownloadStore::use))); + variables->insert("check_hash", new utils::VariableAny("yes")); + variables->insert("use_udp_trackers", new utils::VariableAny("yes")); + variables->insert("port_random", new utils::VariableAny("yes")); + variables->insert("session", new utils::VariableSlotString<>(NULL, rak::mem_fn(&control->core()->download_store(), &core::DownloadStore::set_path))); + variables->insert("session_lock", new utils::VariableAny("yes")); + variables->insert("session_on_completion", new utils::VariableAny("yes")); variables->insert("connection_leech", new utils::VariableAny("leech")); variables->insert("connection_seed", new utils::VariableAny("seed")); variables->insert("directory", new utils::VariableAny("./")); + variables->insert("working_directory", new utils::VariableSlotString<>(NULL, rak::ptr_fn(&apply_working_directory))); variables->insert("ip", new utils::VariableSlotString<>(NULL, rak::ptr_fn(&torrent::set_local_address))); variables->insert("bind", new utils::VariableSlotString<>(NULL, rak::mem_fn(control->core(), &core::Manager::bind))); @@ -223,6 +183,7 @@ initialize_option_handler(Control* c) { variables->insert("print", new utils::VariableSlotString<>(NULL, rak::mem_fn(control->core(), &core::Manager::push_log))); + variables->insert("schedule", new utils::VariableSlotString<>(NULL, rak::mem_fn(c->command_scheduler(), &CommandScheduler::parse))); variables->insert("schedule_remove", new utils::VariableSlotString<>(NULL, rak::mem_fn(c->command_scheduler(), &CommandScheduler::erase))); // Old. @@ -241,5 +202,4 @@ initialize_option_handler(Control* c) { variables->insert("encoding_list", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_encoding_list, c))); variables->insert("http_proxy", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_http_proxy, c))); - variables->insert("schedule", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_schedule, c))); } diff --git a/src/option_handler_rules.h b/src/option_handler_rules.h index 6afc072e..61432253 100644 --- a/src/option_handler_rules.h +++ b/src/option_handler_rules.h @@ -37,55 +37,8 @@ #ifndef RTORRENT_OPTION_HANDLER_RULES_H #define RTORRENT_OPTION_HANDLER_RULES_H -#include -#include -#include -#include - class Control; void initialize_option_handler(Control* c); -class OptionHandlerInt { -public: - typedef void (*Apply)(Control*, int); - - OptionHandlerInt(Control* c, Apply a) : - m_control(c), m_apply(a) {} - - virtual void process(const std::string& key, const std::string& arg); - -private: - Control* m_control; - Apply m_apply; -}; - -class OptionHandlerOctal { -public: - typedef void (*Apply)(Control*, int); - - OptionHandlerOctal(Control* c, Apply a) : - m_control(c), m_apply(a) {} - - virtual void process(const std::string& key, const std::string& arg); - -private: - Control* m_control; - Apply m_apply; -}; - -class OptionHandlerString { -public: - typedef void (*Apply)(Control*, const std::string&); - - OptionHandlerString(Control* c, Apply a) : - m_control(c), m_apply(a) {} - - virtual void process(const std::string& key, const std::string& arg); - -private: - Control* m_control; - Apply m_apply; -}; - #endif diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index 7b72b864..25335f29 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -73,11 +73,11 @@ DownloadList::DownloadList(Control* c) : m_window(c->display()->end()), m_windowTitle(new WTitle("rTorrent " VERSION " - libTorrent " + std::string(torrent::version()))), - m_windowHttpQueue(new WHttp(&c->core()->get_http_queue())), + m_windowHttpQueue(new WHttp(&c->core()->http_queue())), m_uiDownload(NULL), - m_downloadList(&c->core()->get_download_list()), + m_downloadList(&c->core()->download_list()), m_control(c), m_bindings(new input::Bindings) @@ -124,7 +124,7 @@ DownloadList::activate() { m_control->input()->push_front(m_bindings); - m_control->core()->get_download_list().slot_map_erase().insert("0_download_list", sigc::mem_fun(this, &DownloadList::receive_download_erased)); + m_control->core()->download_list().slot_map_erase().insert("0_download_list", sigc::mem_fun(this, &DownloadList::receive_download_erased)); activate_display(DISPLAY_DOWNLOAD_LIST); } diff --git a/src/ui/root.cc b/src/ui/root.cc index 868b73fa..97f57703 100644 --- a/src/ui/root.cc +++ b/src/ui/root.cc @@ -110,7 +110,7 @@ Root::setup_keys() { //m_bindings[KEY_RESIZE] = sigc::mem_fun(*m_control->display(), &display::Manager::adjust_layout); m_bindings['\x0C'] = sigc::mem_fun(m_control->display(), &display::Manager::force_redraw); - m_bindings['\x11'] = sigc::mem_fun(m_control, &Control::receive_shutdown); + m_bindings['\x11'] = sigc::mem_fun(m_control, &Control::receive_normal_shutdown); } void diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am index 7c966faa..88b80a6b 100644 --- a/src/utils/Makefile.am +++ b/src/utils/Makefile.am @@ -4,6 +4,8 @@ libsub_utils_a_SOURCES = \ directory.cc \ directory.h \ list_focus.h \ + lockfile.cc \ + lockfile.h \ variable.h \ variable_generic.cc \ variable_generic.h \ diff --git a/src/utils/lockfile.cc b/src/utils/lockfile.cc new file mode 100644 index 00000000..e93590fd --- /dev/null +++ b/src/utils/lockfile.cc @@ -0,0 +1,75 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005-2006, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#include "config.h" + +#include +#include +#include + +#include "lockfile.h" + +namespace utils { + +bool +Lockfile::try_lock() { + if (m_path.empty()) { + m_id = "foo"; + return true; + } + + // Just do a simple locking for now that isn't safe for network + // devices. + int fd = ::open(m_path.c_str(), O_RDWR | O_CREAT | O_EXCL); + + if (fd == -1) + return false; + + m_id = "foo"; + ::close(fd); + + return true; +} + +bool +Lockfile::unlock() { + if (m_path.empty()) + return true; + else + return ::unlink(m_path.c_str()) != -1; +} + +} diff --git a/src/utils/lockfile.h b/src/utils/lockfile.h new file mode 100644 index 00000000..83e4e5ce --- /dev/null +++ b/src/utils/lockfile.h @@ -0,0 +1,64 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005-2006, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#ifndef RTORRENT_UTILS_LOCKFILE_H +#define RTORRENT_UTILS_LOCKFILE_H + +#include + +namespace utils { + +class Lockfile { +public: + + bool is_locked() const { return !m_id.empty(); } + + // If the path is empty no lock file will be created, although + // is_locked() will return true. + bool try_lock(); + bool unlock(); + + const std::string& path() const { return m_path; } + void set_path(const std::string& path) { m_path = path; } + +private: + std::string m_path; + std::string m_id; +}; + +} + +#endif diff --git a/src/utils/variable.h b/src/utils/variable.h index c9798316..959230b0 100644 --- a/src/utils/variable.h +++ b/src/utils/variable.h @@ -37,6 +37,8 @@ #ifndef RTORRENT_UTILS_VARIABLE_H #define RTORRENT_UTILS_VARIABLE_H +#include + namespace torrent { class Bencode; } @@ -49,7 +51,7 @@ public: virtual ~Variable() {} virtual const torrent::Bencode& get() = 0; - virtual void set(const torrent::Bencode& arg) = 0; + virtual void set(const torrent::Bencode& arg) = 0; protected: Variable(const Variable&); diff --git a/src/utils/variable_generic.h b/src/utils/variable_generic.h index ec10ef59..b2b97881 100644 --- a/src/utils/variable_generic.h +++ b/src/utils/variable_generic.h @@ -34,6 +34,9 @@ // Skomakerveien 33 // 3185 Skoppum, NORWAY +// Parts of this seems ugly in an attempt to avoid copying +// data. Propably need to rewrite torrent::Bencode. + #ifndef RTORRENT_UTILS_VARIABLE_GENERIC_H #define RTORRENT_UTILS_VARIABLE_GENERIC_H @@ -56,7 +59,7 @@ public: virtual ~VariableAny(); virtual const torrent::Bencode& get(); - virtual void set(const torrent::Bencode& arg); + virtual void set(const torrent::Bencode& arg); private: torrent::Bencode m_variable; @@ -68,7 +71,7 @@ public: virtual ~VariableValue(); virtual const torrent::Bencode& get(); - virtual void set(const torrent::Bencode& arg); + virtual void set(const torrent::Bencode& arg); private: torrent::Bencode m_variable; diff --git a/src/utils/variable_map.cc b/src/utils/variable_map.cc index 6d941ae3..a18e7659 100644 --- a/src/utils/variable_map.cc +++ b/src/utils/variable_map.cc @@ -36,6 +36,7 @@ #include "config.h" +#include #include #include #include diff --git a/src/utils/variable_map.h b/src/utils/variable_map.h index cfc7ca2d..b1c00551 100644 --- a/src/utils/variable_map.h +++ b/src/utils/variable_map.h @@ -61,7 +61,7 @@ public: // Consider taking char* start and finish instead of std::string to // avoid copying. Or make a view class. const mapped_type& get(const std::string& key); - std::string get_string(const std::string& key); + const std::string& get_string(const std::string& key) { return get(key).as_string(); } void set(const std::string& key, const mapped_type& arg); void set_string(const std::string& key, const std::string& arg) { set(key, mapped_type(arg)); } @@ -74,16 +74,6 @@ private: void operator = (const VariableMap&); }; -inline std::string -VariableMap::get_string(const std::string& key) { - const mapped_type& v = get(key); - - if (v.get_type() == mapped_type::TYPE_NONE) - return std::string(); - else - return v.as_string(); -} - } #endif