forked from premiere/premiere-libtorrent
add option to delete just the partfile when removing a torrent
This commit is contained in:
parent
035f8e98d1
commit
921cbeebed
|
@ -84,7 +84,7 @@ namespace libtorrent
|
|||
, boost::function<void(disk_io_job const*)> const& handler)= 0;
|
||||
virtual void async_rename_file(piece_manager* storage, int index, std::string const& name
|
||||
, boost::function<void(disk_io_job const*)> const& handler) = 0;
|
||||
virtual void async_delete_files(piece_manager* storage
|
||||
virtual void async_delete_files(piece_manager* storage, int options
|
||||
, boost::function<void(disk_io_job const*)> const& handler) = 0;
|
||||
virtual void async_save_resume_data(piece_manager* storage
|
||||
, boost::function<void(disk_io_job const*)> const& handler) = 0;
|
||||
|
|
|
@ -167,6 +167,7 @@ namespace libtorrent
|
|||
bdecode_node const* check_resume_data;
|
||||
std::vector<boost::uint8_t>* priorities;
|
||||
torrent_info* torrent_file;
|
||||
int delete_options;
|
||||
} buffer;
|
||||
|
||||
// the disk storage this job applies to (if applicable)
|
||||
|
|
|
@ -311,7 +311,7 @@ namespace libtorrent
|
|||
void async_release_files(piece_manager* storage
|
||||
, boost::function<void(disk_io_job const*)> const& handler
|
||||
= boost::function<void(disk_io_job const*)>());
|
||||
void async_delete_files(piece_manager* storage
|
||||
void async_delete_files(piece_manager* storage, int options
|
||||
, boost::function<void(disk_io_job const*)> const& handler);
|
||||
void async_check_fastresume(piece_manager* storage
|
||||
, bdecode_node const* resume_data
|
||||
|
|
|
@ -767,7 +767,11 @@ namespace libtorrent
|
|||
enum options_t
|
||||
{
|
||||
// delete the files belonging to the torrent from disk.
|
||||
delete_files = 1
|
||||
// including the part-file, if there is one
|
||||
delete_files = 1,
|
||||
|
||||
// delete just the part-file associated with this torrent
|
||||
delete_partfile = 2
|
||||
};
|
||||
|
||||
// flags to be passed in to the session constructor
|
||||
|
|
|
@ -339,8 +339,10 @@ namespace libtorrent
|
|||
virtual void rename_file(int index, std::string const& new_filename
|
||||
, storage_error& ec) = 0;
|
||||
|
||||
// This function should delete all files and directories belonging to
|
||||
// this storage.
|
||||
// This function should delete some or all of the storage for this torrent.
|
||||
// The ``options`` parameter specifies whether to delete all files or just
|
||||
// the partfile. ``options`` are set to the same value as the options
|
||||
// passed to session::remove_torrent().
|
||||
//
|
||||
// If an error occurs, ``storage_error`` should be set to reflect it.
|
||||
//
|
||||
|
@ -360,7 +362,7 @@ namespace libtorrent
|
|||
// void release_memory();
|
||||
// };
|
||||
//
|
||||
virtual void delete_files(storage_error& ec) = 0;
|
||||
virtual void delete_files(int options, storage_error& ec) = 0;
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
// This function is called each time a file is completely downloaded. The
|
||||
|
@ -426,7 +428,7 @@ namespace libtorrent
|
|||
virtual void rename_file(int index, std::string const& new_filename
|
||||
, storage_error& ec) TORRENT_OVERRIDE;
|
||||
virtual void release_files(storage_error& ec) TORRENT_OVERRIDE;
|
||||
virtual void delete_files(storage_error& ec) TORRENT_OVERRIDE;
|
||||
virtual void delete_files(int options, storage_error& ec) TORRENT_OVERRIDE;
|
||||
virtual void initialize(storage_error& ec) TORRENT_OVERRIDE;
|
||||
virtual int move_storage(std::string const& save_path, int flags
|
||||
, storage_error& ec) TORRENT_OVERRIDE;
|
||||
|
@ -506,7 +508,7 @@ namespace libtorrent
|
|||
, storage_error&) TORRENT_OVERRIDE {}
|
||||
virtual void rename_file(int, std::string const&, storage_error&) TORRENT_OVERRIDE {}
|
||||
virtual void release_files(storage_error&) TORRENT_OVERRIDE {}
|
||||
virtual void delete_files(storage_error&) TORRENT_OVERRIDE {}
|
||||
virtual void delete_files(int, storage_error&) TORRENT_OVERRIDE {}
|
||||
virtual void initialize(storage_error&) TORRENT_OVERRIDE {}
|
||||
virtual int move_storage(std::string const&, int, storage_error&) TORRENT_OVERRIDE { return 0; }
|
||||
|
||||
|
@ -545,7 +547,7 @@ namespace libtorrent
|
|||
virtual void release_files(storage_error&) TORRENT_OVERRIDE {}
|
||||
virtual void rename_file(int /* index */
|
||||
, std::string const& /* new_filenamem */, storage_error&) TORRENT_OVERRIDE {}
|
||||
virtual void delete_files(storage_error&) TORRENT_OVERRIDE {}
|
||||
virtual void delete_files(int, storage_error&) TORRENT_OVERRIDE {}
|
||||
};
|
||||
|
||||
struct disk_io_thread;
|
||||
|
|
|
@ -505,7 +505,7 @@ namespace libtorrent
|
|||
|
||||
bool should_check_files() const;
|
||||
|
||||
bool delete_files();
|
||||
bool delete_files(int options);
|
||||
void peers_erased(std::vector<torrent_peer*> const& peers);
|
||||
|
||||
// ============ start deprecation =============
|
||||
|
|
|
@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/session.hpp"
|
||||
#include "libtorrent/session_stats.hpp"
|
||||
#include "libtorrent/file.hpp"
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
|
@ -350,6 +351,68 @@ TORRENT_TEST(shutdown)
|
|||
});
|
||||
}
|
||||
|
||||
TORRENT_TEST(delete_files)
|
||||
{
|
||||
std::string save_path;
|
||||
|
||||
setup_swarm(2, swarm_test::download
|
||||
// add session
|
||||
, [](lt::settings_pack& pack) {}
|
||||
// add torrent
|
||||
, [](lt::add_torrent_params& params) {}
|
||||
// on alert
|
||||
, [](lt::alert const* a, lt::session& ses) {}
|
||||
// terminate
|
||||
, [&save_path](int ticks, lt::session& ses) -> bool
|
||||
{
|
||||
if (completed_pieces(ses) == 0) return false;
|
||||
|
||||
auto h = ses.get_torrents()[0];
|
||||
save_path = h.status().save_path;
|
||||
ses.remove_torrent(h, session::delete_files);
|
||||
return true;
|
||||
});
|
||||
|
||||
// assert the file is no longer there
|
||||
file_status st;
|
||||
error_code ec;
|
||||
stat_file(combine_path(save_path, "temporary"), &st, ec);
|
||||
printf("expecting \"%s/temporary\" to NOT exist [%s | %s]\n"
|
||||
, save_path.c_str()
|
||||
, ec.category().name()
|
||||
, ec.message().c_str());
|
||||
TEST_EQUAL(ec, error_code(boost::system::errc::no_such_file_or_directory, system_category()));
|
||||
}
|
||||
|
||||
TORRENT_TEST(delete_partfile)
|
||||
{
|
||||
std::string save_path;
|
||||
setup_swarm(2, swarm_test::download
|
||||
// add session
|
||||
, [](lt::settings_pack& pack) {}
|
||||
// add torrent
|
||||
, [](lt::add_torrent_params& params) {}
|
||||
// on alert
|
||||
, [](lt::alert const* a, lt::session& ses) {}
|
||||
// terminate
|
||||
, [&save_path](int ticks, lt::session& ses) -> bool
|
||||
{
|
||||
if (completed_pieces(ses) == 0) return false;
|
||||
|
||||
auto h = ses.get_torrents()[0];
|
||||
save_path = h.status().save_path;
|
||||
ses.remove_torrent(h, session::delete_partfile);
|
||||
return true;
|
||||
});
|
||||
// assert the file *is* still there
|
||||
file_status st;
|
||||
error_code ec;
|
||||
stat_file(combine_path(save_path, "temporary"), &st, ec);
|
||||
printf("expecting \"%s/temporary\" to exist [%s]\n", save_path.c_str()
|
||||
, ec.message().c_str());
|
||||
TEST_CHECK(!ec);
|
||||
}
|
||||
|
||||
// TODO: add test that makes sure a torrent in graceful pause mode won't make
|
||||
// outgoing connections
|
||||
// TODO: add test that makes sure a torrent in graceful pause mode won't accept
|
||||
|
|
|
@ -1817,6 +1817,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
void disk_io_thread::async_delete_files(piece_manager* storage
|
||||
, int const options
|
||||
, boost::function<void(disk_io_job const*)> const& handler)
|
||||
{
|
||||
#ifdef TORRENT_DEBUG
|
||||
|
@ -1857,6 +1858,7 @@ namespace libtorrent
|
|||
disk_io_job* j = allocate_job(disk_io_job::delete_files);
|
||||
j->storage = storage->shared_from_this();
|
||||
j->callback = handler;
|
||||
j->buffer.delete_options = options;
|
||||
add_fence_job(storage, j);
|
||||
|
||||
fail_jobs_impl(storage_error(boost::asio::error::operation_aborted)
|
||||
|
@ -2548,7 +2550,7 @@ namespace libtorrent
|
|||
|
||||
int disk_io_thread::do_delete_files(disk_io_job* j, jobqueue_t& completed_jobs)
|
||||
{
|
||||
TORRENT_ASSERT(j->buffer.string == 0);
|
||||
TORRENT_ASSERT(j->buffer.delete_options != 0);
|
||||
INVARIANT_CHECK;
|
||||
|
||||
// if this assert fails, something's wrong with the fence logic
|
||||
|
@ -2563,7 +2565,7 @@ namespace libtorrent
|
|||
, completed_jobs, l);
|
||||
l.unlock();
|
||||
|
||||
j->storage->get_storage_impl()->delete_files(j->error);
|
||||
j->storage->get_storage_impl()->delete_files(j->buffer.delete_options, j->error);
|
||||
return j->error ? -1 : 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -5116,7 +5116,8 @@ retry:
|
|||
boost::shared_ptr<torrent> tptr = h.m_torrent.lock();
|
||||
if (!tptr) return;
|
||||
|
||||
m_alerts.emplace_alert<torrent_removed_alert>(tptr->get_handle(), tptr->info_hash());
|
||||
m_alerts.emplace_alert<torrent_removed_alert>(tptr->get_handle()
|
||||
, tptr->info_hash());
|
||||
|
||||
remove_torrent_impl(tptr, options);
|
||||
|
||||
|
@ -5124,7 +5125,8 @@ retry:
|
|||
tptr->set_queue_position(-1);
|
||||
}
|
||||
|
||||
void session_impl::remove_torrent_impl(boost::shared_ptr<torrent> tptr, int options)
|
||||
void session_impl::remove_torrent_impl(boost::shared_ptr<torrent> tptr
|
||||
, int options)
|
||||
{
|
||||
// remove from uuid list
|
||||
if (!tptr->uuid().empty())
|
||||
|
@ -5148,9 +5150,9 @@ retry:
|
|||
if (i == m_torrents.end()) return;
|
||||
|
||||
torrent& t = *i->second;
|
||||
if (options & session::delete_files)
|
||||
if (options)
|
||||
{
|
||||
if (!t.delete_files())
|
||||
if (!t.delete_files(options))
|
||||
{
|
||||
if (m_alerts.should_post<torrent_delete_failed_alert>())
|
||||
m_alerts.emplace_alert<torrent_delete_failed_alert>(t.get_handle()
|
||||
|
|
110
src/storage.cpp
110
src/storage.cpp
|
@ -754,9 +754,10 @@ namespace libtorrent
|
|||
ec.clear();
|
||||
}
|
||||
|
||||
void default_storage::delete_files(storage_error& ec)
|
||||
void default_storage::delete_files(int const options, storage_error& ec)
|
||||
{
|
||||
DFLOG(stderr, "[%p] delete_files\n", static_cast<void*>(this));
|
||||
DFLOG(stderr, "[%p] delete_files [%x]\n", static_cast<void*>(this)
|
||||
, options);
|
||||
|
||||
#if TORRENT_USE_ASSERTS
|
||||
// this is a fence job, we expect no other
|
||||
|
@ -775,58 +776,69 @@ namespace libtorrent
|
|||
// make sure we don't have the files open
|
||||
m_pool.release(this);
|
||||
|
||||
#if defined TORRENT_DEBUG_FILE_LEAKS
|
||||
print_open_files("release files", m_files.name().c_str());
|
||||
#endif
|
||||
|
||||
#if TORRENT_USE_ASSERTS
|
||||
m_pool.mark_deleted(m_files);
|
||||
#endif
|
||||
// delete the files from disk
|
||||
std::set<std::string> directories;
|
||||
typedef std::set<std::string>::iterator iter_t;
|
||||
for (int i = 0; i < files().num_files(); ++i)
|
||||
{
|
||||
std::string fp = files().file_path(i);
|
||||
bool complete = is_complete(fp);
|
||||
std::string p = complete ? fp : combine_path(m_save_path, fp);
|
||||
if (!complete)
|
||||
{
|
||||
std::string bp = parent_path(fp);
|
||||
std::pair<iter_t, bool> ret;
|
||||
ret.second = true;
|
||||
while (ret.second && !bp.empty())
|
||||
{
|
||||
ret = directories.insert(combine_path(m_save_path, bp));
|
||||
bp = parent_path(bp);
|
||||
}
|
||||
}
|
||||
delete_one_file(p, ec.ec);
|
||||
if (ec) { ec.file = i; ec.operation = storage_error::remove; }
|
||||
}
|
||||
|
||||
// remove the directories. Reverse order to delete
|
||||
// subdirectories first
|
||||
|
||||
for (std::set<std::string>::reverse_iterator i = directories.rbegin()
|
||||
, end(directories.rend()); i != end; ++i)
|
||||
{
|
||||
error_code error;
|
||||
delete_one_file(*i, error);
|
||||
if (error && !ec) { ec.file = -1; ec.ec = error; ec.operation = storage_error::remove; }
|
||||
}
|
||||
|
||||
// if there's a part file open, make sure to destruct it to have it
|
||||
// release the underlying part file. Otherwise we may not be able to
|
||||
// delete it
|
||||
if (m_part_file) m_part_file.reset();
|
||||
|
||||
error_code error;
|
||||
remove(combine_path(m_save_path, m_part_file_name), error);
|
||||
DFLOG(stderr, "[%p] delete partfile %s/%s [%s]\n", static_cast<void*>(this)
|
||||
, m_save_path.c_str(), m_part_file_name.c_str(), error.message().c_str());
|
||||
if (error != boost::system::errc::no_such_file_or_directory && !error)
|
||||
{ ec.file = -1; ec.ec = error; ec.operation = storage_error::remove; }
|
||||
#if defined TORRENT_DEBUG_FILE_LEAKS
|
||||
print_open_files("release files", m_files.name().c_str());
|
||||
#endif
|
||||
|
||||
if (options == session::delete_files)
|
||||
{
|
||||
#if TORRENT_USE_ASSERTS
|
||||
m_pool.mark_deleted(m_files);
|
||||
#endif
|
||||
// delete the files from disk
|
||||
std::set<std::string> directories;
|
||||
typedef std::set<std::string>::iterator iter_t;
|
||||
for (int i = 0; i < files().num_files(); ++i)
|
||||
{
|
||||
std::string fp = files().file_path(i);
|
||||
bool complete = is_complete(fp);
|
||||
std::string p = complete ? fp : combine_path(m_save_path, fp);
|
||||
if (!complete)
|
||||
{
|
||||
std::string bp = parent_path(fp);
|
||||
std::pair<iter_t, bool> ret;
|
||||
ret.second = true;
|
||||
while (ret.second && !bp.empty())
|
||||
{
|
||||
ret = directories.insert(combine_path(m_save_path, bp));
|
||||
bp = parent_path(bp);
|
||||
}
|
||||
}
|
||||
delete_one_file(p, ec.ec);
|
||||
if (ec) { ec.file = i; ec.operation = storage_error::remove; }
|
||||
}
|
||||
|
||||
// remove the directories. Reverse order to delete
|
||||
// subdirectories first
|
||||
|
||||
for (std::set<std::string>::reverse_iterator i = directories.rbegin()
|
||||
, end(directories.rend()); i != end; ++i)
|
||||
{
|
||||
error_code error;
|
||||
delete_one_file(*i, error);
|
||||
if (error && !ec) { ec.file = -1; ec.ec = error; ec.operation = storage_error::remove; }
|
||||
}
|
||||
}
|
||||
|
||||
if (options == session::delete_files
|
||||
|| options == session::delete_partfile)
|
||||
{
|
||||
error_code error;
|
||||
remove(combine_path(m_save_path, m_part_file_name), error);
|
||||
DFLOG(stderr, "[%p] delete partfile %s/%s [%s]\n", static_cast<void*>(this)
|
||||
, m_save_path.c_str(), m_part_file_name.c_str(), error.message().c_str());
|
||||
if (error && error != boost::system::errc::no_such_file_or_directory)
|
||||
{
|
||||
ec.file = -1;
|
||||
ec.ec = error;
|
||||
ec.operation = storage_error::remove;
|
||||
}
|
||||
}
|
||||
|
||||
DFLOG(stderr, "[%p] delete_files result: %s\n", static_cast<void*>(this)
|
||||
, ec.ec.message().c_str());
|
||||
|
|
|
@ -9317,7 +9317,7 @@ namespace libtorrent
|
|||
return limit_impl(peer_connection::download_channel);
|
||||
}
|
||||
|
||||
bool torrent::delete_files()
|
||||
bool torrent::delete_files(int const options)
|
||||
{
|
||||
TORRENT_ASSERT(is_single_thread());
|
||||
|
||||
|
@ -9333,7 +9333,7 @@ namespace libtorrent
|
|||
{
|
||||
TORRENT_ASSERT(m_storage);
|
||||
inc_refcount("delete_files");
|
||||
m_ses.disk_thread().async_delete_files(m_storage.get()
|
||||
m_ses.disk_thread().async_delete_files(m_storage.get(), options
|
||||
, boost::bind(&torrent::on_files_deleted, shared_from_this(), _1));
|
||||
m_deleted = true;
|
||||
return true;
|
||||
|
|
|
@ -72,7 +72,7 @@ struct test_storage_impl : storage_interface
|
|||
virtual void release_files(storage_error& ec) {}
|
||||
virtual void rename_file(int index, std::string const& new_filenamem
|
||||
, storage_error& ec) {}
|
||||
virtual void delete_files(storage_error& ec) {}
|
||||
virtual void delete_files(int, storage_error& ec) {}
|
||||
virtual void finalize_file(int, storage_error&) {}
|
||||
};
|
||||
|
||||
|
@ -81,7 +81,7 @@ static void nop() {}
|
|||
#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
|
||||
#define INITIALIZE_JOB(j) j.in_use = true;
|
||||
#else
|
||||
#define INITIALIZE_JOB(j)
|
||||
#define INITIALIZE_JOB(j)
|
||||
#endif
|
||||
|
||||
#define TEST_SETUP \
|
||||
|
|
|
@ -354,7 +354,7 @@ void test_remove(std::string const& test_path, bool unbuffered)
|
|||
, combine_path("_folder3", "test5.tmp"))), &st, ec);
|
||||
TEST_EQUAL(st.file_size, 8);
|
||||
|
||||
s->delete_files(se);
|
||||
s->delete_files(session::delete_files, se);
|
||||
if (se) print_error("delete_files", 0, se.ec);
|
||||
|
||||
if (se)
|
||||
|
@ -664,7 +664,7 @@ TORRENT_TEST(fastresume)
|
|||
{
|
||||
print_alerts(ses, "ses");
|
||||
s = h.status();
|
||||
if (s.progress == 1.0f)
|
||||
if (s.progress == 1.0f)
|
||||
{
|
||||
std::cout << "progress: 1.0f" << std::endl;
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue