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
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)); } { 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 struct TORRENT_EXPORT torrent_paused_alert: torrent_alert
{ {
torrent_paused_alert(torrent_handle const& h, std::string const& msg) 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) {} checker_impl(session_impl& s): m_ses(s), m_abort(false) {}
void operator()(); void operator()();
piece_checker_data* find_torrent(const sha1_hash& info_hash); 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 #ifndef NDEBUG
void check_invariant() const; void check_invariant() const;
@ -270,7 +270,7 @@ namespace libtorrent
, bool paused , bool paused
, void* userdata); , void* userdata);
void remove_torrent(torrent_handle const& h); void remove_torrent(torrent_handle const& h, int options);
std::vector<torrent_handle> get_torrents(); std::vector<torrent_handle> get_torrents();

View file

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

View file

@ -219,7 +219,13 @@ namespace libtorrent
// number of half open connections. // number of half open connections.
int num_connections() const; 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); void set_settings(session_settings const& s);
session_settings const& settings(); session_settings const& settings();

View file

@ -151,6 +151,10 @@ namespace libtorrent
// writing. This is called when a torrent has finished // writing. This is called when a torrent has finished
// downloading. // downloading.
virtual void release_files() = 0; virtual void release_files() = 0;
// this will close all open files and delete them
virtual void delete_files() = 0;
virtual ~storage_interface() {} virtual ~storage_interface() {}
}; };
@ -162,10 +166,6 @@ namespace libtorrent
boost::intrusive_ptr<torrent_info const> ti boost::intrusive_ptr<torrent_info const> ti
, fs::path const& path, file_pool& fp); , 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; struct disk_io_thread;
class TORRENT_EXPORT piece_manager 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&)> const& handler
= boost::function<void(int, disk_io_job const&)>()); = 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 void async_move_storage(fs::path const& p
, boost::function<void(int, disk_io_job const&)> const& handler); , boost::function<void(int, disk_io_job const&)> const& handler);
@ -274,7 +278,8 @@ namespace libtorrent
void switch_to_full_mode(); void switch_to_full_mode();
sha1_hash hash_for_piece_impl(int piece); 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); bool move_storage_impl(fs::path const& save_path);
@ -289,9 +294,6 @@ namespace libtorrent
storage_mode_t m_storage_mode; 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; boost::intrusive_ptr<torrent_info const> m_info;
// slots that haven't had any file storage allocated // slots that haven't had any file storage allocated

View file

@ -177,6 +177,8 @@ namespace libtorrent
void resume(); void resume();
bool is_paused() const { return m_paused; } bool is_paused() const { return m_paused; }
void delete_files();
// ============ start deprecation ============= // ============ start deprecation =============
void filter_piece(int index, bool filter); void filter_piece(int index, bool filter);
void filter_pieces(std::vector<bool> const& bitmask); void filter_pieces(std::vector<bool> const& bitmask);
@ -550,6 +552,7 @@ namespace libtorrent
private: 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_files_released(int ret, disk_io_job const& j);
void on_torrent_paused(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); 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) , boost::function<void(int, disk_io_job const&)> const& f)
{ {
TORRENT_ASSERT(!j.callback); TORRENT_ASSERT(!j.callback);
TORRENT_ASSERT(j.storage);
boost::mutex::scoped_lock l(m_mutex); boost::mutex::scoped_lock l(m_mutex);
std::deque<disk_io_job>::reverse_iterator i = m_jobs.rbegin(); std::deque<disk_io_job>::reverse_iterator i = m_jobs.rbegin();
@ -220,6 +221,7 @@ namespace libtorrent
bool free_buffer = true; bool free_buffer = true;
try try
{ {
TORRENT_ASSERT(j.storage);
#ifdef TORRENT_DISK_STATS #ifdef TORRENT_DISK_STATS
ptime start = time_now(); ptime start = time_now();
#endif #endif
@ -288,6 +290,12 @@ namespace libtorrent
#endif #endif
j.storage->release_files_impl(); j.storage->release_files_impl();
break; 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) catch (std::exception& e)

View file

@ -225,9 +225,9 @@ namespace libtorrent
, storage_mode, sc, paused, userdata); , 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( bool session::listen_on(

View file

@ -481,7 +481,7 @@ namespace detail
return 0; 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; INVARIANT_CHECK;
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
@ -490,6 +490,8 @@ namespace detail
if ((*i)->info_hash == info_hash) if ((*i)->info_hash == info_hash)
{ {
TORRENT_ASSERT((*i)->processing == false); TORRENT_ASSERT((*i)->processing == false);
if (options & session::delete_files)
(*i)->torrent_ptr->delete_files();
m_torrents.erase(i); m_torrents.erase(i);
return; return;
} }
@ -500,6 +502,8 @@ namespace detail
if ((*i)->info_hash == info_hash) if ((*i)->info_hash == info_hash)
{ {
TORRENT_ASSERT((*i)->processing == false); TORRENT_ASSERT((*i)->processing == false);
if (options & session::delete_files)
(*i)->torrent_ptr->delete_files();
m_processing.erase(i); m_processing.erase(i);
return; return;
} }
@ -1754,7 +1758,7 @@ namespace detail
return torrent_handle(this, &m_checker_impl, info_hash); 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; if (h.m_ses != this) return;
TORRENT_ASSERT(h.m_chk == &m_checker_impl || h.m_chk == 0); TORRENT_ASSERT(h.m_chk == &m_checker_impl || h.m_chk == 0);
@ -1769,6 +1773,8 @@ namespace detail
if (i != m_torrents.end()) if (i != m_torrents.end())
{ {
torrent& t = *i->second; torrent& t = *i->second;
if (options & session::delete_files)
t.delete_files();
t.abort(); t.abort();
if ((!t.is_paused() || t.should_request()) if ((!t.is_paused() || t.should_request())
@ -1815,7 +1821,7 @@ namespace detail
if (d != 0) if (d != 0)
{ {
if (d->processing) d->abort = true; 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; return;
} }
} }

View file

@ -361,6 +361,7 @@ namespace libtorrent
} }
void release_files(); void release_files();
void delete_files();
void initialize(bool allocate_files); void initialize(bool allocate_files);
bool move_storage(fs::path save_path); bool move_storage(fs::path save_path);
size_type read(char* buf, int slot, int offset, int size); size_type read(char* buf, int slot, int offset, int size);
@ -470,6 +471,38 @@ namespace libtorrent
std::vector<char>().swap(m_scratch_buffer); 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 void storage::write_resume_data(entry& rd) const
{ {
std::vector<std::pair<size_type, std::time_t> > file_sizes std::vector<std::pair<size_type, std::time_t> > file_sizes
@ -981,6 +1014,15 @@ namespace libtorrent
m_io_thread.add_job(j, handler); 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 void piece_manager::async_move_storage(fs::path const& p
, boost::function<void(int, disk_io_job const&)> const& handler) , 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)); 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) bool piece_manager::move_storage_impl(fs::path const& save_path)
{ {
if (m_storage->move_storage(save_path)) if (m_storage->move_storage(save_path))
@ -1077,6 +1114,7 @@ namespace libtorrent
} }
return false; return false;
} }
void piece_manager::export_piece_map( void piece_manager::export_piece_map(
std::vector<int>& p, std::vector<bool> const& have) const std::vector<int>& p, std::vector<bool> const& have) const
{ {
@ -1495,7 +1533,6 @@ namespace libtorrent
return false; return false;
} }
error_msg = "empty piece map";
m_state = state_full_check; m_state = state_full_check;
return false; return false;
} }

View file

@ -1032,6 +1032,16 @@ namespace libtorrent
m_announce_timer.cancel(); 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) void torrent::on_files_released(int ret, disk_io_job const& j)
{ {
/* /*
@ -2549,6 +2559,29 @@ namespace libtorrent
return limit; 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() void torrent::pause()
{ {
INVARIANT_CHECK; INVARIANT_CHECK;

View file

@ -169,7 +169,7 @@ class torrent_info:
self.trackers = "" self.trackers = ""
self.delete_me = False # set this to true, to delete it on next sync 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 # 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 = self.unique_IDs[unique_ID]
temp_fileinfo = deluge_core.get_file_info(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() self.sync()
# Remove .torrent file if asked to do so # Remove .torrent file if asked to do so
if torrent_also: if torrent_also:
os.remove(temp.filename) 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 # 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. # 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) new_torrent = torrent_info(full_new_name, save_dir, compact)
self.state.torrents[new_torrent] = None 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].delete_me = True
self.unique_IDs[unique_ID].del_data = data_also
# Sync the state.torrents and unique_IDs lists with the core # Sync the state.torrents and unique_IDs lists with the core
# ___ALL syncing code with the core is here, and ONLY here___ # ___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(): for unique_ID in self.unique_IDs.keys():
# print torrent # print torrent
if self.unique_IDs[unique_ID].delete_me: 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) to_delete.append(unique_ID)
for unique_ID in to_delete: 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()); assert(index < M_torrents->size());
torrent_handle& h = M_torrents->at(index).handle; torrent_handle& h = M_torrents->at(index).handle;
M_ses->remove_torrent(h, delete_files);
M_ses->remove_torrent(h);
torrents_t_iterator it = M_torrents->begin() + index; torrents_t_iterator it = M_torrents->begin() + index;
M_torrents->erase(it); 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) static PyObject *torrent_remove_torrent(PyObject *self, PyObject *args)
{ {
python_long unique_ID; python_long unique_ID, delete_files;
if (!PyArg_ParseTuple(args, "i", &unique_ID)) if (!PyArg_ParseTuple(args, "ii", &unique_ID, &delete_files))
return NULL; return NULL;
long index = get_index_from_unique_ID(unique_ID); long index = get_index_from_unique_ID(unique_ID);
if (PyErr_Occurred()) if (PyErr_Occurred())
return NULL; return NULL;
internal_remove_torrent(index); internal_remove_torrent(index, delete_files);
Py_INCREF(Py_None); return Py_None; Py_INCREF(Py_None); return Py_None;
} }