use libtorrent to remove files, which solves the problem of us deleting files that werent part of the torrent and other minor issues
This commit is contained in:
parent
a7868ed3fd
commit
0eb88197c7
|
@ -252,6 +252,16 @@ namespace libtorrent
|
|||
{ return std::auto_ptr<alert>(new storage_moved_alert(*this)); }
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT torrent_deleted_alert: torrent_alert
|
||||
{
|
||||
torrent_deleted_alert(torrent_handle const& h, std::string const& msg)
|
||||
: torrent_alert(h, alert::warning, msg)
|
||||
{}
|
||||
|
||||
virtual std::auto_ptr<alert> clone() const
|
||||
{ return std::auto_ptr<alert>(new torrent_deleted_alert(*this)); }
|
||||
};
|
||||
|
||||
struct TORRENT_EXPORT torrent_paused_alert: torrent_alert
|
||||
{
|
||||
torrent_paused_alert(torrent_handle const& h, std::string const& msg)
|
||||
|
|
|
@ -140,7 +140,7 @@ namespace libtorrent
|
|||
checker_impl(session_impl& s): m_ses(s), m_abort(false) {}
|
||||
void operator()();
|
||||
piece_checker_data* find_torrent(const sha1_hash& info_hash);
|
||||
void remove_torrent(sha1_hash const& info_hash);
|
||||
void remove_torrent(sha1_hash const& info_hash, int options);
|
||||
|
||||
#ifndef NDEBUG
|
||||
void check_invariant() const;
|
||||
|
@ -270,7 +270,7 @@ namespace libtorrent
|
|||
, bool paused
|
||||
, void* userdata);
|
||||
|
||||
void remove_torrent(torrent_handle const& h);
|
||||
void remove_torrent(torrent_handle const& h, int options);
|
||||
|
||||
std::vector<torrent_handle> get_torrents();
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ namespace libtorrent
|
|||
, hash
|
||||
, move_storage
|
||||
, release_files
|
||||
, delete_files
|
||||
};
|
||||
|
||||
action_t action;
|
||||
|
|
|
@ -219,7 +219,13 @@ namespace libtorrent
|
|||
// number of half open connections.
|
||||
int num_connections() const;
|
||||
|
||||
void remove_torrent(const torrent_handle& h);
|
||||
enum options_t
|
||||
{
|
||||
none = 0,
|
||||
delete_files = 1
|
||||
};
|
||||
|
||||
void remove_torrent(const torrent_handle& h, int options = none);
|
||||
|
||||
void set_settings(session_settings const& s);
|
||||
session_settings const& settings();
|
||||
|
|
|
@ -151,6 +151,10 @@ namespace libtorrent
|
|||
// writing. This is called when a torrent has finished
|
||||
// downloading.
|
||||
virtual void release_files() = 0;
|
||||
|
||||
// this will close all open files and delete them
|
||||
virtual void delete_files() = 0;
|
||||
|
||||
virtual ~storage_interface() {}
|
||||
};
|
||||
|
||||
|
@ -162,10 +166,6 @@ namespace libtorrent
|
|||
boost::intrusive_ptr<torrent_info const> ti
|
||||
, fs::path const& path, file_pool& fp);
|
||||
|
||||
// returns true if the filesystem the path relies on supports
|
||||
// sparse files or automatic zero filling of files.
|
||||
TORRENT_EXPORT bool supports_sparse_files(fs::path const& p);
|
||||
|
||||
struct disk_io_thread;
|
||||
|
||||
class TORRENT_EXPORT piece_manager
|
||||
|
@ -230,6 +230,10 @@ namespace libtorrent
|
|||
boost::function<void(int, disk_io_job const&)> const& handler
|
||||
= boost::function<void(int, disk_io_job const&)>());
|
||||
|
||||
void async_delete_files(
|
||||
boost::function<void(int, disk_io_job const&)> const& handler
|
||||
= boost::function<void(int, disk_io_job const&)>());
|
||||
|
||||
void async_move_storage(fs::path const& p
|
||||
, boost::function<void(int, disk_io_job const&)> const& handler);
|
||||
|
||||
|
@ -274,7 +278,8 @@ namespace libtorrent
|
|||
void switch_to_full_mode();
|
||||
sha1_hash hash_for_piece_impl(int piece);
|
||||
|
||||
void release_files_impl();
|
||||
void release_files_impl() { m_storage->release_files(); }
|
||||
void delete_files_impl() { m_storage->delete_files(); }
|
||||
|
||||
bool move_storage_impl(fs::path const& save_path);
|
||||
|
||||
|
@ -289,9 +294,6 @@ namespace libtorrent
|
|||
|
||||
storage_mode_t m_storage_mode;
|
||||
|
||||
// a bitmask representing the pieces we have
|
||||
std::vector<bool> m_have_piece;
|
||||
|
||||
boost::intrusive_ptr<torrent_info const> m_info;
|
||||
|
||||
// slots that haven't had any file storage allocated
|
||||
|
|
|
@ -177,6 +177,8 @@ namespace libtorrent
|
|||
void resume();
|
||||
bool is_paused() const { return m_paused; }
|
||||
|
||||
void delete_files();
|
||||
|
||||
// ============ start deprecation =============
|
||||
void filter_piece(int index, bool filter);
|
||||
void filter_pieces(std::vector<bool> const& bitmask);
|
||||
|
@ -550,6 +552,7 @@ namespace libtorrent
|
|||
|
||||
private:
|
||||
|
||||
void on_files_deleted(int ret, disk_io_job const& j);
|
||||
void on_files_released(int ret, disk_io_job const& j);
|
||||
void on_torrent_paused(int ret, disk_io_job const& j);
|
||||
void on_storage_moved(int ret, disk_io_job const& j);
|
||||
|
|
|
@ -125,6 +125,7 @@ namespace libtorrent
|
|||
, boost::function<void(int, disk_io_job const&)> const& f)
|
||||
{
|
||||
TORRENT_ASSERT(!j.callback);
|
||||
TORRENT_ASSERT(j.storage);
|
||||
boost::mutex::scoped_lock l(m_mutex);
|
||||
|
||||
std::deque<disk_io_job>::reverse_iterator i = m_jobs.rbegin();
|
||||
|
@ -220,6 +221,7 @@ namespace libtorrent
|
|||
bool free_buffer = true;
|
||||
try
|
||||
{
|
||||
TORRENT_ASSERT(j.storage);
|
||||
#ifdef TORRENT_DISK_STATS
|
||||
ptime start = time_now();
|
||||
#endif
|
||||
|
@ -288,6 +290,12 @@ namespace libtorrent
|
|||
#endif
|
||||
j.storage->release_files_impl();
|
||||
break;
|
||||
case disk_io_job::delete_files:
|
||||
#ifdef TORRENT_DISK_STATS
|
||||
m_log << log_time() << " delete" << std::endl;
|
||||
#endif
|
||||
j.storage->delete_files_impl();
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
|
|
|
@ -225,9 +225,9 @@ namespace libtorrent
|
|||
, storage_mode, sc, paused, userdata);
|
||||
}
|
||||
|
||||
void session::remove_torrent(const torrent_handle& h)
|
||||
void session::remove_torrent(const torrent_handle& h, int options)
|
||||
{
|
||||
m_impl->remove_torrent(h);
|
||||
m_impl->remove_torrent(h, options);
|
||||
}
|
||||
|
||||
bool session::listen_on(
|
||||
|
|
|
@ -481,7 +481,7 @@ namespace detail
|
|||
return 0;
|
||||
}
|
||||
|
||||
void checker_impl::remove_torrent(sha1_hash const& info_hash)
|
||||
void checker_impl::remove_torrent(sha1_hash const& info_hash, int options)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
|
||||
|
@ -490,6 +490,8 @@ namespace detail
|
|||
if ((*i)->info_hash == info_hash)
|
||||
{
|
||||
TORRENT_ASSERT((*i)->processing == false);
|
||||
if (options & session::delete_files)
|
||||
(*i)->torrent_ptr->delete_files();
|
||||
m_torrents.erase(i);
|
||||
return;
|
||||
}
|
||||
|
@ -500,6 +502,8 @@ namespace detail
|
|||
if ((*i)->info_hash == info_hash)
|
||||
{
|
||||
TORRENT_ASSERT((*i)->processing == false);
|
||||
if (options & session::delete_files)
|
||||
(*i)->torrent_ptr->delete_files();
|
||||
m_processing.erase(i);
|
||||
return;
|
||||
}
|
||||
|
@ -1754,7 +1758,7 @@ namespace detail
|
|||
return torrent_handle(this, &m_checker_impl, info_hash);
|
||||
}
|
||||
|
||||
void session_impl::remove_torrent(const torrent_handle& h)
|
||||
void session_impl::remove_torrent(const torrent_handle& h, int options)
|
||||
{
|
||||
if (h.m_ses != this) return;
|
||||
TORRENT_ASSERT(h.m_chk == &m_checker_impl || h.m_chk == 0);
|
||||
|
@ -1769,6 +1773,8 @@ namespace detail
|
|||
if (i != m_torrents.end())
|
||||
{
|
||||
torrent& t = *i->second;
|
||||
if (options & session::delete_files)
|
||||
t.delete_files();
|
||||
t.abort();
|
||||
|
||||
if ((!t.is_paused() || t.should_request())
|
||||
|
@ -1815,7 +1821,7 @@ namespace detail
|
|||
if (d != 0)
|
||||
{
|
||||
if (d->processing) d->abort = true;
|
||||
else m_checker_impl.remove_torrent(h.m_info_hash);
|
||||
else m_checker_impl.remove_torrent(h.m_info_hash, options);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -361,6 +361,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
void release_files();
|
||||
void delete_files();
|
||||
void initialize(bool allocate_files);
|
||||
bool move_storage(fs::path save_path);
|
||||
size_type read(char* buf, int slot, int offset, int size);
|
||||
|
@ -470,6 +471,38 @@ namespace libtorrent
|
|||
std::vector<char>().swap(m_scratch_buffer);
|
||||
}
|
||||
|
||||
void storage::delete_files()
|
||||
{
|
||||
// make sure we don't have the files open
|
||||
m_files.release(this);
|
||||
std::vector<char>().swap(m_scratch_buffer);
|
||||
|
||||
// delete the files from disk
|
||||
std::set<std::string> directories;
|
||||
typedef std::set<std::string>::iterator iter_t;
|
||||
for (torrent_info::file_iterator i = m_info->begin_files(true)
|
||||
, end(m_info->end_files(true)); i != end; ++i)
|
||||
{
|
||||
std::string p = (m_save_path / i->path).string();
|
||||
fs::path bp = i->path.branch_path();
|
||||
std::pair<iter_t, bool> ret = directories.insert(bp.string());
|
||||
while (ret.second && !bp.empty())
|
||||
{
|
||||
bp = bp.branch_path();
|
||||
std::pair<iter_t, bool> ret = directories.insert(bp.string());
|
||||
}
|
||||
std::remove(p.c_str());
|
||||
}
|
||||
|
||||
// remove the directories. Reverse order to delete
|
||||
// subdirectories first
|
||||
std::for_each(directories.rbegin(), directories.rend()
|
||||
, bind((int(*)(char const*))&std::remove, bind(&std::string::c_str, _1)));
|
||||
|
||||
std::string p = (m_save_path / m_info->name()).string();
|
||||
std::remove(p.c_str());
|
||||
}
|
||||
|
||||
void storage::write_resume_data(entry& rd) const
|
||||
{
|
||||
std::vector<std::pair<size_type, std::time_t> > file_sizes
|
||||
|
@ -981,6 +1014,15 @@ namespace libtorrent
|
|||
m_io_thread.add_job(j, handler);
|
||||
}
|
||||
|
||||
void piece_manager::async_delete_files(
|
||||
boost::function<void(int, disk_io_job const&)> const& handler)
|
||||
{
|
||||
disk_io_job j;
|
||||
j.storage = this;
|
||||
j.action = disk_io_job::delete_files;
|
||||
m_io_thread.add_job(j, handler);
|
||||
}
|
||||
|
||||
void piece_manager::async_move_storage(fs::path const& p
|
||||
, boost::function<void(int, disk_io_job const&)> const& handler)
|
||||
{
|
||||
|
@ -1063,11 +1105,6 @@ namespace libtorrent
|
|||
return m_storage->hash_for_slot(slot, ph, m_info->piece_size(piece));
|
||||
}
|
||||
|
||||
void piece_manager::release_files_impl()
|
||||
{
|
||||
m_storage->release_files();
|
||||
}
|
||||
|
||||
bool piece_manager::move_storage_impl(fs::path const& save_path)
|
||||
{
|
||||
if (m_storage->move_storage(save_path))
|
||||
|
@ -1077,6 +1114,7 @@ namespace libtorrent
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void piece_manager::export_piece_map(
|
||||
std::vector<int>& p, std::vector<bool> const& have) const
|
||||
{
|
||||
|
@ -1495,7 +1533,6 @@ namespace libtorrent
|
|||
return false;
|
||||
}
|
||||
|
||||
error_msg = "empty piece map";
|
||||
m_state = state_full_check;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1032,6 +1032,16 @@ namespace libtorrent
|
|||
m_announce_timer.cancel();
|
||||
}
|
||||
|
||||
void torrent::on_files_deleted(int ret, disk_io_job const& j)
|
||||
{
|
||||
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
|
||||
|
||||
if (alerts().should_post(alert::warning))
|
||||
{
|
||||
alerts().post_alert(torrent_deleted_alert(get_handle(), "files deleted"));
|
||||
}
|
||||
}
|
||||
|
||||
void torrent::on_files_released(int ret, disk_io_job const& j)
|
||||
{
|
||||
/*
|
||||
|
@ -2549,6 +2559,29 @@ namespace libtorrent
|
|||
return limit;
|
||||
}
|
||||
|
||||
void torrent::delete_files()
|
||||
{
|
||||
#if defined(TORRENT_VERBOSE_LOGGING)
|
||||
for (peer_iterator i = m_connections.begin();
|
||||
i != m_connections.end(); ++i)
|
||||
{
|
||||
(*i->second->m_logger) << "*** DELETING FILES IN TORRENT\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
disconnect_all();
|
||||
m_paused = true;
|
||||
// tell the tracker that we stopped
|
||||
m_event = tracker_request::stopped;
|
||||
|
||||
if (m_owning_storage.get())
|
||||
{
|
||||
TORRENT_ASSERT(m_storage);
|
||||
m_storage->async_delete_files(
|
||||
bind(&torrent::on_files_deleted, shared_from_this(), _1, _2));
|
||||
}
|
||||
}
|
||||
|
||||
void torrent::pause()
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
|
30
src/core.py
30
src/core.py
|
@ -169,7 +169,7 @@ class torrent_info:
|
|||
self.trackers = ""
|
||||
|
||||
self.delete_me = False # set this to true, to delete it on next sync
|
||||
|
||||
self.del_data = False # set this to true, to delete data on next sync
|
||||
|
||||
# The persistent state of the torrent system. Everything in this will be pickled
|
||||
|
||||
|
@ -360,31 +360,12 @@ class Manager:
|
|||
temp = self.unique_IDs[unique_ID]
|
||||
temp_fileinfo = deluge_core.get_file_info(unique_ID)
|
||||
|
||||
self.remove_torrent_ns(unique_ID)
|
||||
self.remove_torrent_ns(unique_ID, data_also)
|
||||
self.sync()
|
||||
|
||||
# Remove .torrent file if asked to do so
|
||||
if torrent_also:
|
||||
os.remove(temp.filename)
|
||||
|
||||
# Remove data, if asked to do so
|
||||
if data_also:
|
||||
# Must be done AFTER the torrent is removed
|
||||
# Note: can this be to the trash?
|
||||
for filedata in temp_fileinfo:
|
||||
filename = filedata['path']
|
||||
if filename.find(os.sep) != -1:
|
||||
# This is a file inside a directory inside the torrent. We can delete the
|
||||
# directory itself, save time
|
||||
try:
|
||||
shutil.rmtree(os.path.dirname(os.path.join(temp.save_dir, filename)))
|
||||
except OSError: # Perhaps it wasn't downloaded
|
||||
pass
|
||||
# Perhaps this is just a file, try to remove it
|
||||
try:
|
||||
os.remove(os.path.join(temp.save_dir, filename))
|
||||
except OSError:
|
||||
pass # No file just means it wasn't downloaded, we can continue
|
||||
|
||||
# A function to try and reload a torrent from a previous session. This is
|
||||
# used in the event that Deluge crashes and a blank state is loaded.
|
||||
|
@ -839,9 +820,9 @@ class Manager:
|
|||
new_torrent = torrent_info(full_new_name, save_dir, compact)
|
||||
self.state.torrents[new_torrent] = None
|
||||
|
||||
def remove_torrent_ns(self, unique_ID):
|
||||
def remove_torrent_ns(self, unique_ID, data_also):
|
||||
self.unique_IDs[unique_ID].delete_me = True
|
||||
|
||||
self.unique_IDs[unique_ID].del_data = data_also
|
||||
|
||||
# Sync the state.torrents and unique_IDs lists with the core
|
||||
# ___ALL syncing code with the core is here, and ONLY here___
|
||||
|
@ -886,7 +867,8 @@ class Manager:
|
|||
for unique_ID in self.unique_IDs.keys():
|
||||
# print torrent
|
||||
if self.unique_IDs[unique_ID].delete_me:
|
||||
deluge_core.remove_torrent(unique_ID)
|
||||
deluge_core.remove_torrent(unique_ID, \
|
||||
self.unique_IDs[unique_ID].del_data)
|
||||
to_delete.append(unique_ID)
|
||||
|
||||
for unique_ID in to_delete:
|
||||
|
|
|
@ -265,13 +265,12 @@ boost::filesystem::path const& save_path)
|
|||
}
|
||||
|
||||
|
||||
void internal_remove_torrent(long index)
|
||||
void internal_remove_torrent(long index, int delete_files)
|
||||
{
|
||||
assert(index < M_torrents->size());
|
||||
|
||||
torrent_handle& h = M_torrents->at(index).handle;
|
||||
|
||||
M_ses->remove_torrent(h);
|
||||
M_ses->remove_torrent(h, delete_files);
|
||||
|
||||
torrents_t_iterator it = M_torrents->begin() + index;
|
||||
M_torrents->erase(it);
|
||||
|
@ -728,15 +727,15 @@ static PyObject *torrent_move_storage(PyObject *self, PyObject *args)
|
|||
|
||||
static PyObject *torrent_remove_torrent(PyObject *self, PyObject *args)
|
||||
{
|
||||
python_long unique_ID;
|
||||
if (!PyArg_ParseTuple(args, "i", &unique_ID))
|
||||
python_long unique_ID, delete_files;
|
||||
if (!PyArg_ParseTuple(args, "ii", &unique_ID, &delete_files))
|
||||
return NULL;
|
||||
|
||||
long index = get_index_from_unique_ID(unique_ID);
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
|
||||
internal_remove_torrent(index);
|
||||
internal_remove_torrent(index, delete_files);
|
||||
|
||||
Py_INCREF(Py_None); return Py_None;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue