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:
Marcos Pinto 2007-10-13 23:23:44 +00:00
parent a7868ed3fd
commit 0eb88197c7
13 changed files with 139 additions and 52 deletions

View File

@ -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)

View File

@ -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();

View File

@ -64,6 +64,7 @@ namespace libtorrent
, hash
, move_storage
, release_files
, delete_files
};
action_t action;

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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)

View File

@ -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(

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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:

View File

@ -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;
}