fixed bug in storage when forcing recheck while renaming a file or moving it

This commit is contained in:
Arvid Norberg 2009-04-10 07:22:27 +00:00
parent 04d1684482
commit a051228069
4 changed files with 97 additions and 51 deletions

View File

@ -5112,12 +5112,30 @@ storage_interface
=================
The storage interface is a pure virtual class that can be implemented to
change the behavior of the actual file storage. The interface looks like
this::
customize how and where data for a torrent is stored. The default storage
implementation uses regular files in the filesystem, mapping the files in the
torrent in the way one would assume a torrent is saved to disk. Implementing
your own storage interface makes it possible to store all data in RAM, or in
some optimized order on disk (the order the pieces are received for instance),
or saving multifile torrents in a single file in order to be able to take
advantage of optimized disk-I/O.
It is also possible to write a thin class that uses the default storage but
modifies some particular behavior, for instance encrypting the data before
it's written to disk, and decrypting it when it's read again.
The storage interface is based on slots, each slot is 'piece_size' number
of bytes. All access is done by writing and reading whole or partial
slots. One slot is one piece in the torrent, but the data in the slot
does not necessarily correspond to the piece with the same index (in
compact allocation mode it won't).
The interface looks like this::
struct storage_interface
{
virtual bool initialize(bool allocate_files) = 0;
virtual bool has_any_file() = 0;
virtual int readv(file::iovec_t const* bufs, int slot, int offset, int num_bufs) = 0;
virtual int writev(file::iovec_t const* bufs, int slot, int offset, int num_bufs) = 0;
virtual int sparse_end(int start) const;
@ -5156,6 +5174,16 @@ it will also ``ftruncate`` all files to their target size.
Returning ``true`` indicates an error occurred.
has_any_file()
--------------
::
virtual bool has_any_file() = 0;
This function is called when first checking (or re-checking) the storage for a torrent.
It should return true if any of the files that is used in this storage exists on disk.
If so, the storage will be checked for existing pieces before starting the download.
readv() writev()
----------------

View File

@ -119,6 +119,8 @@ namespace libtorrent
// false return value indicates an error
virtual bool initialize(bool allocate_files) = 0;
virtual bool has_any_file() = 0;
virtual int readv(file::iovec_t const* bufs, int slot, int offset, int num_bufs);
virtual int writev(file::iovec_t const* bufs, int slot, int offset, int num_bufs);

View File

@ -407,6 +407,7 @@ namespace libtorrent
#endif
}
bool has_any_file();
bool rename_file(int index, std::string const& new_filename);
bool release_files();
bool delete_files();
@ -581,6 +582,43 @@ namespace libtorrent
return false;
}
bool storage::has_any_file()
{
file_storage::iterator i = files().begin();
file_storage::iterator end = files().end();
for (; i != end; ++i)
{
bool file_exists = false;
fs::path f = m_save_path / i->path;
#ifndef BOOST_NO_EXCEPTIONS
try
{
#endif
#if TORRENT_USE_WPATH
fs::wpath wf = convert_to_wstring(f.string());
file_exists = exists(wf);
#elif TORRENT_USE_LOCALE_FILENAMES
file_exists = exists(convert_to_native(f.string()));
#else
file_exists = exists(f);
#endif
std::cerr << "has_any_file(): " << f << " " << (file_exists?"exists": "don't exist")
<< std::endl;
#ifndef BOOST_NO_EXCEPTIONS
}
catch (boost::system::system_error& e)
{
set_error(f, e.code());
return false;
}
#endif
if (file_exists && i->size > 0)
return true;
}
return false;
}
bool storage::rename_file(int index, std::string const& new_filename)
{
if (index < 0 || index >= m_files.num_files()) return true;
@ -1857,53 +1895,27 @@ ret:
int piece_manager::check_no_fastresume(std::string& error)
{
file_storage::iterator i = m_files.begin();
file_storage::iterator end = m_files.end();
bool has_files = m_storage->has_any_file();
for (; i != end; ++i)
if (m_storage->error())
return fatal_disk_error;
if (has_files)
{
bool file_exists = false;
fs::path f = m_save_path / i->path;
#ifndef BOOST_NO_EXCEPTIONS
try
m_state = state_full_check;
m_piece_to_slot.clear();
m_piece_to_slot.resize(m_files.num_pieces(), has_no_slot);
m_slot_to_piece.clear();
m_slot_to_piece.resize(m_files.num_pieces(), unallocated);
if (m_storage_mode == storage_mode_compact)
{
#endif
#if TORRENT_USE_WPATH
fs::wpath wf = convert_to_wstring(f.string());
file_exists = exists(wf);
#elif TORRENT_USE_LOCALE_FILENAMES
file_exists = exists(convert_to_native(f.string()));
#else
file_exists = exists(f);
#endif
#ifndef BOOST_NO_EXCEPTIONS
}
catch (std::exception& e)
{
error = f.string();
error += ": ";
error += e.what();
TORRENT_ASSERT(!error.empty());
return fatal_disk_error;
}
#endif
if (file_exists && i->size > 0)
{
m_state = state_full_check;
m_piece_to_slot.clear();
m_piece_to_slot.resize(m_files.num_pieces(), has_no_slot);
m_slot_to_piece.clear();
m_slot_to_piece.resize(m_files.num_pieces(), unallocated);
if (m_storage_mode == storage_mode_compact)
{
m_unallocated_slots.clear();
m_free_slots.clear();
}
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces());
return need_full_check;
m_unallocated_slots.clear();
m_free_slots.clear();
}
TORRENT_ASSERT(int(m_piece_to_slot.size()) == m_files.num_pieces());
return need_full_check;
}
if (m_storage_mode == storage_mode_compact)
{
// in compact mode without checking, we need to

View File

@ -804,10 +804,6 @@ namespace libtorrent
disconnect_all();
m_owning_storage->async_release_files();
m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file
, m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor
, m_storage_mode);
m_storage = m_owning_storage.get();
if (!m_picker) m_picker.reset(new piece_picker());
m_picker->init(m_torrent_file->piece_length() / m_block_size
, int((m_torrent_file->total_size()+m_block_size-1)/m_block_size));
@ -845,9 +841,17 @@ namespace libtorrent
pause();
return;
}
set_state(torrent_status::queued_for_checking);
if (should_check_files())
queue_torrent_check();
if (ret == 0)
{
// if there are no files, just start
files_checked();
}
else
{
set_state(torrent_status::queued_for_checking);
if (should_check_files())
queue_torrent_check();
}
}
void torrent::start_checking()