improved error reporting of file errors (uses boost.system's error_code). Now permission errors are properly reported when checking files

This commit is contained in:
Arvid Norberg
2008-07-17 23:41:46 +00:00
parent 86d8b54f5b
commit 3cb1369385
11 changed files with 336 additions and 283 deletions

View File

@@ -111,6 +111,9 @@ namespace libtorrent
boost::shared_ptr<entry> resume_data; boost::shared_ptr<entry> resume_data;
// the error code from the file operation
error_code error;
// this is called when operation completes // this is called when operation completes
boost::function<void(int, disk_io_job const&)> callback; boost::function<void(int, disk_io_job const&)> callback;
}; };
@@ -214,6 +217,8 @@ namespace libtorrent
typedef boost::recursive_mutex mutex_t; typedef boost::recursive_mutex mutex_t;
typedef std::list<cached_piece_entry> cache_t; typedef std::list<cached_piece_entry> cache_t;
bool test_error(disk_io_job& j);
// cache operations // cache operations
cache_t::iterator find_cached_piece( cache_t::iterator find_cached_piece(
cache_t& cache, disk_io_job const& j cache_t& cache, disk_io_job const& j

View File

@@ -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 <boost/version.hpp>
#if BOOST_VERSION < 103500
#include <asio/error_code.hpp>
#else
#include <boost/system/error_code.hpp>
#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

View File

@@ -48,6 +48,7 @@ POSSIBILITY OF SUCH DAMAGE.
#pragma warning(pop) #pragma warning(pop)
#endif #endif
#include "libtorrent/error_code.hpp"
#include "libtorrent/size_type.hpp" #include "libtorrent/size_type.hpp"
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
@@ -102,20 +103,18 @@ namespace libtorrent
static const open_mode out; static const open_mode out;
file(); file();
file(fs::path const& p, open_mode m); file(fs::path const& p, open_mode m, error_code& ec);
~file(); ~file();
bool open(fs::path const& p, open_mode m); bool open(fs::path const& p, open_mode m, error_code& ec);
void close(); 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 write(const char*, size_type num_bytes, error_code& ec);
size_type read(char*, size_type num_bytes); size_type read(char*, size_type num_bytes, error_code& ec);
size_type seek(size_type pos, seek_mode m = begin); size_type seek(size_type pos, seek_mode m, error_code& ec);
size_type tell(); size_type tell(error_code& ec);
std::string const& error() const;
private: private:

View File

@@ -66,7 +66,7 @@ namespace libtorrent
file_pool(int size = 40): m_size(size) {} file_pool(int size = 40): m_size(size) {}
boost::shared_ptr<file> open_file(void* st, fs::path const& p boost::shared_ptr<file> 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(void* st);
void release(fs::path const& p); void release(fs::path const& p);
void resize(int size); void resize(int size);

View File

@@ -73,6 +73,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/io.hpp" #include "libtorrent/io.hpp"
#include "libtorrent/time.hpp" #include "libtorrent/time.hpp"
#include "libtorrent/error_code.hpp"
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
@@ -94,12 +95,10 @@ namespace libtorrent
typedef asio::ip::udp::socket datagram_socket; typedef asio::ip::udp::socket datagram_socket;
typedef asio::ip::tcp::acceptor socket_acceptor; typedef asio::ip::tcp::acceptor socket_acceptor;
typedef asio::io_service io_service; typedef asio::io_service io_service;
typedef asio::error_code error_code;
namespace asio = ::asio; namespace asio = ::asio;
typedef asio::basic_deadline_timer<libtorrent::ptime> deadline_timer; typedef asio::basic_deadline_timer<libtorrent::ptime> deadline_timer;
#else #else
using boost::system::error_code;
using boost::asio::ip::tcp; using boost::asio::ip::tcp;
using boost::asio::ip::udp; using boost::asio::ip::udp;
using boost::asio::async_write; using boost::asio::async_write;

View File

@@ -164,17 +164,17 @@ namespace libtorrent
// non-zero return value indicates an error // non-zero return value indicates an error
virtual bool delete_files() = 0; 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_file = file.string();
m_error = msg; 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; } 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; mutable std::string m_error_file;
virtual ~storage_interface() {} virtual ~storage_interface() {}
@@ -267,7 +267,7 @@ namespace libtorrent
void mark_failed(int index); 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(); } std::string const& error_file() const { return m_storage->error_file(); }
void clear_error() { m_storage->clear_error(); } void clear_error() { m_storage->clear_error(); }
@@ -308,7 +308,8 @@ namespace libtorrent
, int offset , int offset
, int size); , 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( int identify_data(
const std::vector<char>& piece_data const std::vector<char>& piece_data
, int current_slot); , int current_slot);

View File

@@ -420,7 +420,7 @@ namespace libtorrent
l.unlock(); l.unlock();
ret += p.storage->read_impl(buf.get(), p.piece, start_block * m_block_size, buffer_size); ret += p.storage->read_impl(buf.get(), p.piece, start_block * m_block_size, buffer_size);
l.lock(); l.lock();
if (!p.storage->error().empty()) { return -1; } if (p.storage->error()) { return -1; }
++m_cache_stats.reads; ++m_cache_stats.reads;
} }
@@ -440,7 +440,7 @@ namespace libtorrent
{ {
l.unlock(); l.unlock();
ret += p.storage->read_impl(p.blocks[i], p.piece, piece_offset, block_size); 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(); l.lock();
++m_cache_stats.reads; ++m_cache_stats.reads;
} }
@@ -735,6 +735,23 @@ namespace libtorrent
#endif #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()() void disk_io_thread::operator()()
{ {
for (;;) for (;;)
@@ -819,17 +836,10 @@ namespace libtorrent
} }
case disk_io_job::read: case disk_io_job::read:
{ {
std::string const& error_string = j.storage->error(); if (test_error(j))
if (!error_string.empty())
{ {
#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; ret = -1;
break; return;
} }
#ifdef TORRENT_DISK_STATS #ifdef TORRENT_DISK_STATS
m_log << log_time() << " read " << j.buffer_size << std::endl; m_log << log_time() << " read " << j.buffer_size << std::endl;
@@ -841,7 +851,8 @@ namespace libtorrent
if (j.buffer == 0) if (j.buffer == 0)
{ {
ret = -1; ret = -1;
j.str = "out of memory"; j.error = error_code(ENOMEM, get_posix_category());
j.str = j.error.message();
break; break;
} }
@@ -853,9 +864,7 @@ namespace libtorrent
if (ret == -1) if (ret == -1)
{ {
j.buffer = 0; j.buffer = 0;
j.str = j.storage->error(); test_error(j);
j.error_file = j.storage->error_file();
j.storage->clear_error();
break; break;
} }
else if (ret == -2) else if (ret == -2)
@@ -864,9 +873,7 @@ namespace libtorrent
, j.buffer_size); , j.buffer_size);
if (ret < 0) if (ret < 0)
{ {
j.str = j.storage->error(); test_error(j);
j.error_file = j.storage->error_file();
j.storage->clear_error();
break; break;
} }
++m_cache_stats.blocks_read; ++m_cache_stats.blocks_read;
@@ -876,15 +883,8 @@ namespace libtorrent
} }
case disk_io_job::write: case disk_io_job::write:
{ {
std::string const& error_string = j.storage->error(); if (test_error(j))
if (!error_string.empty())
{ {
#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; ret = -1;
break; break;
} }
@@ -936,26 +936,18 @@ namespace libtorrent
if (i != m_pieces.end()) if (i != m_pieces.end())
{ {
flush_and_remove(i, l); flush_and_remove(i, l);
std::string const& e = j.storage->error(); if (test_error(j))
if (!e.empty())
{ {
j.str = e;
j.error_file = j.storage->error_file();
ret = -1; ret = -1;
j.storage->clear_error();
j.storage->mark_failed(j.piece); j.storage->mark_failed(j.piece);
break; break;
} }
} }
l.unlock(); l.unlock();
sha1_hash h = j.storage->hash_for_piece_impl(j.piece); sha1_hash h = j.storage->hash_for_piece_impl(j.piece);
std::string const& e = j.storage->error(); if (test_error(j))
if (!e.empty())
{ {
j.str = e;
j.error_file = j.storage->error_file();
ret = -1; ret = -1;
j.storage->clear_error();
j.storage->mark_failed(j.piece); j.storage->mark_failed(j.piece);
break; break;
} }
@@ -972,9 +964,7 @@ namespace libtorrent
ret = j.storage->move_storage_impl(j.str) ? 1 : 0; ret = j.storage->move_storage_impl(j.str) ? 1 : 0;
if (ret != 0) if (ret != 0)
{ {
j.str = j.storage->error(); test_error(j);
j.error_file = j.storage->error_file();
j.storage->clear_error();
break; break;
} }
j.str = j.storage->save_path().string(); j.str = j.storage->save_path().string();
@@ -1010,12 +1000,7 @@ namespace libtorrent
} }
#endif #endif
ret = j.storage->release_files_impl(); ret = j.storage->release_files_impl();
if (ret != 0) if (ret != 0) test_error(j);
{
j.str = j.storage->error();
j.error_file = j.storage->error_file();
j.storage->clear_error();
}
break; break;
} }
case disk_io_job::delete_files: case disk_io_job::delete_files:
@@ -1051,12 +1036,7 @@ namespace libtorrent
} }
#endif #endif
ret = j.storage->delete_files_impl(); ret = j.storage->delete_files_impl();
if (ret != 0) if (ret != 0) test_error(j);
{
j.str = j.storage->error();
j.error_file = j.storage->error_file();
j.storage->clear_error();
}
break; break;
} }
case disk_io_job::check_fastresume: case disk_io_job::check_fastresume:
@@ -1090,6 +1070,13 @@ namespace libtorrent
#endif #endif
if (ret != piece_manager::need_full_check) break; 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 the check is not done, add it at the end of the job queue
if (ret == piece_manager::need_full_check) if (ret == piece_manager::need_full_check)
{ {
@@ -1133,6 +1120,7 @@ namespace libtorrent
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
try { try {
#endif #endif
TORRENT_ASSERT(ret != -2 || !j.str.empty());
if (handler) m_ios.post(bind(handler, ret, j)); if (handler) m_ios.post(bind(handler, ret, j));
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
} catch (std::exception&) } catch (std::exception&)

View File

@@ -121,7 +121,7 @@ namespace
} }
} }
#else #else
std::string utf8_native(std::string const& s) std::string const& utf8_native(std::string const& s)
{ {
return s; return s;
} }
@@ -146,11 +146,11 @@ namespace libtorrent
, m_open_mode(0) , 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_fd(-1)
, m_open_mode(0) , m_open_mode(0)
{ {
open(path, mode); open(path, mode, ec);
} }
~impl() ~impl()
@@ -158,30 +158,33 @@ namespace libtorrent
close(); close();
} }
bool open(fs::path const& path, int mode) bool open(fs::path const& path, int mode, error_code& ec)
{ {
close(); close();
#if defined _WIN32 && defined UNICODE #ifdef TORRENT_WINDOWS
std::wstring wpath(safe_convert(path.native_file_string()));
m_fd = ::_wopen( const int permissions = _S_IREAD | _S_IWRITE;
wpath.c_str()
, map_open_mode(mode)); #ifdef defined UNICODE
#elif defined _WIN32 #define open _wopen
m_fd = ::_open( std::wstring file_path(safe_convert(path.native_file_string()));
utf8_native(path.native_file_string()).c_str()
, map_open_mode(mode));
#else #else
m_fd = ::open( #define open _open
utf8_native(path.native_file_string()).c_str() std::string const& file_path = path.native_file_string();
, map_open_mode(mode));
#endif #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) if (m_fd == -1)
{ {
std::stringstream msg; ec = error_code(errno, get_posix_category());
msg << "open failed: '" << path.native_file_string() << "'. "
<< std::strerror(errno);
if (!m_error) m_error.reset(new std::string);
*m_error = msg.str();
return false; return false;
} }
m_open_mode = mode; m_open_mode = mode;
@@ -201,7 +204,7 @@ namespace libtorrent
m_open_mode = 0; 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_open_mode & mode_in);
TORRENT_ASSERT(m_fd != -1); TORRENT_ASSERT(m_fd != -1);
@@ -211,17 +214,11 @@ namespace libtorrent
#else #else
size_type ret = ::read(m_fd, buf, num_bytes); size_type ret = ::read(m_fd, buf, num_bytes);
#endif #endif
if (ret == -1) if (ret == -1) ec = error_code(errno, get_posix_category());
{
std::stringstream msg;
msg << "read failed: " << std::strerror(errno);
if (!m_error) m_error.reset(new std::string);
*m_error = msg.str();
}
return ret; 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_open_mode & mode_out);
TORRENT_ASSERT(m_fd != -1); TORRENT_ASSERT(m_fd != -1);
@@ -236,34 +233,25 @@ namespace libtorrent
#else #else
size_type ret = ::write(m_fd, buf, num_bytes); size_type ret = ::write(m_fd, buf, num_bytes);
#endif #endif
if (ret == -1) if (ret == -1) ec = error_code(errno, get_posix_category());
{
std::stringstream msg;
msg << "write failed: " << std::strerror(errno);
if (!m_error) m_error.reset(new std::string);
*m_error = msg.str();
}
return ret; return ret;
} }
bool set_size(size_type s) bool set_size(size_type s, error_code& ec)
{ {
#ifdef _WIN32 #ifdef _WIN32
#error file.cpp is for posix systems only. use file_win.cpp on windows #error file.cpp is for posix systems only. use file_win.cpp on windows
#else #else
if (ftruncate(m_fd, s) < 0) if (ftruncate(m_fd, s) < 0)
{ {
std::stringstream msg; ec = error_code(errno, get_posix_category());
msg << "ftruncate failed: '" << std::strerror(errno);
if (!m_error) m_error.reset(new std::string);
*m_error = msg.str();
return false; return false;
} }
return true; return true;
#endif #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_open_mode);
TORRENT_ASSERT(m_fd != -1); TORRENT_ASSERT(m_fd != -1);
@@ -278,56 +266,42 @@ namespace libtorrent
// For some strange reason this fails // For some strange reason this fails
// on win32. Use windows specific file // on win32. Use windows specific file
// wrapper instead. // wrapper instead.
if (ret == -1) if (ret < 0) ec = error_code(errno, get_posix_category());
{
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;
}
return ret; return ret;
} }
size_type tell() size_type tell(error_code& ec)
{ {
TORRENT_ASSERT(m_open_mode); TORRENT_ASSERT(m_open_mode);
TORRENT_ASSERT(m_fd != -1); TORRENT_ASSERT(m_fd != -1);
size_type ret;
#ifdef _WIN32 #ifdef _WIN32
return _telli64(m_fd); ret = _telli64(m_fd);
#else #else
return lseek(m_fd, 0, SEEK_CUR); ret = lseek(m_fd, 0, SEEK_CUR);
#endif #endif
} if (ret < 0) ec = error_code(errno, get_posix_category());
return ret;
std::string const& error() const
{
if (!m_error) m_error.reset(new std::string);
return *m_error;
} }
int m_fd; int m_fd;
int m_open_mode; int m_open_mode;
mutable boost::scoped_ptr<std::string> m_error;
}; };
// pimpl forwardings // pimpl forwardings
file::file() : m_impl(new impl()) {} file::file() : m_impl(new impl()) {}
file::file(fs::path const& p, file::open_mode m) file::file(fs::path const& p, file::open_mode m, error_code& ec)
: m_impl(new impl(p, m.m_mask)) : m_impl(new impl(p, m.m_mask, ec))
{} {}
file::~file() {} 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() void file::close()
@@ -335,34 +309,28 @@ namespace libtorrent
m_impl->close(); 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();
}
} }

View File

@@ -30,9 +30,10 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <boost/version.hpp>
#include "libtorrent/pch.hpp" #include "libtorrent/pch.hpp"
#include "libtorrent/file_pool.hpp" #include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"
#include <iostream> #include <iostream>
@@ -41,8 +42,38 @@ namespace libtorrent
using boost::multi_index::nth_index; using boost::multi_index::nth_index;
using boost::multi_index::get; 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> file_pool::open_file(void* st, fs::path const& p boost::shared_ptr<file> 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(st != 0);
TORRENT_ASSERT(p.is_complete()); TORRENT_ASSERT(p.is_complete());
@@ -60,8 +91,9 @@ namespace libtorrent
{ {
// this means that another instance of the storage // this means that another instance of the storage
// is using the exact same file. // is using the exact same file.
error = "torrent uses the same file as another torrent " #if BOOST_VERSION >= 103500
"(" + p.string() + ")"; ec = error_code(1, file_pool_category);
#endif
return boost::shared_ptr<file>(); return boost::shared_ptr<file>();
} }
@@ -73,9 +105,8 @@ namespace libtorrent
i->file_ptr.reset(); i->file_ptr.reset();
TORRENT_ASSERT(e.file_ptr.unique()); TORRENT_ASSERT(e.file_ptr.unique());
e.file_ptr->close(); 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); m_files.erase(i);
return boost::shared_ptr<file>(); return boost::shared_ptr<file>();
} }
@@ -97,17 +128,14 @@ namespace libtorrent
lt.erase(i); lt.erase(i);
} }
lru_file_entry e; lru_file_entry e;
e.file_ptr.reset(new file); e.file_ptr.reset(new (std::nothrow)file);
if (!e.file_ptr) if (!e.file_ptr)
{ {
error = "no memory"; ec = error_code(ENOMEM, get_posix_category());
return e.file_ptr; return e.file_ptr;
} }
if (!e.file_ptr->open(p, m)) if (!e.file_ptr->open(p, m, ec))
{
error = e.file_ptr->error();
return boost::shared_ptr<file>(); return boost::shared_ptr<file>();
}
e.mode = m; e.mode = m;
e.key = st; e.key = st;
e.file_path = p; e.file_path = p;

View File

@@ -253,20 +253,20 @@ namespace
namespace libtorrent namespace libtorrent
{ {
template <class Path> template <class Path>
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; using boost::filesystem::basic_directory_iterator;
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
try { try {
#endif #endif
TORRENT_ASSERT(error.empty()); TORRENT_ASSERT(!ec);
if (is_directory(old_path)) if (is_directory(old_path))
{ {
create_directory(new_path); create_directory(new_path);
for (basic_directory_iterator<Path> i(old_path), end; i != end; ++i) for (basic_directory_iterator<Path> i(old_path), end; i != end; ++i)
{ {
recursive_copy(i->path(), new_path / i->leaf(), error); recursive_copy(i->path(), new_path / i->leaf(), ec);
if (!error.empty()) return; if (ec) return;
} }
} }
else else
@@ -274,7 +274,7 @@ namespace libtorrent
copy_file(old_path, new_path); copy_file(old_path, new_path);
} }
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
} catch (std::exception& e) { error = e.what(); } } catch (std::exception& e) { ec = error_code(errno, get_posix_category()); }
#endif #endif
} }
@@ -478,6 +478,7 @@ namespace libtorrent
bool storage::initialize(bool allocate_files) bool storage::initialize(bool allocate_files)
{ {
error_code ec;
// first, create all missing directories // first, create all missing directories
fs::path last_path; fs::path last_path;
for (file_storage::iterator file_iter = files().begin(), for (file_storage::iterator file_iter = files().begin(),
@@ -508,18 +509,12 @@ namespace libtorrent
// the directory exists. // the directory exists.
if (file_iter->size == 0) if (file_iter->size == 0)
{ {
#ifndef BOOST_NO_EXCEPTIONS file(m_save_path / file_iter->path, file::out, ec);
try { if (ec)
#endif
file(m_save_path / file_iter->path, file::out);
#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, ec);
return true; return true;
} }
#endif
continue; continue;
} }
@@ -528,18 +523,22 @@ namespace libtorrent
#endif #endif
if (allocate_files) if (allocate_files)
{ {
std::string error; error_code ec;
boost::shared_ptr<file> f = m_pool.open_file(this boost::shared_ptr<file> f = m_pool.open_file(this
, m_save_path / file_iter->path, file::in | file::out , m_save_path / file_iter->path, file::in | file::out, ec);
, error); if (ec) set_error(m_save_path / file_iter->path, ec);
if (f && f->error().empty()) else if (f)
f->set_size(file_iter->size); {
f->set_size(file_iter->size, ec);
if (ec) set_error(m_save_path / file_iter->path, ec);
}
} }
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
} }
catch (std::exception& e) 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; return true;
} }
#endif #endif
@@ -568,6 +567,15 @@ namespace libtorrent
{ {
#endif #endif
rename(old_path, new_path); 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) if (!m_mapped_files)
{ m_mapped_files.reset(new file_storage(m_files)); } { m_mapped_files.reset(new file_storage(m_files)); }
m_mapped_files->rename_file(index, new_filename); m_mapped_files->rename_file(index, new_filename);
@@ -575,7 +583,7 @@ namespace libtorrent
} }
catch (std::exception& e) catch (std::exception& e)
{ {
set_error(old_name.string(), e.what()); set_error(old_name, error_code(errno, get_posix_category()));
return true; return true;
} }
#endif #endif
@@ -595,8 +603,7 @@ namespace libtorrent
m_pool.release(this); m_pool.release(this);
buffer().swap(m_scratch_buffer); buffer().swap(m_scratch_buffer);
int result = 0; int error;
std::string error;
std::string error_file; std::string error_file;
// delete the files from disk // delete the files from disk
@@ -619,16 +626,14 @@ namespace libtorrent
{ fs::remove(safe_convert(p)); } { fs::remove(safe_convert(p)); }
catch (std::exception& e) catch (std::exception& e)
{ {
error = e.what(); error = errno;
error_file = p; error_file = p;
result = 1;
} }
#else #else
if (std::remove(p.c_str()) != 0 && errno != ENOENT) if (std::remove(p.c_str()) != 0 && errno != ENOENT)
{ {
error = std::strerror(errno); error = errno;
error_file = p; error_file = p;
result = errno;
} }
#endif #endif
} }
@@ -644,26 +649,25 @@ namespace libtorrent
{ fs::remove(safe_convert(*i)); } { fs::remove(safe_convert(*i)); }
catch (std::exception& e) catch (std::exception& e)
{ {
error = e.what(); error = errno;
error_file = *i; error_file = *i;
result = 1;
} }
#else #else
if (std::remove(i->c_str()) != 0 && errno != ENOENT) if (std::remove(i->c_str()) != 0 && errno != ENOENT)
{ {
error = std::strerror(errno); error = errno;
error_file = *i; error_file = *i;
result = errno;
} }
#endif #endif
} }
if (!error.empty()) if (error)
{ {
m_error.swap(error); m_error = error_code(error, get_posix_category());
m_error_file.swap(error_file); m_error_file.swap(error_file);
return true;
} }
return result != 0; return false;
} }
bool storage::write_resume_data(entry& rd) const bool storage::write_resume_data(entry& rd) const
@@ -832,11 +836,11 @@ namespace libtorrent
} }
catch (std::exception& e) catch (std::exception& e)
{ {
std::string err; error_code ec;
recursive_copy(old_path, new_path, err); recursive_copy(old_path, new_path, ec);
if (!err.empty()) if (ec)
{ {
set_error((m_save_path / files().name()).string(), e.what()); set_error(m_save_path / files().name(), ec);
return true; return true;
} }
m_save_path = save_path; m_save_path = save_path;
@@ -964,30 +968,24 @@ namespace libtorrent
} }
int buf_pos = 0; int buf_pos = 0;
std::string error; error_code ec;
boost::shared_ptr<file> in(m_pool.open_file( boost::shared_ptr<file> in(m_pool.open_file(
this, m_save_path / file_iter->path, file::in this, m_save_path / file_iter->path, file::in, ec));
, error)); if (!in || ec)
if (!in)
{ {
set_error((m_save_path / file_iter->path).string(), error); set_error(m_save_path / file_iter->path, ec);
return -1;
}
if (!in->error().empty())
{
set_error((m_save_path / file_iter->path).string(), in->error());
return -1; return -1;
} }
TORRENT_ASSERT(file_offset < file_iter->size); TORRENT_ASSERT(file_offset < file_iter->size);
TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base); TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base);
size_type new_pos = in->seek(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) if (new_pos != file_offset + file_iter->file_base || ec)
{ {
// the file was not big enough // the file was not big enough
if (!fill_zero) 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; return -1;
} }
std::memset(buf + buf_pos, 0, size - buf_pos); std::memset(buf + buf_pos, 0, size - buf_pos);
@@ -995,8 +993,8 @@ namespace libtorrent
} }
#ifndef NDEBUG #ifndef NDEBUG
size_type in_tell = in->tell(); size_type in_tell = in->tell(ec);
TORRENT_ASSERT(in_tell == file_offset + file_iter->file_base); TORRENT_ASSERT(in_tell == file_offset + file_iter->file_base && !ec);
#endif #endif
int left_to_read = size; int left_to_read = size;
@@ -1029,15 +1027,15 @@ namespace libtorrent
== file_iter->path); == file_iter->path);
#endif #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 // the file was not big enough
if (actual_read > 0) buf_pos += actual_read; if (actual_read > 0) buf_pos += actual_read;
if (!fill_zero) 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; return -1;
} }
std::memset(buf + buf_pos, 0, size - buf_pos); std::memset(buf + buf_pos, 0, size - buf_pos);
@@ -1061,25 +1059,19 @@ namespace libtorrent
fs::path path = m_save_path / file_iter->path; fs::path path = m_save_path / file_iter->path;
file_offset = 0; file_offset = 0;
std::string error; error_code ec;
in = m_pool.open_file( in = m_pool.open_file( this, path, file::in, ec);
this, path, file::in, error); if (!in || ec)
if (!in)
{ {
set_error(path.string(), error); set_error(path, ec);
return -1; return -1;
} }
if (!in->error().empty()) size_type pos = in->seek(file_iter->file_base, file::begin, ec);
{ if (pos != file_iter->file_base || ec)
set_error((m_save_path / file_iter->path).string(), in->error());
return -1;
}
size_type pos = in->seek(file_iter->file_base);
if (pos != file_iter->file_base)
{ {
if (!fill_zero) 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; return -1;
} }
std::memset(buf + buf_pos, 0, size - buf_pos); std::memset(buf + buf_pos, 0, size - buf_pos);
@@ -1125,28 +1117,23 @@ namespace libtorrent
} }
fs::path p(m_save_path / file_iter->path); fs::path p(m_save_path / file_iter->path);
std::string error; error_code ec;
boost::shared_ptr<file> out = m_pool.open_file( boost::shared_ptr<file> 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); set_error(p, ec);
return -1;
}
if (!out->error().empty())
{
set_error(p.string(), out->error());
return -1; return -1;
} }
TORRENT_ASSERT(file_offset < file_iter->size); TORRENT_ASSERT(file_offset < file_iter->size);
TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base); 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; return -1;
} }
@@ -1180,11 +1167,12 @@ namespace libtorrent
TORRENT_ASSERT(buf_pos >= 0); TORRENT_ASSERT(buf_pos >= 0);
TORRENT_ASSERT(write_bytes >= 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; return -1;
} }
@@ -1205,26 +1193,21 @@ namespace libtorrent
TORRENT_ASSERT(file_iter != files().end()); TORRENT_ASSERT(file_iter != files().end());
fs::path p = m_save_path / file_iter->path; fs::path p = m_save_path / file_iter->path;
file_offset = 0; file_offset = 0;
std::string error; error_code ec;
out = m_pool.open_file( 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); set_error(p, ec);
return -1;
}
if (!out->error().empty())
{
set_error(p.string(), out->error());
return -1; 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; return -1;
} }
} }
@@ -1723,6 +1706,7 @@ namespace libtorrent
error = f.string(); error = f.string();
error += ": "; error += ": ";
error += e.what(); error += e.what();
TORRENT_ASSERT(!error.empty());
return fatal_disk_error; return fatal_disk_error;
} }
#endif #endif
@@ -1762,8 +1746,8 @@ namespace libtorrent
{ {
if (m_storage->initialize(m_storage_mode == storage_mode_allocate)) if (m_storage->initialize(m_storage_mode == storage_mode_allocate))
{ {
error = m_storage->error(); error = m_storage->error().message();
m_storage->clear_error(); TORRENT_ASSERT(!error.empty());
return fatal_disk_error; return fatal_disk_error;
} }
m_state = state_finished; m_state = state_finished;
@@ -2021,8 +2005,8 @@ namespace libtorrent
if (m_storage->read(&m_scratch_buffer2[0], piece, 0, piece_size) if (m_storage->read(&m_scratch_buffer2[0], piece, 0, piece_size)
!= piece_size) != piece_size)
{ {
error = m_storage->error(); error = m_storage->error().message();
m_storage->clear_error(); TORRENT_ASSERT(!error.empty());
return fatal_disk_error; return fatal_disk_error;
} }
m_scratch_piece = other_piece; m_scratch_piece = other_piece;
@@ -2034,8 +2018,8 @@ namespace libtorrent
int piece_size = m_files.piece_size(piece); int piece_size = m_files.piece_size(piece);
if (m_storage->write(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size) if (m_storage->write(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size)
{ {
error = m_storage->error(); error = m_storage->error().message();
m_storage->clear_error(); TORRENT_ASSERT(!error.empty());
return fatal_disk_error; return fatal_disk_error;
} }
m_piece_to_slot[piece] = piece; m_piece_to_slot[piece] = piece;
@@ -2075,8 +2059,8 @@ namespace libtorrent
int piece_size = m_files.piece_size(other_piece); int piece_size = m_files.piece_size(other_piece);
if (m_storage->read(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size) if (m_storage->read(&m_scratch_buffer[0], piece, 0, piece_size) != piece_size)
{ {
error = m_storage->error(); error = m_storage->error().message();
m_storage->clear_error(); TORRENT_ASSERT(!error.empty());
return fatal_disk_error; return fatal_disk_error;
} }
m_scratch_piece = other_piece; m_scratch_piece = other_piece;
@@ -2095,9 +2079,16 @@ namespace libtorrent
TORRENT_ASSERT(m_state == state_full_check); 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()); 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) if (skip)
{ {
clear_error(); clear_error();
@@ -2174,7 +2165,8 @@ namespace libtorrent
return need_full_check; 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 // DO THE FULL CHECK
@@ -2196,9 +2188,20 @@ namespace libtorrent
int num_read = m_storage->read(&m_piece_data[0] int num_read = m_storage->read(&m_piece_data[0]
, m_current_slot, 0, piece_size); , 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 the file is incomplete, skip the rest of it
if (num_read != piece_size) if (num_read != piece_size)
return true; return 1;
int piece_index = identify_data(m_piece_data, m_current_slot); int piece_index = identify_data(m_piece_data, m_current_slot);
@@ -2271,7 +2274,7 @@ namespace libtorrent
else else
ret |= m_storage->move_slot(m_current_slot, other_slot); 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 TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot); || 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); 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 TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot); || 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); 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 TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot); || 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 TORRENT_ASSERT(m_slot_to_piece[m_current_slot] == unassigned
|| m_piece_to_slot[m_slot_to_piece[m_current_slot]] == m_current_slot); || 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() void piece_manager::switch_to_full_mode()

View File

@@ -211,14 +211,19 @@ namespace libtorrent
int load_file(fs::path const& filename, std::vector<char>& v) int load_file(fs::path const& filename, std::vector<char>& v)
{ {
file f; file f;
if (!f.open(filename, file::in)) return -1; error_code ec;
f.seek(0, file::end); if (!f.open(filename, file::in, ec)) return -1;
size_type s = f.tell(); 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; if (s > 5000000) return -2;
v.resize(s); v.resize(s);
f.seek(0); f.seek(0, file::begin, ec);
size_type read = f.read(&v[0], s); if (ec) return -1;
size_type read = f.read(&v[0], s, ec);
if (read != s) return -3; if (read != s) return -3;
if (ec) return -3;
return 0; return 0;
} }