From fce5e07f23175d17adb1df498facb6b91c369aa8 Mon Sep 17 00:00:00 2001 From: arvidn Date: Thu, 17 Jul 2008 23:41:46 +0000 Subject: [PATCH] improved error reporting of file errors (uses boost.system's error_code). Now permission errors are properly reported when checking files git-svn-id: http://libtorrent.svn.sourceforge.net/svnroot/libtorrent/trunk@2546 a83610d8-ad2a-0410-a6ab-fc0612d85776 --- include/libtorrent/disk_io_thread.hpp | 5 + include/libtorrent/error_code.hpp | 57 +++++++++ include/libtorrent/file.hpp | 17 ++- include/libtorrent/file_pool.hpp | 2 +- include/libtorrent/socket.hpp | 3 +- include/libtorrent/storage.hpp | 17 +-- src/disk_io_thread.cpp | 90 ++++++-------- src/file.cpp | 136 ++++++++------------ src/file_pool.cpp | 52 ++++++-- src/storage.cpp | 225 +++++++++++++++++----------------- src/torrent_info.cpp | 15 ++- 11 files changed, 336 insertions(+), 283 deletions(-) create mode 100644 include/libtorrent/error_code.hpp diff --git a/include/libtorrent/disk_io_thread.hpp b/include/libtorrent/disk_io_thread.hpp index d0d57441..e7abbbf8 100644 --- a/include/libtorrent/disk_io_thread.hpp +++ b/include/libtorrent/disk_io_thread.hpp @@ -111,6 +111,9 @@ namespace libtorrent boost::shared_ptr resume_data; + // the error code from the file operation + error_code error; + // this is called when operation completes boost::function callback; }; @@ -214,6 +217,8 @@ namespace libtorrent typedef boost::recursive_mutex mutex_t; typedef std::list cache_t; + bool test_error(disk_io_job& j); + // cache operations cache_t::iterator find_cached_piece( cache_t& cache, disk_io_job const& j diff --git a/include/libtorrent/error_code.hpp b/include/libtorrent/error_code.hpp new file mode 100644 index 00000000..6b3781fe --- /dev/null +++ b/include/libtorrent/error_code.hpp @@ -0,0 +1,57 @@ +/* + +Copyright (c) 2008, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_ERROR_CODE_HPP_INCLUDED +#define TORRENT_ERROR_CODE_HPP_INCLUDED + +#include + +#if BOOST_VERSION < 103500 +#include +#else +#include +#endif + +namespace libtorrent +{ +#if BOOST_VERSION < 103500 + typedef asio::error_code error_code; + inline asio::error::error_category get_posix_category() { return asio::error::system_category; } +#else + using boost::system::error_code; + inline boost::system::error_category const& get_posix_category() + { return boost::system::get_posix_category(); } +#endif +} + +#endif + diff --git a/include/libtorrent/file.hpp b/include/libtorrent/file.hpp index a0d3ef1c..90714905 100644 --- a/include/libtorrent/file.hpp +++ b/include/libtorrent/file.hpp @@ -48,6 +48,7 @@ POSSIBILITY OF SUCH DAMAGE. #pragma warning(pop) #endif +#include "libtorrent/error_code.hpp" #include "libtorrent/size_type.hpp" #include "libtorrent/config.hpp" @@ -102,20 +103,18 @@ namespace libtorrent static const open_mode out; file(); - file(fs::path const& p, open_mode m); + file(fs::path const& p, open_mode m, error_code& ec); ~file(); - bool open(fs::path const& p, open_mode m); + bool open(fs::path const& p, open_mode m, error_code& ec); void close(); - bool set_size(size_type size); + bool set_size(size_type size, error_code& ec); - size_type write(const char*, size_type num_bytes); - size_type read(char*, size_type num_bytes); + size_type write(const char*, size_type num_bytes, error_code& ec); + size_type read(char*, size_type num_bytes, error_code& ec); - size_type seek(size_type pos, seek_mode m = begin); - size_type tell(); - - std::string const& error() const; + size_type seek(size_type pos, seek_mode m, error_code& ec); + size_type tell(error_code& ec); private: diff --git a/include/libtorrent/file_pool.hpp b/include/libtorrent/file_pool.hpp index 69116d67..cbabfe80 100644 --- a/include/libtorrent/file_pool.hpp +++ b/include/libtorrent/file_pool.hpp @@ -66,7 +66,7 @@ namespace libtorrent file_pool(int size = 40): m_size(size) {} boost::shared_ptr open_file(void* st, fs::path const& p - , file::open_mode m, std::string& error); + , file::open_mode m, error_code& ec); void release(void* st); void release(fs::path const& p); void resize(int size); diff --git a/include/libtorrent/socket.hpp b/include/libtorrent/socket.hpp index d041024b..d4cc9bdb 100644 --- a/include/libtorrent/socket.hpp +++ b/include/libtorrent/socket.hpp @@ -73,6 +73,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/io.hpp" #include "libtorrent/time.hpp" +#include "libtorrent/error_code.hpp" #ifdef _MSC_VER #pragma warning(pop) @@ -94,12 +95,10 @@ namespace libtorrent typedef asio::ip::udp::socket datagram_socket; typedef asio::ip::tcp::acceptor socket_acceptor; typedef asio::io_service io_service; - typedef asio::error_code error_code; namespace asio = ::asio; typedef asio::basic_deadline_timer deadline_timer; #else - using boost::system::error_code; using boost::asio::ip::tcp; using boost::asio::ip::udp; using boost::asio::async_write; diff --git a/include/libtorrent/storage.hpp b/include/libtorrent/storage.hpp index 1733abe8..9f6b6b2b 100644 --- a/include/libtorrent/storage.hpp +++ b/include/libtorrent/storage.hpp @@ -164,17 +164,17 @@ namespace libtorrent // non-zero return value indicates an error virtual bool delete_files() = 0; - void set_error(std::string const& file, std::string const& msg) const + void set_error(boost::filesystem::path const& file, error_code const& ec) const { - m_error_file = file; - m_error = msg; + m_error_file = file.string(); + m_error = ec; } - std::string const& error() const { return m_error; } + error_code const& error() const { return m_error; } std::string const& error_file() const { return m_error_file; } - void clear_error() { m_error.clear(); m_error_file.clear(); } + void clear_error() { m_error = error_code(); m_error_file.clear(); } - mutable std::string m_error; + mutable error_code m_error; mutable std::string m_error_file; virtual ~storage_interface() {} @@ -267,7 +267,7 @@ namespace libtorrent void mark_failed(int index); - std::string const& error() const { return m_storage->error(); } + error_code const& error() const { return m_storage->error(); } std::string const& error_file() const { return m_storage->error_file(); } void clear_error() { m_storage->clear_error(); } @@ -308,7 +308,8 @@ namespace libtorrent , int offset , int size); - bool check_one_piece(int& have_piece); + // -1=error 0=ok 1=skip + int check_one_piece(int& have_piece); int identify_data( const std::vector& piece_data , int current_slot); diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index b1b49880..175d68f3 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -420,7 +420,7 @@ namespace libtorrent l.unlock(); ret += p.storage->read_impl(buf.get(), p.piece, start_block * m_block_size, buffer_size); l.lock(); - if (!p.storage->error().empty()) { return -1; } + if (p.storage->error()) { return -1; } ++m_cache_stats.reads; } @@ -440,7 +440,7 @@ namespace libtorrent { l.unlock(); ret += p.storage->read_impl(p.blocks[i], p.piece, piece_offset, block_size); - if (!p.storage->error().empty()) { return -1; } + if (!p.storage->error()) { return -1; } l.lock(); ++m_cache_stats.reads; } @@ -735,6 +735,23 @@ namespace libtorrent #endif } + bool disk_io_thread::test_error(disk_io_job& j) + { + error_code const& ec = j.storage->error(); + if (ec) + { + j.str = ec.message(); + j.error = ec; + j.error_file = j.storage->error_file(); + j.storage->clear_error(); +#ifndef NDEBUG + std::cout << "ERROR: '" << j.str << "' " << j.error_file << std::endl; +#endif + return true; + } + return false; + } + void disk_io_thread::operator()() { for (;;) @@ -819,17 +836,10 @@ namespace libtorrent } case disk_io_job::read: { - std::string const& error_string = j.storage->error(); - if (!error_string.empty()) + if (test_error(j)) { -#ifndef NDEBUG - std::cout << "ERROR: '" << error_string << "' " << j.error_file << std::endl; -#endif - j.str = error_string; - j.error_file = j.storage->error_file(); - j.storage->clear_error(); ret = -1; - break; + return; } #ifdef TORRENT_DISK_STATS m_log << log_time() << " read " << j.buffer_size << std::endl; @@ -841,7 +851,8 @@ namespace libtorrent if (j.buffer == 0) { ret = -1; - j.str = "out of memory"; + j.error = error_code(ENOMEM, get_posix_category()); + j.str = j.error.message(); break; } @@ -853,9 +864,7 @@ namespace libtorrent if (ret == -1) { j.buffer = 0; - j.str = j.storage->error(); - j.error_file = j.storage->error_file(); - j.storage->clear_error(); + test_error(j); break; } else if (ret == -2) @@ -864,9 +873,7 @@ namespace libtorrent , j.buffer_size); if (ret < 0) { - j.str = j.storage->error(); - j.error_file = j.storage->error_file(); - j.storage->clear_error(); + test_error(j); break; } ++m_cache_stats.blocks_read; @@ -876,15 +883,8 @@ namespace libtorrent } case disk_io_job::write: { - std::string const& error_string = j.storage->error(); - if (!error_string.empty()) + if (test_error(j)) { -#ifndef NDEBUG - std::cout << "ERROR: '" << error_string << "' " << j.error_file << std::endl; -#endif - j.str = error_string; - j.error_file = j.storage->error_file(); - j.storage->clear_error(); ret = -1; break; } @@ -936,26 +936,18 @@ namespace libtorrent if (i != m_pieces.end()) { flush_and_remove(i, l); - std::string const& e = j.storage->error(); - if (!e.empty()) + if (test_error(j)) { - j.str = e; - j.error_file = j.storage->error_file(); ret = -1; - j.storage->clear_error(); j.storage->mark_failed(j.piece); break; } } l.unlock(); sha1_hash h = j.storage->hash_for_piece_impl(j.piece); - std::string const& e = j.storage->error(); - if (!e.empty()) + if (test_error(j)) { - j.str = e; - j.error_file = j.storage->error_file(); ret = -1; - j.storage->clear_error(); j.storage->mark_failed(j.piece); break; } @@ -972,9 +964,7 @@ namespace libtorrent ret = j.storage->move_storage_impl(j.str) ? 1 : 0; if (ret != 0) { - j.str = j.storage->error(); - j.error_file = j.storage->error_file(); - j.storage->clear_error(); + test_error(j); break; } j.str = j.storage->save_path().string(); @@ -1010,12 +1000,7 @@ namespace libtorrent } #endif ret = j.storage->release_files_impl(); - if (ret != 0) - { - j.str = j.storage->error(); - j.error_file = j.storage->error_file(); - j.storage->clear_error(); - } + if (ret != 0) test_error(j); break; } case disk_io_job::delete_files: @@ -1051,12 +1036,7 @@ namespace libtorrent } #endif ret = j.storage->delete_files_impl(); - if (ret != 0) - { - j.str = j.storage->error(); - j.error_file = j.storage->error_file(); - j.storage->clear_error(); - } + if (ret != 0) test_error(j); break; } case disk_io_job::check_fastresume: @@ -1090,6 +1070,13 @@ namespace libtorrent #endif if (ret != piece_manager::need_full_check) break; } + if (test_error(j)) + { + ret = piece_manager::fatal_disk_error; + break; + } + TORRENT_ASSERT(ret != -2 || !j.str.empty()); + // if the check is not done, add it at the end of the job queue if (ret == piece_manager::need_full_check) { @@ -1133,6 +1120,7 @@ namespace libtorrent #ifndef BOOST_NO_EXCEPTIONS try { #endif + TORRENT_ASSERT(ret != -2 || !j.str.empty()); if (handler) m_ios.post(bind(handler, ret, j)); #ifndef BOOST_NO_EXCEPTIONS } catch (std::exception&) diff --git a/src/file.cpp b/src/file.cpp index 050ec11c..8a9d8814 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -121,7 +121,7 @@ namespace } } #else - std::string utf8_native(std::string const& s) + std::string const& utf8_native(std::string const& s) { return s; } @@ -146,11 +146,11 @@ namespace libtorrent , m_open_mode(0) {} - impl(fs::path const& path, int mode) + impl(fs::path const& path, int mode, error_code& ec) : m_fd(-1) , m_open_mode(0) { - open(path, mode); + open(path, mode, ec); } ~impl() @@ -158,30 +158,33 @@ namespace libtorrent close(); } - bool open(fs::path const& path, int mode) + bool open(fs::path const& path, int mode, error_code& ec) { close(); -#if defined _WIN32 && defined UNICODE - std::wstring wpath(safe_convert(path.native_file_string())); - m_fd = ::_wopen( - wpath.c_str() - , map_open_mode(mode)); -#elif defined _WIN32 - m_fd = ::_open( - utf8_native(path.native_file_string()).c_str() - , map_open_mode(mode)); +#ifdef TORRENT_WINDOWS + + const int permissions = _S_IREAD | _S_IWRITE; + +#ifdef defined UNICODE +#define open _wopen + std::wstring file_path(safe_convert(path.native_file_string())); #else - m_fd = ::open( - utf8_native(path.native_file_string()).c_str() - , map_open_mode(mode)); +#define open _open + std::string const& file_path = path.native_file_string(); +#endif +#else // if not windows + const mode_t permissions = S_IRWXU | S_IRGRP | S_IROTH; + std::string const& file_path = path.native_file_string(); +#endif + m_fd = ::open(file_path.c_str(), map_open_mode(mode), permissions); + +#ifdef TORRENT_WINDOWS +#undef open #endif + if (m_fd == -1) { - std::stringstream msg; - msg << "open failed: '" << path.native_file_string() << "'. " - << std::strerror(errno); - if (!m_error) m_error.reset(new std::string); - *m_error = msg.str(); + ec = error_code(errno, get_posix_category()); return false; } m_open_mode = mode; @@ -201,7 +204,7 @@ namespace libtorrent m_open_mode = 0; } - size_type read(char* buf, size_type num_bytes) + size_type read(char* buf, size_type num_bytes, error_code& ec) { TORRENT_ASSERT(m_open_mode & mode_in); TORRENT_ASSERT(m_fd != -1); @@ -211,17 +214,11 @@ namespace libtorrent #else size_type ret = ::read(m_fd, buf, num_bytes); #endif - if (ret == -1) - { - std::stringstream msg; - msg << "read failed: " << std::strerror(errno); - if (!m_error) m_error.reset(new std::string); - *m_error = msg.str(); - } + if (ret == -1) ec = error_code(errno, get_posix_category()); return ret; } - size_type write(const char* buf, size_type num_bytes) + size_type write(const char* buf, size_type num_bytes, error_code& ec) { TORRENT_ASSERT(m_open_mode & mode_out); TORRENT_ASSERT(m_fd != -1); @@ -236,34 +233,25 @@ namespace libtorrent #else size_type ret = ::write(m_fd, buf, num_bytes); #endif - if (ret == -1) - { - std::stringstream msg; - msg << "write failed: " << std::strerror(errno); - if (!m_error) m_error.reset(new std::string); - *m_error = msg.str(); - } + if (ret == -1) ec = error_code(errno, get_posix_category()); return ret; } - bool set_size(size_type s) + bool set_size(size_type s, error_code& ec) { #ifdef _WIN32 #error file.cpp is for posix systems only. use file_win.cpp on windows #else if (ftruncate(m_fd, s) < 0) { - std::stringstream msg; - msg << "ftruncate failed: '" << std::strerror(errno); - if (!m_error) m_error.reset(new std::string); - *m_error = msg.str(); + ec = error_code(errno, get_posix_category()); return false; } return true; #endif } - size_type seek(size_type offset, int m = 1) + size_type seek(size_type offset, int m, error_code& ec) { TORRENT_ASSERT(m_open_mode); TORRENT_ASSERT(m_fd != -1); @@ -278,56 +266,42 @@ namespace libtorrent // For some strange reason this fails // on win32. Use windows specific file // wrapper instead. - if (ret == -1) - { - std::stringstream msg; - msg << "seek failed: '" << std::strerror(errno) - << "' fd: " << m_fd - << " offset: " << offset - << " seekdir: " << seekdir; - if (!m_error) m_error.reset(new std::string); - *m_error = msg.str(); - return -1; - } + if (ret < 0) ec = error_code(errno, get_posix_category()); return ret; } - size_type tell() + size_type tell(error_code& ec) { TORRENT_ASSERT(m_open_mode); TORRENT_ASSERT(m_fd != -1); + size_type ret; #ifdef _WIN32 - return _telli64(m_fd); + ret = _telli64(m_fd); #else - return lseek(m_fd, 0, SEEK_CUR); + ret = lseek(m_fd, 0, SEEK_CUR); #endif - } - - std::string const& error() const - { - if (!m_error) m_error.reset(new std::string); - return *m_error; + if (ret < 0) ec = error_code(errno, get_posix_category()); + return ret; } int m_fd; int m_open_mode; - mutable boost::scoped_ptr m_error; }; // pimpl forwardings file::file() : m_impl(new impl()) {} - file::file(fs::path const& p, file::open_mode m) - : m_impl(new impl(p, m.m_mask)) + file::file(fs::path const& p, file::open_mode m, error_code& ec) + : m_impl(new impl(p, m.m_mask, ec)) {} file::~file() {} - bool file::open(fs::path const& p, file::open_mode m) + bool file::open(fs::path const& p, file::open_mode m, error_code& ec) { - return m_impl->open(p, m.m_mask); + return m_impl->open(p, m.m_mask, ec); } void file::close() @@ -335,34 +309,28 @@ namespace libtorrent m_impl->close(); } - size_type file::write(const char* buf, size_type num_bytes) + size_type file::write(const char* buf, size_type num_bytes, error_code& ec) { - return m_impl->write(buf, num_bytes); + return m_impl->write(buf, num_bytes, ec); } - size_type file::read(char* buf, size_type num_bytes) + size_type file::read(char* buf, size_type num_bytes, error_code& ec) { - return m_impl->read(buf, num_bytes); + return m_impl->read(buf, num_bytes, ec); } - bool file::set_size(size_type s) + bool file::set_size(size_type s, error_code& ec) { - return m_impl->set_size(s); + return m_impl->set_size(s, ec); } - size_type file::seek(size_type pos, file::seek_mode m) + size_type file::seek(size_type pos, file::seek_mode m, error_code& ec) { - return m_impl->seek(pos, m.m_val); + return m_impl->seek(pos, m.m_val, ec); } - size_type file::tell() + size_type file::tell(error_code& ec) { - return m_impl->tell(); + return m_impl->tell(ec); } - - std::string const& file::error() const - { - return m_impl->error(); - } - } diff --git a/src/file_pool.cpp b/src/file_pool.cpp index 19bdb416..de914c70 100644 --- a/src/file_pool.cpp +++ b/src/file_pool.cpp @@ -30,9 +30,10 @@ POSSIBILITY OF SUCH DAMAGE. */ +#include #include "libtorrent/pch.hpp" - #include "libtorrent/file_pool.hpp" +#include "libtorrent/error_code.hpp" #include @@ -41,8 +42,38 @@ namespace libtorrent using boost::multi_index::nth_index; using boost::multi_index::get; +#if BOOST_VERSION >= 103500 + struct file_pool_error_category : boost::system::error_category + { + virtual const char* name() const { return "file pool error"; } + virtual std::string message(int ev) const + { + static char const* msgs[] = + { "no error", "torrent file collides with file from another torrent" }; + if (ev < 0 || ev >= sizeof(msgs)/sizeof(msgs[0])) + return "Unknown error"; + return msgs[ev]; + } + virtual boost::system::error_condition default_error_condition(int ev) const + { + return boost::system::error_condition(ev, *this); + } + virtual bool equivalent(int code, boost::system::error_condition const& condition) const + { + return default_error_condition(code) == condition; + } + virtual bool equivalent(boost::system::error_code const& code, int condition ) const + { + return *this == code.category() && code.value() == condition; + } + }; + + file_pool_error_category file_pool_category; + +#endif + boost::shared_ptr file_pool::open_file(void* st, fs::path const& p - , file::open_mode m, std::string& error) + , file::open_mode m, error_code& ec) { TORRENT_ASSERT(st != 0); TORRENT_ASSERT(p.is_complete()); @@ -60,8 +91,9 @@ namespace libtorrent { // this means that another instance of the storage // is using the exact same file. - error = "torrent uses the same file as another torrent " - "(" + p.string() + ")"; +#if BOOST_VERSION >= 103500 + ec = error_code(1, file_pool_category); +#endif return boost::shared_ptr(); } @@ -73,9 +105,8 @@ namespace libtorrent i->file_ptr.reset(); TORRENT_ASSERT(e.file_ptr.unique()); e.file_ptr->close(); - if (!e.file_ptr->open(p, m)) + if (!e.file_ptr->open(p, m, ec)) { - error = e.file_ptr->error(); m_files.erase(i); return boost::shared_ptr(); } @@ -97,17 +128,14 @@ namespace libtorrent lt.erase(i); } lru_file_entry e; - e.file_ptr.reset(new file); + e.file_ptr.reset(new (std::nothrow)file); if (!e.file_ptr) { - error = "no memory"; + ec = error_code(ENOMEM, get_posix_category()); return e.file_ptr; } - if (!e.file_ptr->open(p, m)) - { - error = e.file_ptr->error(); + if (!e.file_ptr->open(p, m, ec)) return boost::shared_ptr(); - } e.mode = m; e.key = st; e.file_path = p; diff --git a/src/storage.cpp b/src/storage.cpp index d6ecd4e7..d0024d2a 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -253,20 +253,20 @@ namespace namespace libtorrent { template - void recursive_copy(Path const& old_path, Path const& new_path, std::string& error) + void recursive_copy(Path const& old_path, Path const& new_path, error_code& ec) { using boost::filesystem::basic_directory_iterator; #ifndef BOOST_NO_EXCEPTIONS try { #endif - TORRENT_ASSERT(error.empty()); + TORRENT_ASSERT(!ec); if (is_directory(old_path)) { create_directory(new_path); for (basic_directory_iterator i(old_path), end; i != end; ++i) { - recursive_copy(i->path(), new_path / i->leaf(), error); - if (!error.empty()) return; + recursive_copy(i->path(), new_path / i->leaf(), ec); + if (ec) return; } } else @@ -274,7 +274,7 @@ namespace libtorrent copy_file(old_path, new_path); } #ifndef BOOST_NO_EXCEPTIONS - } catch (std::exception& e) { error = e.what(); } + } catch (std::exception& e) { ec = error_code(errno, get_posix_category()); } #endif } @@ -478,6 +478,7 @@ namespace libtorrent bool storage::initialize(bool allocate_files) { + error_code ec; // first, create all missing directories fs::path last_path; for (file_storage::iterator file_iter = files().begin(), @@ -508,18 +509,12 @@ namespace libtorrent // the directory exists. if (file_iter->size == 0) { -#ifndef BOOST_NO_EXCEPTIONS - try { -#endif - file(m_save_path / file_iter->path, file::out); -#ifndef BOOST_NO_EXCEPTIONS - } - catch (std::exception& e) + file(m_save_path / file_iter->path, file::out, ec); + if (ec) { - set_error((m_save_path / file_iter->path).string(), e.what()); + set_error(m_save_path / file_iter->path, ec); return true; } -#endif continue; } @@ -528,18 +523,22 @@ namespace libtorrent #endif if (allocate_files) { - std::string error; + error_code ec; boost::shared_ptr f = m_pool.open_file(this - , m_save_path / file_iter->path, file::in | file::out - , error); - if (f && f->error().empty()) - f->set_size(file_iter->size); + , m_save_path / file_iter->path, file::in | file::out, ec); + if (ec) set_error(m_save_path / file_iter->path, ec); + else if (f) + { + f->set_size(file_iter->size, ec); + if (ec) set_error(m_save_path / file_iter->path, ec); + } } #ifndef BOOST_NO_EXCEPTIONS } catch (std::exception& e) { - set_error((m_save_path / file_iter->path).string(), e.what()); + set_error(m_save_path / file_iter->path + , error_code(errno, get_posix_category())); return true; } #endif @@ -568,6 +567,15 @@ namespace libtorrent { #endif rename(old_path, new_path); +/* + error_code ec; + rename(old_path, new_path, ec); + if (ec) + { + set_error(old_path, ec); + return; + } +*/ if (!m_mapped_files) { m_mapped_files.reset(new file_storage(m_files)); } m_mapped_files->rename_file(index, new_filename); @@ -575,7 +583,7 @@ namespace libtorrent } catch (std::exception& e) { - set_error(old_name.string(), e.what()); + set_error(old_name, error_code(errno, get_posix_category())); return true; } #endif @@ -595,8 +603,7 @@ namespace libtorrent m_pool.release(this); buffer().swap(m_scratch_buffer); - int result = 0; - std::string error; + int error; std::string error_file; // delete the files from disk @@ -619,16 +626,14 @@ namespace libtorrent { fs::remove(safe_convert(p)); } catch (std::exception& e) { - error = e.what(); + error = errno; error_file = p; - result = 1; } #else if (std::remove(p.c_str()) != 0 && errno != ENOENT) { - error = std::strerror(errno); + error = errno; error_file = p; - result = errno; } #endif } @@ -644,26 +649,25 @@ namespace libtorrent { fs::remove(safe_convert(*i)); } catch (std::exception& e) { - error = e.what(); + error = errno; error_file = *i; - result = 1; } #else if (std::remove(i->c_str()) != 0 && errno != ENOENT) { - error = std::strerror(errno); + error = errno; error_file = *i; - result = errno; } #endif } - if (!error.empty()) + if (error) { - m_error.swap(error); + m_error = error_code(error, get_posix_category()); m_error_file.swap(error_file); + return true; } - return result != 0; + return false; } bool storage::write_resume_data(entry& rd) const @@ -832,11 +836,11 @@ namespace libtorrent } catch (std::exception& e) { - std::string err; - recursive_copy(old_path, new_path, err); - if (!err.empty()) + error_code ec; + recursive_copy(old_path, new_path, ec); + if (ec) { - set_error((m_save_path / files().name()).string(), e.what()); + set_error(m_save_path / files().name(), ec); return true; } m_save_path = save_path; @@ -964,30 +968,24 @@ namespace libtorrent } int buf_pos = 0; - std::string error; + error_code ec; boost::shared_ptr in(m_pool.open_file( - this, m_save_path / file_iter->path, file::in - , error)); - if (!in) + this, m_save_path / file_iter->path, file::in, ec)); + if (!in || ec) { - set_error((m_save_path / file_iter->path).string(), error); - return -1; - } - if (!in->error().empty()) - { - set_error((m_save_path / file_iter->path).string(), in->error()); + 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); - if (new_pos != 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).string(), "seek failed"); + set_error(m_save_path / file_iter->path, ec); return -1; } std::memset(buf + buf_pos, 0, size - buf_pos); @@ -995,8 +993,8 @@ namespace libtorrent } #ifndef NDEBUG - size_type in_tell = in->tell(); - TORRENT_ASSERT(in_tell == file_offset + file_iter->file_base); + size_type in_tell = in->tell(ec); + TORRENT_ASSERT(in_tell == file_offset + file_iter->file_base && !ec); #endif int left_to_read = size; @@ -1029,15 +1027,15 @@ namespace libtorrent == file_iter->path); #endif - int actual_read = int(in->read(buf + buf_pos, read_bytes)); + int actual_read = int(in->read(buf + buf_pos, read_bytes, ec)); - if (read_bytes != actual_read) + 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).string(), "read failed"); + set_error(m_save_path / file_iter->path, ec); return -1; } std::memset(buf + buf_pos, 0, size - buf_pos); @@ -1061,25 +1059,19 @@ namespace libtorrent fs::path path = m_save_path / file_iter->path; file_offset = 0; - std::string error; - in = m_pool.open_file( - this, path, file::in, error); - if (!in) - { - set_error(path.string(), error); - return -1; - } - if (!in->error().empty()) + error_code ec; + in = m_pool.open_file( this, path, file::in, ec); + if (!in || ec) { - set_error((m_save_path / file_iter->path).string(), in->error()); + set_error(path, ec); return -1; } - size_type pos = in->seek(file_iter->file_base); - if (pos != file_iter->file_base) + 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).string(), "seek failed"); + set_error(m_save_path / file_iter->path, ec); return -1; } std::memset(buf + buf_pos, 0, size - buf_pos); @@ -1125,28 +1117,23 @@ namespace libtorrent } fs::path p(m_save_path / file_iter->path); - std::string error; + error_code ec; boost::shared_ptr out = m_pool.open_file( - this, p, file::out | file::in, error); + this, p, file::out | file::in, ec); - if (!out) + if (!out || ec) { - set_error(p.string(), error); - return -1; - } - if (!out->error().empty()) - { - set_error(p.string(), out->error()); + 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); + size_type pos = out->seek(file_offset + file_iter->file_base, file::begin, ec); - if (pos != file_offset + file_iter->file_base) + if (pos != file_offset + file_iter->file_base || ec) { - set_error((m_save_path / file_iter->path).string(), "seek failed"); + set_error(p, ec); return -1; } @@ -1180,11 +1167,12 @@ namespace libtorrent TORRENT_ASSERT(buf_pos >= 0); TORRENT_ASSERT(write_bytes >= 0); - size_type written = out->write(buf + buf_pos, write_bytes); + error_code ec; + size_type written = out->write(buf + buf_pos, write_bytes, ec); - if (written != write_bytes) + if (written != write_bytes || ec) { - set_error((m_save_path / file_iter->path).string(), "write failed"); + set_error(m_save_path / file_iter->path, ec); return -1; } @@ -1205,26 +1193,21 @@ namespace libtorrent TORRENT_ASSERT(file_iter != files().end()); fs::path p = m_save_path / file_iter->path; file_offset = 0; - std::string error; + error_code ec; out = m_pool.open_file( - this, p, file::out | file::in, error); + this, p, file::out | file::in, ec); - if (!out) + if (!out || ec) { - set_error(p.string(), error); - return -1; - } - if (!out->error().empty()) - { - set_error(p.string(), out->error()); + set_error(p, ec); return -1; } - size_type pos = out->seek(file_iter->file_base); + size_type pos = out->seek(file_iter->file_base, file::begin, ec); - if (pos != file_iter->file_base) + if (pos != file_iter->file_base || ec) { - set_error((m_save_path / file_iter->path).string(), "seek failed"); + set_error(p, ec); return -1; } } @@ -1723,6 +1706,7 @@ namespace libtorrent error = f.string(); error += ": "; error += e.what(); + TORRENT_ASSERT(!error.empty()); return fatal_disk_error; } #endif @@ -1762,8 +1746,8 @@ namespace libtorrent { if (m_storage->initialize(m_storage_mode == storage_mode_allocate)) { - error = m_storage->error(); - m_storage->clear_error(); + error = m_storage->error().message(); + TORRENT_ASSERT(!error.empty()); return fatal_disk_error; } m_state = state_finished; @@ -2021,8 +2005,8 @@ namespace libtorrent if (m_storage->read(&m_scratch_buffer2[0], piece, 0, piece_size) != piece_size) { - error = m_storage->error(); - m_storage->clear_error(); + error = m_storage->error().message(); + TORRENT_ASSERT(!error.empty()); return fatal_disk_error; } m_scratch_piece = other_piece; @@ -2034,8 +2018,8 @@ namespace libtorrent int piece_size = m_files.piece_size(piece); if (m_storage->write(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size) { - error = m_storage->error(); - m_storage->clear_error(); + error = m_storage->error().message(); + TORRENT_ASSERT(!error.empty()); return fatal_disk_error; } m_piece_to_slot[piece] = piece; @@ -2075,8 +2059,8 @@ namespace libtorrent int piece_size = m_files.piece_size(other_piece); if (m_storage->read(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size) { - error = m_storage->error(); - m_storage->clear_error(); + error = m_storage->error().message(); + TORRENT_ASSERT(!error.empty()); return fatal_disk_error; } m_scratch_piece = other_piece; @@ -2095,9 +2079,16 @@ namespace libtorrent TORRENT_ASSERT(m_state == state_full_check); - bool skip = check_one_piece(have_piece); + int skip = check_one_piece(have_piece); TORRENT_ASSERT(m_current_slot <= m_files.num_pieces()); + if (skip == -1) + { + error = m_storage->error().message(); + TORRENT_ASSERT(!error.empty()); + return fatal_disk_error; + } + if (skip) { clear_error(); @@ -2174,7 +2165,8 @@ namespace libtorrent return need_full_check; } - bool piece_manager::check_one_piece(int& have_piece) + // -1=error 0=ok 1=skip + int piece_manager::check_one_piece(int& have_piece) { // ------------------------ // DO THE FULL CHECK @@ -2196,9 +2188,20 @@ namespace libtorrent int num_read = m_storage->read(&m_piece_data[0] , m_current_slot, 0, piece_size); + if (num_read < 0) + { + if (m_storage->error() + && m_storage->error() != error_code(ENOENT, get_posix_category())) + { + std::cerr << m_storage->error().message() << std::endl; + return -1; + } + return 1; + } + // if the file is incomplete, skip the rest of it if (num_read != piece_size) - return true; + return 1; int piece_index = identify_data(m_piece_data, m_current_slot); @@ -2271,7 +2274,7 @@ namespace libtorrent else ret |= m_storage->move_slot(m_current_slot, other_slot); - if (ret) return true; + if (ret) return 1; TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot); @@ -2304,7 +2307,7 @@ namespace libtorrent ret |= m_storage->move_slot(other_slot, m_current_slot); } - if (ret) return true; + if (ret) return 1; TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot); @@ -2388,7 +2391,7 @@ namespace libtorrent ret |= m_storage->move_slot(slot2, m_current_slot); } - if (ret) return true; + if (ret) return 1; TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot); @@ -2411,7 +2414,7 @@ namespace libtorrent TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned || m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot); } - return false; + return 0; } void piece_manager::switch_to_full_mode() diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index c6c222fa..03dc235d 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -211,14 +211,19 @@ namespace libtorrent int load_file(fs::path const& filename, std::vector& v) { file f; - if (!f.open(filename, file::in)) return -1; - f.seek(0, file::end); - size_type s = f.tell(); + error_code ec; + if (!f.open(filename, file::in, ec)) return -1; + f.seek(0, file::end, ec); + if (ec) return -1; + size_type s = f.tell(ec); + if (ec) return -1; if (s > 5000000) return -2; v.resize(s); - f.seek(0); - size_type read = f.read(&v[0], s); + f.seek(0, file::begin, ec); + if (ec) return -1; + size_type read = f.read(&v[0], s, ec); if (read != s) return -3; + if (ec) return -3; return 0; } -- 2.11.4.GIT