changed storage interface to not require exceptions

This commit is contained in:
Arvid Norberg
2008-02-14 03:48:20 +00:00
parent c6de20173f
commit 7e83c3fc51
13 changed files with 891 additions and 655 deletions

View File

@@ -470,7 +470,8 @@ void add_torrent(libtorrent::session& ses
catch (boost::filesystem::filesystem_error&) {} catch (boost::filesystem::filesystem_error&) {}
torrent_handle h = ses.add_torrent(t, save_path, resume_data torrent_handle h = ses.add_torrent(t, save_path, resume_data
, compact_mode ? storage_mode_compact : storage_mode_sparse, false); , compact_mode ? storage_mode_compact : storage_mode_sparse, false
, mapped_storage_constructor);
handles.insert(std::make_pair( handles.insert(std::make_pair(
monitored_dir?std::string(torrent):std::string(), h)); monitored_dir?std::string(torrent):std::string(), h));
@@ -871,7 +872,7 @@ int main(int ac, char* av[])
torrent_handle h = ses.add_torrent(std::string(what[2]).c_str() torrent_handle h = ses.add_torrent(std::string(what[2]).c_str()
, info_hash, 0, save_path, entry(), compact_allocation_mode ? storage_mode_compact , info_hash, 0, save_path, entry(), compact_allocation_mode ? storage_mode_compact
: storage_mode_sparse); : storage_mode_sparse, false, mapped_storage_constructor);
handles.insert(std::make_pair(std::string(), h)); handles.insert(std::make_pair(std::string(), h));
h.set_max_connections(50); h.set_max_connections(50);

View File

@@ -111,7 +111,7 @@ namespace libtorrent
void open(fs::path const& p, open_mode m); void open(fs::path const& p, open_mode m);
void close(); void close();
void set_size(size_type size); bool set_size(size_type size);
size_type write(const char*, size_type num_bytes); size_type write(const char*, size_type num_bytes);
size_type read(char*, size_type num_bytes); size_type read(char*, size_type num_bytes);
@@ -119,6 +119,8 @@ namespace libtorrent
size_type seek(size_type pos, seek_mode m = begin); size_type seek(size_type pos, seek_mode m = begin);
size_type tell(); size_type tell();
std::string const& error() const;
private: private:
struct impl; struct impl;

View File

@@ -119,31 +119,33 @@ namespace libtorrent
// if allocate_files is true. // if allocate_files is true.
// allocate_files is true if allocation mode // allocate_files is true if allocation mode
// is set to full and sparse files are supported // is set to full and sparse files are supported
virtual void initialize(bool allocate_files) = 0; virtual bool initialize(bool allocate_files) = 0;
// may throw file_error if storage for slot does not exist // negative return value indicates an error
virtual size_type read(char* buf, int slot, int offset, int size) = 0; virtual size_type read(char* buf, int slot, int offset, int size) = 0;
// may throw file_error if storage for slot hasn't been allocated // may throw file_error if storage for slot hasn't been allocated
virtual void write(const char* buf, int slot, int offset, int size) = 0; // negative return value indicates an error
virtual size_type write(const char* buf, int slot, int offset, int size) = 0;
// non-zero return value indicates an error
virtual bool move_storage(fs::path save_path) = 0; virtual bool move_storage(fs::path save_path) = 0;
// verify storage dependent fast resume entries // verify storage dependent fast resume entries
virtual bool verify_resume_data(entry& rd, std::string& error) = 0; virtual bool verify_resume_data(entry const& rd, std::string& error) = 0;
// write storage dependent fast resume entries // write storage dependent fast resume entries
virtual void write_resume_data(entry& rd) const = 0; virtual bool write_resume_data(entry& rd) const = 0;
// moves (or copies) the content in src_slot to dst_slot // moves (or copies) the content in src_slot to dst_slot
virtual void move_slot(int src_slot, int dst_slot) = 0; virtual bool move_slot(int src_slot, int dst_slot) = 0;
// swaps the data in slot1 and slot2 // swaps the data in slot1 and slot2
virtual void swap_slots(int slot1, int slot2) = 0; virtual bool swap_slots(int slot1, int slot2) = 0;
// swaps the puts the data in slot1 in slot2, the data in slot2 // swaps the puts the data in slot1 in slot2, the data in slot2
// in slot3 and the data in slot3 in slot1 // in slot3 and the data in slot3 in slot1
virtual void swap_slots3(int slot1, int slot2, int slot3) = 0; virtual bool swap_slots3(int slot1, int slot2, int slot3) = 0;
// returns the sha1-hash for the data at the given slot // returns the sha1-hash for the data at the given slot
virtual sha1_hash hash_for_slot(int slot, partial_hash& h, int piece_size) = 0; virtual sha1_hash hash_for_slot(int slot, partial_hash& h, int piece_size) = 0;
@@ -151,10 +153,15 @@ namespace libtorrent
// this will close all open files that are opened for // this will close all open files that are opened for
// writing. This is called when a torrent has finished // writing. This is called when a torrent has finished
// downloading. // downloading.
virtual void release_files() = 0; // non-zero return value indicates an error
virtual bool release_files() = 0;
// this will close all open files and delete them // this will close all open files and delete them
virtual void delete_files() = 0; // non-zero return value indicates an error
virtual bool delete_files() = 0;
virtual std::string const& error() const = 0;
virtual void clear_error() = 0;
virtual ~storage_interface() {} virtual ~storage_interface() {}
}; };
@@ -197,19 +204,25 @@ namespace libtorrent
, std::vector<bool>& pieces, int& num_pieces, storage_mode_t storage_mode , std::vector<bool>& pieces, int& num_pieces, storage_mode_t storage_mode
, std::string& error_msg); , std::string& error_msg);
std::pair<bool, float> check_files(std::vector<bool>& pieces std::pair<bool, float> check_files(std::vector<bool>& pieces
, int& num_pieces, boost::recursive_mutex& mutex); , int& num_pieces, boost::recursive_mutex& mutex, bool& error);
// frees a buffer that was returned from a read operation // frees a buffer that was returned from a read operation
void free_buffer(char* buf); void free_buffer(char* buf);
void write_resume_data(entry& rd) const; void write_resume_data(entry& rd) const
bool verify_resume_data(entry& rd, std::string& error); { m_storage->write_resume_data(rd); }
bool verify_resume_data(entry const& rd, std::string& error)
{ return m_storage->verify_resume_data(rd, error); }
bool is_allocating() const bool is_allocating() const
{ return m_state == state_expand_pieces; } { return m_state == state_expand_pieces; }
void mark_failed(int index); void mark_failed(int index);
std::string const& error() const { return m_storage->error(); }
void clear_error() { m_storage->clear_error(); }
unsigned long piece_crc( unsigned long piece_crc(
int slot_index int slot_index
, int block_size , int block_size
@@ -276,17 +289,20 @@ namespace libtorrent
, int offset , int offset
, int size); , int size);
void write_impl( size_type write_impl(
const char* buf const char* buf
, int piece_index , int piece_index
, int offset , int offset
, int size); , int size);
bool check_one_piece(std::vector<bool>& pieces, int& num_pieces
, boost::recursive_mutex& mutex);
void switch_to_full_mode(); void switch_to_full_mode();
sha1_hash hash_for_piece_impl(int piece); sha1_hash hash_for_piece_impl(int piece);
void release_files_impl() { m_storage->release_files(); } int release_files_impl() { return m_storage->release_files(); }
void delete_files_impl() { m_storage->delete_files(); } int delete_files_impl() { return m_storage->delete_files(); }
bool move_storage_impl(fs::path const& save_path); bool move_storage_impl(fs::path const& save_path);

View File

@@ -159,7 +159,7 @@ namespace libtorrent
void set_sequential_download(bool sd); void set_sequential_download(bool sd);
bool verify_resume_data(entry& rd, std::string& error) bool verify_resume_data(entry const& rd, std::string& error)
{ TORRENT_ASSERT(m_storage); return m_storage->verify_resume_data(rd, error); } { TORRENT_ASSERT(m_storage); return m_storage->verify_resume_data(rd, error); }
void second_tick(stat& accumulator, float tick_interval); void second_tick(stat& accumulator, float tick_interval);
@@ -170,7 +170,7 @@ namespace libtorrent
std::string name() const; std::string name() const;
bool check_fastresume(aux::piece_checker_data&); bool check_fastresume(aux::piece_checker_data&);
std::pair<bool, float> check_files(); std::pair<bool, float> check_files(bool& error);
void files_checked(std::vector<piece_picker::downloading_piece> const& void files_checked(std::vector<piece_picker::downloading_piece> const&
unfinished_pieces); unfinished_pieces);

View File

@@ -60,6 +60,8 @@ for k in keys:
except: except:
print l print l
out.close()
peak_out.close()
out = open('send_buffer.gnuplot', 'wb') out = open('send_buffer.gnuplot', 'wb')
print >>out, "set term png size 1200,700" print >>out, "set term png size 1200,700"
@@ -79,5 +81,5 @@ for k in keys:
print >>out, 'x=0' print >>out, 'x=0'
out.close() out.close()
os.system('gnuplot send_buffer.gnuplot'); os.system('gnuplot send_buffer.gnuplot')

View File

@@ -461,16 +461,27 @@ namespace libtorrent
int ret = 0; int ret = 0;
bool free_current_buffer = true; bool free_current_buffer = true;
try TORRENT_ASSERT(j.storage);
{
TORRENT_ASSERT(j.storage);
#ifdef TORRENT_DISK_STATS #ifdef TORRENT_DISK_STATS
ptime start = time_now(); ptime start = time_now();
#endif #endif
// std::cerr << "DISK THREAD: executing job: " << j.action << std::endl; #ifndef BOOST_NO_EXCEPTIONS
try {
#endif
std::string const& error_string = j.storage->error();
if (!error_string.empty())
{
std::cout << "ERROR: " << error_string << std::endl;
j.str = error_string;
j.storage->clear_error();
ret = -1;
}
else
{
switch (j.action) switch (j.action)
{ {
case disk_io_job::read: case disk_io_job::read:
{
#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;
#endif #endif
@@ -488,7 +499,13 @@ namespace libtorrent
} }
ret = j.storage->read_impl(j.buffer, j.piece, j.offset ret = j.storage->read_impl(j.buffer, j.piece, j.offset
, j.buffer_size); , j.buffer_size);
if (ret < 0)
{
j.str = j.storage->error();
j.storage->clear_error();
}
break; break;
}
case disk_io_job::write: case disk_io_job::write:
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
@@ -527,17 +544,33 @@ namespace libtorrent
if (i != m_pieces.end()) flush_and_remove(i, l); if (i != m_pieces.end()) flush_and_remove(i, l);
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 (!e.empty())
{
j.str = e;
ret = -1;
j.storage->clear_error();
break;
}
j.str.resize(20); j.str.resize(20);
std::memcpy(&j.str[0], &h[0], 20); std::memcpy(&j.str[0], &h[0], 20);
break; break;
} }
case disk_io_job::move_storage: case disk_io_job::move_storage:
{
#ifdef TORRENT_DISK_STATS #ifdef TORRENT_DISK_STATS
m_log << log_time() << " move" << std::endl; m_log << log_time() << " move" << std::endl;
#endif #endif
ret = j.storage->move_storage_impl(j.str) ? 1 : 0; ret = j.storage->move_storage_impl(j.str) ? 1 : 0;
if (ret != 0)
{
j.str = j.storage->error();
j.storage->clear_error();
break;
}
j.str = j.storage->save_path().string(); j.str = j.storage->save_path().string();
break; break;
}
case disk_io_job::release_files: case disk_io_job::release_files:
{ {
#ifdef TORRENT_DISK_STATS #ifdef TORRENT_DISK_STATS
@@ -553,7 +586,12 @@ namespace libtorrent
m_pieces.erase(i, m_pieces.end()); m_pieces.erase(i, m_pieces.end());
m_pool.release_memory(); m_pool.release_memory();
l.unlock(); l.unlock();
j.storage->release_files_impl(); ret = j.storage->release_files_impl();
if (ret != 0)
{
j.str = j.storage->error();
j.storage->clear_error();
}
break; break;
} }
case disk_io_job::delete_files: case disk_io_job::delete_files:
@@ -580,26 +618,38 @@ namespace libtorrent
m_pieces.erase(i, m_pieces.end()); m_pieces.erase(i, m_pieces.end());
m_pool.release_memory(); m_pool.release_memory();
l.unlock(); l.unlock();
j.storage->delete_files_impl(); ret = j.storage->delete_files_impl();
if (ret != 0)
{
j.str = j.storage->error();
j.storage->clear_error();
}
break; break;
} }
} }
} }
catch (std::exception& e) #ifndef BOOST_NO_EXCEPTIONS
} catch (std::exception& e)
{ {
// std::cerr << "DISK THREAD: exception: " << e.what() << std::endl; ret = -1;
try try
{ {
j.str = e.what(); j.str = e.what();
} }
catch (std::exception&) {} catch (std::exception&) {}
ret = -1;
} }
#endif
// if (!handler) std::cerr << "DISK THREAD: no callback specified" << std::endl; // if (!handler) std::cerr << "DISK THREAD: no callback specified" << std::endl;
// else std::cerr << "DISK THREAD: invoking callback" << std::endl; // else std::cerr << "DISK THREAD: invoking callback" << std::endl;
#ifndef BOOST_NO_EXCEPTIONS
try {
#endif
if (handler) m_ios.post(bind(handler, ret, j));
#ifndef BOOST_NO_EXCEPTIONS
} catch (std::exception&) {}
#endif
if (handler) m_ios.post(bind(handler, ret, j));
#ifndef NDEBUG #ifndef NDEBUG
m_current.storage = 0; m_current.storage = 0;
@@ -608,6 +658,7 @@ namespace libtorrent
if (j.buffer && free_current_buffer) free_buffer(j.buffer); if (j.buffer && free_current_buffer) free_buffer(j.buffer);
} }
TORRENT_ASSERT(false);
} }
} }

View File

@@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/pch.hpp" #include "libtorrent/pch.hpp"
#include <boost/scoped_ptr.hpp>
#ifdef _WIN32 #ifdef _WIN32
// windows part // windows part
#include "libtorrent/utf8.hpp" #include "libtorrent/utf8.hpp"
@@ -186,7 +187,8 @@ namespace libtorrent
std::stringstream msg; std::stringstream msg;
msg << "open failed: '" << path.native_file_string() << "'. " msg << "open failed: '" << path.native_file_string() << "'. "
<< std::strerror(errno); << std::strerror(errno);
throw file_error(msg.str()); if (!m_error) m_error.reset(new std::string);
*m_error = msg.str();
} }
m_open_mode = mode; m_open_mode = mode;
} }
@@ -218,7 +220,8 @@ namespace libtorrent
{ {
std::stringstream msg; std::stringstream msg;
msg << "read failed: " << std::strerror(errno); msg << "read failed: " << std::strerror(errno);
throw file_error(msg.str()); if (!m_error) m_error.reset(new std::string);
*m_error = msg.str();
} }
return ret; return ret;
} }
@@ -242,12 +245,13 @@ namespace libtorrent
{ {
std::stringstream msg; std::stringstream msg;
msg << "write failed: " << std::strerror(errno); msg << "write failed: " << std::strerror(errno);
throw file_error(msg.str()); if (!m_error) m_error.reset(new std::string);
*m_error = msg.str();
} }
return ret; return ret;
} }
void set_size(size_type s) bool set_size(size_type s)
{ {
#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
@@ -256,8 +260,11 @@ namespace libtorrent
{ {
std::stringstream msg; std::stringstream msg;
msg << "ftruncate failed: '" << std::strerror(errno); msg << "ftruncate failed: '" << std::strerror(errno);
throw file_error(msg.str()); if (!m_error) m_error.reset(new std::string);
*m_error = msg.str();
return false;
} }
return true;
#endif #endif
} }
@@ -283,7 +290,9 @@ namespace libtorrent
<< "' fd: " << m_fd << "' fd: " << m_fd
<< " offset: " << offset << " offset: " << offset
<< " seekdir: " << seekdir; << " seekdir: " << seekdir;
throw file_error(msg.str()); if (!m_error) m_error.reset(new std::string);
*m_error = msg.str();
return -1;
} }
return ret; return ret;
} }
@@ -300,8 +309,15 @@ namespace libtorrent
#endif #endif
} }
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
@@ -334,9 +350,9 @@ namespace libtorrent
return m_impl->read(buf, num_bytes); return m_impl->read(buf, num_bytes);
} }
void file::set_size(size_type s) bool file::set_size(size_type s)
{ {
m_impl->set_size(s); return m_impl->set_size(s);
} }
size_type file::seek(size_type pos, file::seek_mode m) size_type file::seek(size_type pos, file::seek_mode m)
@@ -349,4 +365,9 @@ namespace libtorrent
return m_impl->tell(); return m_impl->tell();
} }
std::string const& file::error() const
{
return m_impl->error();
}
} }

View File

@@ -57,10 +57,14 @@ namespace libtorrent
if (e.key != st) if (e.key != st)
{ {
#ifdef BOOST_NO_EXCEPTIONS
return boost::shared_ptr<file>();
#else
// 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.
throw file_error("torrent uses the same file as another torrent " throw file_error("torrent uses the same file as another torrent "
"(" + p.string() + ")"); "(" + p.string() + ")");
#endif
} }
e.key = st; e.key = st;

View File

@@ -254,7 +254,7 @@ namespace libtorrent
, m_save_path(save_path) , m_save_path(save_path)
{} {}
void initialize(bool allocate_files) {} bool initialize(bool allocate_files) { return false; }
size_type read(char* buf, int slot, int offset, int size) size_type read(char* buf, int slot, int offset, int size)
{ {
@@ -292,7 +292,12 @@ namespace libtorrent
, file_iter->size + file_iter->file_base); , file_iter->size + file_iter->file_base);
if (!view.valid()) if (!view.valid())
throw file_error("failed to open file for reading"); {
m_error = "failed to open file '";
m_error += (m_save_path / file_iter->path).string();
m_error += "'for reading";
return -1;
}
int left_to_read = size; int left_to_read = size;
int slot_size = static_cast<int>(m_info->piece_size(slot)); int slot_size = static_cast<int>(m_info->piece_size(slot));
@@ -347,14 +352,20 @@ namespace libtorrent
view = m_pool.open_file(path, std::ios::in, file_offset + file_iter->file_base view = m_pool.open_file(path, std::ios::in, file_offset + file_iter->file_base
, left_to_read, this , left_to_read, this
, file_iter->size + file_iter->file_base); , file_iter->size + file_iter->file_base);
if (!view.valid()) if (!view.valid())
throw file_error("failed to open file for reading"); {
m_error = "failed to open file '";
m_error += (m_save_path / file_iter->path).string();
m_error += "'for reading";
return -1;
}
} }
} }
return result; return result;
} }
void write(const char* buf, int slot, int offset, int size) size_type write(const char* buf, int slot, int offset, int size)
{ {
TORRENT_ASSERT(buf != 0); TORRENT_ASSERT(buf != 0);
TORRENT_ASSERT(slot >= 0 && slot < m_info->num_pieces()); TORRENT_ASSERT(slot >= 0 && slot < m_info->num_pieces());
@@ -390,7 +401,12 @@ namespace libtorrent
, file_iter->size + file_iter->file_base); , file_iter->size + file_iter->file_base);
if (!view.valid()) if (!view.valid())
throw file_error("failed to open file for writing"); {
m_error = "failed to open file '";
m_error += (m_save_path / file_iter->path).string();
m_error += "'for writing";
return -1;
}
int left_to_write = size; int left_to_write = size;
int slot_size = static_cast<int>(m_info->piece_size(slot)); int slot_size = static_cast<int>(m_info->piece_size(slot));
@@ -442,10 +458,17 @@ namespace libtorrent
view = m_pool.open_file(path, std::ios::in | std::ios::out view = m_pool.open_file(path, std::ios::in | std::ios::out
, file_offset + file_iter->file_base, left_to_write, this , file_offset + file_iter->file_base, left_to_write, this
, file_iter->size + file_iter->file_base); , file_iter->size + file_iter->file_base);
if (!view.valid()) if (!view.valid())
throw file_error("failed to open file for reading"); {
m_error = "failed to open file '";
m_error += (m_save_path / file_iter->path).string();
m_error += "'for reading";
return -1;
}
} }
} }
return size;
} }
bool move_storage(fs::path save_path) bool move_storage(fs::path save_path)
@@ -509,17 +532,34 @@ namespace libtorrent
return false; return false;
} }
bool verify_resume_data(entry& rd, std::string& error) bool verify_resume_data(entry const& rd, std::string& error)
{ {
std::vector<std::pair<size_type, std::time_t> > file_sizes; if (rd.type() != entry::dictionary_t)
entry::list_type& l = rd["file sizes"].list(); {
error = "invalid fastresume file";
return true;
}
for (entry::list_type::iterator i = l.begin(); std::vector<std::pair<size_type, std::time_t> > file_sizes;
entry const* file_sizes_ent = rd.find_key("file sizes");
if (file_sizes_ent == 0 || file_sizes_ent->type() != entry::list_t)
{
error = "missing or invalid 'file sizes' entry in resume data";
return false;
}
entry::list_type const& l = file_sizes_ent->list();
for (entry::list_type::const_iterator i = l.begin();
i != l.end(); ++i) i != l.end(); ++i)
{ {
if (i->type() != entry::list_t) break;
entry::list_type const& pair = i->list();
if (pair.size() != 2 || pair.front().type() != entry::int_t
|| pair.back().type() != entry::int_t)
break;
file_sizes.push_back(std::pair<size_type, std::time_t>( file_sizes.push_back(std::pair<size_type, std::time_t>(
i->list().front().integer() pair.front().integer(), pair.back().integer()));
, i->list().back().integer()));
} }
if (file_sizes.empty()) if (file_sizes.empty())
@@ -528,7 +568,14 @@ namespace libtorrent
return false; return false;
} }
entry::list_type& slots = rd["slots"].list(); entry const* slots_ent = rd.find_key("slots");
if (slots_ent == 0 || slots_ent->type() != entry::list_t)
{
error = "missing or invalid 'slots' entry in resume data";
return false;
}
entry::list_type const& slots = slots_ent->list();
bool seed = int(slots.size()) == m_info->num_pieces() bool seed = int(slots.size()) == m_info->num_pieces()
&& std::find_if(slots.begin(), slots.end() && std::find_if(slots.begin(), slots.end()
, boost::bind<bool>(std::less<int>() , boost::bind<bool>(std::less<int>()
@@ -536,11 +583,9 @@ namespace libtorrent
&entry::integer, _1), 0)) == slots.end(); &entry::integer, _1), 0)) == slots.end();
bool full_allocation_mode = false; bool full_allocation_mode = false;
try entry const* allocation_mode = rd.find_key("allocation");
{ if (allocation_mode && allocation_mode->type() == entry::string_t)
full_allocation_mode = rd["allocation"].string() == "full"; full_allocation_mode = allocation_mode->string() == "full";
}
catch (std::exception&) {}
if (seed) if (seed)
{ {
@@ -574,12 +619,16 @@ namespace libtorrent
, !full_allocation_mode, &error); , !full_allocation_mode, &error);
} }
void write_resume_data(entry& rd) const bool write_resume_data(entry& rd) const
{ {
if (rd.type() != entry::dictionary_t)
{
m_error = "invalid fastresume file";
return true;
}
std::vector<std::pair<size_type, std::time_t> > file_sizes std::vector<std::pair<size_type, std::time_t> > file_sizes
= get_filesizes(*m_info, m_save_path); = get_filesizes(*m_info, m_save_path);
rd["file sizes"] = entry::list_type();
entry::list_type& fl = rd["file sizes"].list(); entry::list_type& fl = rd["file sizes"].list();
for (std::vector<std::pair<size_type, std::time_t> >::iterator i for (std::vector<std::pair<size_type, std::time_t> >::iterator i
= file_sizes.begin(), end(file_sizes.end()); i != end; ++i) = file_sizes.begin(), end(file_sizes.end()); i != end; ++i)
@@ -589,18 +638,20 @@ namespace libtorrent
p.push_back(entry(i->second)); p.push_back(entry(i->second));
fl.push_back(entry(p)); fl.push_back(entry(p));
} }
return false;
} }
void move_slot(int src_slot, int dst_slot) bool move_slot(int src_slot, int dst_slot)
{ {
// TODO: this can be optimized by mapping both slots and do a straight memcpy // TODO: this can be optimized by mapping both slots and do a straight memcpy
int piece_size = m_info->piece_size(dst_slot); int piece_size = m_info->piece_size(dst_slot);
m_scratch_buffer.resize(piece_size); m_scratch_buffer.resize(piece_size);
read(&m_scratch_buffer[0], src_slot, 0, piece_size); size_type ret1 = read(&m_scratch_buffer[0], src_slot, 0, piece_size);
write(&m_scratch_buffer[0], dst_slot, 0, piece_size); size_type ret2 = write(&m_scratch_buffer[0], dst_slot, 0, piece_size);
return ret1 != piece_size || ret2 != piece_size;
} }
void swap_slots(int slot1, int slot2) bool swap_slots(int slot1, int slot2)
{ {
// TODO: this can be optimized by mapping both slots and do a straight memcpy // TODO: this can be optimized by mapping both slots and do a straight memcpy
// the size of the target slot is the size of the piece // the size of the target slot is the size of the piece
@@ -608,13 +659,15 @@ namespace libtorrent
int piece1_size = m_info->piece_size(slot2); int piece1_size = m_info->piece_size(slot2);
int piece2_size = m_info->piece_size(slot1); int piece2_size = m_info->piece_size(slot1);
m_scratch_buffer.resize(piece_size * 2); m_scratch_buffer.resize(piece_size * 2);
read(&m_scratch_buffer[0], slot1, 0, piece1_size); size_type ret1 = read(&m_scratch_buffer[0], slot1, 0, piece1_size);
read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size); size_type ret2 = read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size);
write(&m_scratch_buffer[0], slot2, 0, piece1_size); size_type ret3 = write(&m_scratch_buffer[0], slot2, 0, piece1_size);
write(&m_scratch_buffer[piece_size], slot1, 0, piece2_size); size_type ret4 = write(&m_scratch_buffer[piece_size], slot1, 0, piece2_size);
return ret1 != piece1_size || ret2 != piece2_size
|| ret3 != piece1_size || ret4 != piece2_size;
} }
void swap_slots3(int slot1, int slot2, int slot3) bool swap_slots3(int slot1, int slot2, int slot3)
{ {
// TODO: this can be optimized by mapping both slots and do a straight memcpy // TODO: this can be optimized by mapping both slots and do a straight memcpy
// the size of the target slot is the size of the piece // the size of the target slot is the size of the piece
@@ -623,12 +676,15 @@ namespace libtorrent
int piece2_size = m_info->piece_size(slot3); int piece2_size = m_info->piece_size(slot3);
int piece3_size = m_info->piece_size(slot1); int piece3_size = m_info->piece_size(slot1);
m_scratch_buffer.resize(piece_size * 2); m_scratch_buffer.resize(piece_size * 2);
read(&m_scratch_buffer[0], slot1, 0, piece1_size); size_type ret1 = read(&m_scratch_buffer[0], slot1, 0, piece1_size);
read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size); size_type ret2 = read(&m_scratch_buffer[piece_size], slot2, 0, piece2_size);
write(&m_scratch_buffer[0], slot2, 0, piece1_size); size_type ret3 = write(&m_scratch_buffer[0], slot2, 0, piece1_size);
read(&m_scratch_buffer[0], slot3, 0, piece3_size); size_type ret4 = read(&m_scratch_buffer[0], slot3, 0, piece3_size);
write(&m_scratch_buffer[piece_size], slot3, 0, piece2_size); size_type ret5 = write(&m_scratch_buffer[piece_size], slot3, 0, piece2_size);
write(&m_scratch_buffer[0], slot1, 0, piece3_size); size_type ret6 = write(&m_scratch_buffer[0], slot1, 0, piece3_size);
return ret1 != piece1_size || ret2 != piece2_size
|| ret3 != piece1_size || ret4 != piece3_size
|| ret5 != piece2_size || ret6 != piece3_size;
} }
sha1_hash hash_for_slot(int slot, partial_hash& ph, int piece_size) sha1_hash hash_for_slot(int slot, partial_hash& ph, int piece_size)
@@ -661,17 +717,19 @@ namespace libtorrent
#endif #endif
} }
void release_files() bool release_files()
{ {
m_pool.release(this); m_pool.release(this);
return false;
} }
void delete_files() bool delete_files()
{ {
// make sure we don't have the files open // make sure we don't have the files open
m_pool.release(this); m_pool.release(this);
buffer().swap(m_scratch_buffer); buffer().swap(m_scratch_buffer);
int result = 0;
std::string error; std::string error;
// delete the files from disk // delete the files from disk
@@ -690,7 +748,10 @@ namespace libtorrent
bp = bp.branch_path(); bp = bp.branch_path();
} }
if (std::remove(p.c_str()) != 0 && errno != ENOENT) if (std::remove(p.c_str()) != 0 && errno != ENOENT)
{
error = std::strerror(errno); error = std::strerror(errno);
result = errno;
}
} }
// remove the directories. Reverse order to delete // remove the directories. Reverse order to delete
@@ -700,12 +761,19 @@ namespace libtorrent
, end(directories.rend()); i != end; ++i) , end(directories.rend()); i != end; ++i)
{ {
if (std::remove(i->c_str()) != 0 && errno != ENOENT) if (std::remove(i->c_str()) != 0 && errno != ENOENT)
{
error = std::strerror(errno); error = std::strerror(errno);
result = errno;
}
} }
if (!error.empty()) throw std::runtime_error(error); if (!error.empty()) m_error.swap(error);
return result != 0;
} }
std::string const& error() const { return m_error; }
void clear_error() { m_error.clear(); }
private: private:
boost::intrusive_ptr<torrent_info const> m_info; boost::intrusive_ptr<torrent_info const> m_info;
@@ -715,6 +783,8 @@ namespace libtorrent
buffer m_scratch_buffer; buffer m_scratch_buffer;
static mapped_file_pool m_pool; static mapped_file_pool m_pool;
mutable std::string m_error;
}; };
storage_interface* mapped_storage_constructor(boost::intrusive_ptr<torrent_info const> ti storage_interface* mapped_storage_constructor(boost::intrusive_ptr<torrent_info const> ti

View File

@@ -134,309 +134,175 @@ namespace detail
for (;;) for (;;)
{ {
// temporary torrent used while checking fastresume data // temporary torrent used while checking fastresume data
try t.reset();
{ {
t.reset(); boost::mutex::scoped_lock l(m_mutex);
INVARIANT_CHECK;
// if the job queue is empty and
// we shouldn't abort
// wait for a signal
while (m_torrents.empty() && !m_abort && !processing)
m_cond.wait(l);
if (m_abort)
{ {
boost::mutex::scoped_lock l(m_mutex); // no lock is needed here, because the main thread
// has already been shut down by now
INVARIANT_CHECK; processing.reset();
t.reset();
// if the job queue is empty and std::for_each(m_torrents.begin(), m_torrents.end()
// we shouldn't abort , boost::bind(&torrent::abort
// wait for a signal
while (m_torrents.empty() && !m_abort && !processing)
m_cond.wait(l);
if (m_abort)
{
// no lock is needed here, because the main thread
// has already been shut down by now
processing.reset();
t.reset();
std::for_each(m_torrents.begin(), m_torrents.end()
, boost::bind(&torrent::abort
, boost::bind(&shared_ptr<torrent>::get , boost::bind(&shared_ptr<torrent>::get
, boost::bind(&piece_checker_data::torrent_ptr, _1)))); , boost::bind(&piece_checker_data::torrent_ptr, _1))));
m_torrents.clear(); m_torrents.clear();
std::for_each(m_processing.begin(), m_processing.end() std::for_each(m_processing.begin(), m_processing.end()
, boost::bind(&torrent::abort , boost::bind(&torrent::abort
, boost::bind(&shared_ptr<torrent>::get , boost::bind(&shared_ptr<torrent>::get
, boost::bind(&piece_checker_data::torrent_ptr, _1)))); , boost::bind(&piece_checker_data::torrent_ptr, _1))));
m_processing.clear(); m_processing.clear();
return; return;
}
if (!m_torrents.empty())
{
t = m_torrents.front();
if (t->abort)
{
// make sure the locking order is
// consistent to avoid dead locks
// we need to lock the session because closing
// torrents assume to have access to it
l.unlock();
session_impl::mutex_t::scoped_lock l2(m_ses.m_mutex);
l.lock();
t->torrent_ptr->abort();
m_torrents.pop_front();
continue;
}
}
} }
if (t) if (!m_torrents.empty())
{ {
std::string error_msg; t = m_torrents.front();
t->parse_resume_data(t->resume_data, t->torrent_ptr->torrent_file() if (t->abort)
, error_msg);
// lock the session to add the new torrent
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
if (!error_msg.empty() && m_ses.m_alerts.should_post(alert::warning))
{ {
m_ses.m_alerts.post_alert(fastresume_rejected_alert( // make sure the locking order is
// consistent to avoid dead locks
// we need to lock the session because closing
// torrents assume to have access to it
l.unlock();
session_impl::mutex_t::scoped_lock l2(m_ses.m_mutex);
l.lock();
t->torrent_ptr->abort();
m_torrents.pop_front();
continue;
}
}
}
if (t)
{
std::string error_msg;
t->parse_resume_data(t->resume_data, t->torrent_ptr->torrent_file()
, error_msg);
// lock the session to add the new torrent
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
if (!error_msg.empty() && m_ses.m_alerts.should_post(alert::warning))
{
m_ses.m_alerts.post_alert(fastresume_rejected_alert(
t->torrent_ptr->get_handle() t->torrent_ptr->get_handle()
, error_msg)); , error_msg));
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_ses.m_logger) << "fastresume data for " (*m_ses.m_logger) << "fastresume data for "
<< t->torrent_ptr->torrent_file().name() << " rejected: " << t->torrent_ptr->torrent_file().name() << " rejected: "
<< error_msg << "\n"; << error_msg << "\n";
#endif #endif
}
mutex::scoped_lock l2(m_mutex);
if (m_torrents.empty() || m_torrents.front() != t)
{
// this means the torrent was removed right after it was
// added. Abort the checking.
t.reset();
continue;
}
// clear the resume data now that it has been used
// (the fast resume data is now parsed and stored in t)
t->resume_data = entry();
bool up_to_date = t->torrent_ptr->check_fastresume(*t);
if (up_to_date)
{
INVARIANT_CHECK;
TORRENT_ASSERT(!m_torrents.empty());
TORRENT_ASSERT(m_torrents.front() == t);
t->torrent_ptr->files_checked(t->unfinished_pieces);
m_torrents.pop_front();
// we cannot add the torrent if the session is aborted.
if (!m_ses.is_aborted())
{
m_ses.m_torrents.insert(std::make_pair(t->info_hash, t->torrent_ptr));
if (m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(torrent_checked_alert(
processing->torrent_ptr->get_handle()
, "torrent finished checking"));
}
if (t->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(torrent_finished_alert(
t->torrent_ptr->get_handle()
, "torrent is complete"));
}
peer_id id;
std::fill(id.begin(), id.end(), 0);
for (std::vector<tcp::endpoint>::const_iterator i = t->peers.begin();
i != t->peers.end(); ++i)
{
t->torrent_ptr->get_policy().peer_from_tracker(*i, id
, peer_info::resume_data, 0);
}
for (std::vector<tcp::endpoint>::const_iterator i = t->banned_peers.begin();
i != t->banned_peers.end(); ++i)
{
policy::peer* p = t->torrent_ptr->get_policy().peer_from_tracker(*i, id
, peer_info::resume_data, 0);
if (p) p->banned = true;
}
}
else
{
t->torrent_ptr->abort();
}
t.reset();
continue;
}
l.unlock();
// move the torrent from
// m_torrents to m_processing
TORRENT_ASSERT(m_torrents.front() == t);
m_torrents.pop_front();
m_processing.push_back(t);
if (!processing)
{
processing = t;
processing->processing = true;
t.reset();
}
} }
}
catch (const std::exception& e)
{
// This will happen if the storage fails to initialize
// for example if one of the files has an invalid filename.
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
mutex::scoped_lock l2(m_mutex); mutex::scoped_lock l2(m_mutex);
if (m_ses.m_alerts.should_post(alert::fatal)) if (m_torrents.empty() || m_torrents.front() != t)
{ {
m_ses.m_alerts.post_alert( // this means the torrent was removed right after it was
file_error_alert( // added. Abort the checking.
t->torrent_ptr->get_handle() t.reset();
, e.what())); continue;
} }
t->torrent_ptr->abort();
TORRENT_ASSERT(!m_torrents.empty()); // clear the resume data now that it has been used
m_torrents.pop_front(); // (the fast resume data is now parsed and stored in t)
} t->resume_data = entry();
catch(...) bool up_to_date = t->torrent_ptr->check_fastresume(*t);
{
#ifndef NDEBUG
std::cerr << "error while checking resume data\n";
#endif
mutex::scoped_lock l(m_mutex);
TORRENT_ASSERT(!m_torrents.empty());
m_torrents.pop_front();
TORRENT_ASSERT(false);
}
if (!processing) continue;
try
{
TORRENT_ASSERT(processing);
float finished = false;
float progress = 0.f;
boost::tie(finished, progress) = processing->torrent_ptr->check_files();
if (up_to_date)
{ {
mutex::scoped_lock l2(m_mutex);
INVARIANT_CHECK; INVARIANT_CHECK;
processing->progress = progress; TORRENT_ASSERT(!m_torrents.empty());
if (processing->abort) TORRENT_ASSERT(m_torrents.front() == t);
{
TORRENT_ASSERT(!m_processing.empty());
TORRENT_ASSERT(m_processing.front() == processing);
m_processing.pop_front();
// make sure the lock order is correct t->torrent_ptr->files_checked(t->unfinished_pieces);
l2.unlock(); m_torrents.pop_front();
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
l2.lock();
processing->torrent_ptr->abort();
processing.reset(); // we cannot add the torrent if the session is aborted.
if (!m_processing.empty())
{
processing = m_processing.front();
processing->processing = true;
}
continue;
}
}
if (finished)
{
// lock the session to add the new torrent
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
mutex::scoped_lock l2(m_mutex);
INVARIANT_CHECK;
TORRENT_ASSERT(!m_processing.empty());
TORRENT_ASSERT(m_processing.front() == processing);
// TODO: factor out the adding of torrents to the session
// and to the checker thread to avoid duplicating the
// check for abortion.
if (!m_ses.is_aborted()) if (!m_ses.is_aborted())
{ {
processing->torrent_ptr->files_checked(processing->unfinished_pieces); m_ses.m_torrents.insert(std::make_pair(t->info_hash, t->torrent_ptr));
m_ses.m_torrents.insert(std::make_pair(
processing->info_hash, processing->torrent_ptr));
if (m_ses.m_alerts.should_post(alert::info)) if (m_ses.m_alerts.should_post(alert::info))
{ {
m_ses.m_alerts.post_alert(torrent_checked_alert( m_ses.m_alerts.post_alert(torrent_checked_alert(
processing->torrent_ptr->get_handle() processing->torrent_ptr->get_handle()
, "torrent finished checking")); , "torrent finished checking"));
} }
if (processing->torrent_ptr->is_seed() if (t->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info))
&& m_ses.m_alerts.should_post(alert::info))
{ {
m_ses.m_alerts.post_alert(torrent_finished_alert( m_ses.m_alerts.post_alert(torrent_finished_alert(
processing->torrent_ptr->get_handle() t->torrent_ptr->get_handle()
, "torrent is complete")); , "torrent is complete"));
} }
peer_id id; peer_id id;
std::fill(id.begin(), id.end(), 0); std::fill(id.begin(), id.end(), 0);
for (std::vector<tcp::endpoint>::const_iterator i = processing->peers.begin(); for (std::vector<tcp::endpoint>::const_iterator i = t->peers.begin();
i != processing->peers.end(); ++i) i != t->peers.end(); ++i)
{ {
processing->torrent_ptr->get_policy().peer_from_tracker(*i, id t->torrent_ptr->get_policy().peer_from_tracker(*i, id
, peer_info::resume_data, 0); , peer_info::resume_data, 0);
} }
for (std::vector<tcp::endpoint>::const_iterator i = processing->banned_peers.begin(); for (std::vector<tcp::endpoint>::const_iterator i = t->banned_peers.begin();
i != processing->banned_peers.end(); ++i) i != t->banned_peers.end(); ++i)
{ {
policy::peer* p = processing->torrent_ptr->get_policy().peer_from_tracker(*i, id policy::peer* p = t->torrent_ptr->get_policy().peer_from_tracker(*i, id
, peer_info::resume_data, 0); , peer_info::resume_data, 0);
if (p) p->banned = true; if (p) p->banned = true;
} }
} }
else else
{ {
processing->torrent_ptr->abort(); t->torrent_ptr->abort();
}
processing.reset();
m_processing.pop_front();
if (!m_processing.empty())
{
processing = m_processing.front();
processing->processing = true;
} }
t.reset();
continue;
}
l.unlock();
// move the torrent from
// m_torrents to m_processing
TORRENT_ASSERT(m_torrents.front() == t);
m_torrents.pop_front();
m_processing.push_back(t);
if (!processing)
{
processing = t;
processing->processing = true;
t.reset();
} }
} }
catch(std::exception const& e) if (!processing) continue;
TORRENT_ASSERT(processing);
bool finished = false;
bool error = false;
float progress = 0.f;
boost::tie(finished, progress) = processing->torrent_ptr->check_files(error);
if (error)
{ {
// This will happen if the storage fails to initialize // This will happen if the storage fails to initialize
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
mutex::scoped_lock l2(m_mutex); mutex::scoped_lock l2(m_mutex);
if (m_ses.m_alerts.should_post(alert::fatal))
{
m_ses.m_alerts.post_alert(
file_error_alert(
processing->torrent_ptr->get_handle()
, e.what()));
}
processing->torrent_ptr->abort();
if (!m_processing.empty() if (!m_processing.empty()
&& m_processing.front() == processing) && m_processing.front() == processing)
m_processing.pop_front(); m_processing.pop_front();
@@ -446,15 +312,90 @@ namespace detail
processing = m_processing.front(); processing = m_processing.front();
processing->processing = true; processing->processing = true;
} }
continue;
} }
catch(...)
{
#ifndef NDEBUG
std::cerr << "error while checking files\n";
#endif
mutex::scoped_lock l(m_mutex);
TORRENT_ASSERT(!m_processing.empty());
{
mutex::scoped_lock l2(m_mutex);
INVARIANT_CHECK;
processing->progress = progress;
if (processing->abort)
{
TORRENT_ASSERT(!m_processing.empty());
TORRENT_ASSERT(m_processing.front() == processing);
m_processing.pop_front();
// make sure the lock order is correct
l2.unlock();
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
l2.lock();
processing->torrent_ptr->abort();
processing.reset();
if (!m_processing.empty())
{
processing = m_processing.front();
processing->processing = true;
}
continue;
}
}
if (finished)
{
// lock the session to add the new torrent
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
mutex::scoped_lock l2(m_mutex);
INVARIANT_CHECK;
TORRENT_ASSERT(!m_processing.empty());
TORRENT_ASSERT(m_processing.front() == processing);
// TODO: factor out the adding of torrents to the session
// and to the checker thread to avoid duplicating the
// check for abortion.
if (!m_ses.is_aborted())
{
processing->torrent_ptr->files_checked(processing->unfinished_pieces);
m_ses.m_torrents.insert(std::make_pair(
processing->info_hash, processing->torrent_ptr));
if (m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(torrent_checked_alert(
processing->torrent_ptr->get_handle()
, "torrent finished checking"));
}
if (processing->torrent_ptr->is_seed()
&& m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(torrent_finished_alert(
processing->torrent_ptr->get_handle()
, "torrent is complete"));
}
peer_id id;
std::fill(id.begin(), id.end(), 0);
for (std::vector<tcp::endpoint>::const_iterator i = processing->peers.begin();
i != processing->peers.end(); ++i)
{
processing->torrent_ptr->get_policy().peer_from_tracker(*i, id
, peer_info::resume_data, 0);
}
for (std::vector<tcp::endpoint>::const_iterator i = processing->banned_peers.begin();
i != processing->banned_peers.end(); ++i)
{
policy::peer* p = processing->torrent_ptr->get_policy().peer_from_tracker(*i, id
, peer_info::resume_data, 0);
if (p) p->banned = true;
}
}
else
{
processing->torrent_ptr->abort();
}
processing.reset(); processing.reset();
m_processing.pop_front(); m_processing.pop_front();
if (!m_processing.empty()) if (!m_processing.empty())
@@ -462,8 +403,6 @@ namespace detail
processing = m_processing.front(); processing = m_processing.front();
processing->processing = true; processing->processing = true;
} }
TORRENT_ASSERT(false);
} }
} }
} }
@@ -2455,6 +2394,7 @@ namespace detail
boost::mutex::scoped_lock l(m_send_buffer_mutex); boost::mutex::scoped_lock l(m_send_buffer_mutex);
#ifdef TORRENT_STATS #ifdef TORRENT_STATS
TORRENT_ASSERT(m_buffer_allocations >= 0);
m_buffer_allocations += num_buffers; m_buffer_allocations += num_buffers;
m_buffer_usage_logger << log_time() << " protocol_buffer: " m_buffer_usage_logger << log_time() << " protocol_buffer: "
<< (m_buffer_allocations * send_buffer_size) << std::endl; << (m_buffer_allocations * send_buffer_size) << std::endl;

File diff suppressed because it is too large Load Diff

View File

@@ -2511,7 +2511,7 @@ namespace libtorrent
return done; return done;
} }
std::pair<bool, float> torrent::check_files() std::pair<bool, float> torrent::check_files(bool& error)
{ {
TORRENT_ASSERT(m_torrent_file->is_valid()); TORRENT_ASSERT(m_torrent_file->is_valid());
INVARIANT_CHECK; INVARIANT_CHECK;
@@ -2519,13 +2519,11 @@ namespace libtorrent
TORRENT_ASSERT(m_owning_storage.get()); TORRENT_ASSERT(m_owning_storage.get());
std::pair<bool, float> progress(true, 1.f); std::pair<bool, float> progress(true, 1.f);
try TORRENT_ASSERT(m_storage);
{ progress = m_storage->check_files(m_have_pieces, m_num_pieces
TORRENT_ASSERT(m_storage); , m_ses.m_mutex, error);
progress = m_storage->check_files(m_have_pieces, m_num_pieces
, m_ses.m_mutex); if (error)
}
catch (std::exception& e)
{ {
// probably means file permission failure or invalid filename // probably means file permission failure or invalid filename
std::fill(m_have_pieces.begin(), m_have_pieces.end(), false); std::fill(m_have_pieces.begin(), m_have_pieces.end(), false);
@@ -2536,7 +2534,7 @@ namespace libtorrent
m_ses.m_alerts.post_alert( m_ses.m_alerts.post_alert(
file_error_alert( file_error_alert(
get_handle() get_handle()
, e.what())); , m_storage->error()));
} }
pause(); pause();
} }
@@ -2573,7 +2571,13 @@ namespace libtorrent
for (extension_list_t::iterator i = m_extensions.begin() for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i) , end(m_extensions.end()); i != end; ++i)
{ {
try { (*i)->on_files_checked(); } catch (std::exception&) {} #ifndef BOOST_NO_EXCEPTIONS
try {
#endif
(*i)->on_files_checked();
#ifndef BOOST_NO_EXCEPTIONS
} catch (std::exception&) {}
#endif
} }
#endif #endif

View File

@@ -102,8 +102,9 @@ void run_storage_tests(boost::intrusive_ptr<torrent_info> info
float progress; float progress;
num_pieces = 0; num_pieces = 0;
boost::recursive_mutex mutex; boost::recursive_mutex mutex;
bool error;
while (!finished) while (!finished)
boost::tie(finished, progress) = pm->check_files(pieces, num_pieces, mutex); boost::tie(finished, progress) = pm->check_files(pieces, num_pieces, mutex, error);
TEST_CHECK(num_pieces == std::count(pieces.begin(), pieces.end() TEST_CHECK(num_pieces == std::count(pieces.begin(), pieces.end()
, true)); , true));