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;
// the error code from the file operation
error_code error;
// this is called when operation completes
boost::function<void(int, disk_io_job const&)> callback;
};
@ -214,6 +217,8 @@ namespace libtorrent
typedef boost::recursive_mutex mutex_t;
typedef std::list<cached_piece_entry> 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

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)
#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:

View File

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

View File

@ -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<libtorrent::ptime> deadline_timer;
#else
using boost::system::error_code;
using boost::asio::ip::tcp;
using boost::asio::ip::udp;
using boost::asio::async_write;

View File

@ -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<char>& piece_data
, int current_slot);

View File

@ -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&)

View File

@ -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<std::string> 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();
}
}

View File

@ -30,9 +30,10 @@ POSSIBILITY OF SUCH DAMAGE.
*/
#include <boost/version.hpp>
#include "libtorrent/pch.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"
#include <iostream>
@ -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> 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<file>();
}
@ -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<file>();
}
@ -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<file>();
}
e.mode = m;
e.key = st;
e.file_path = p;

View File

@ -253,20 +253,20 @@ namespace
namespace libtorrent
{
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;
#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<Path> 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<file> 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<file> 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)
error_code ec;
in = m_pool.open_file( this, path, file::in, ec);
if (!in || ec)
{
set_error(path.string(), error);
set_error(path, ec);
return -1;
}
if (!in->error().empty())
{
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)
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<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);
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()

View File

@ -211,14 +211,19 @@ namespace libtorrent
int load_file(fs::path const& filename, std::vector<char>& 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;
}