forked from premiere/premiere-libtorrent
fixed bug in storage when forcing recheck while renaming a file or moving it
This commit is contained in:
parent
04d1684482
commit
a051228069
|
@ -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()
|
||||
----------------
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue