clear sparse flag on files that complete on windows
This commit is contained in:
parent
c1ea06f373
commit
d498c129ab
|
@ -1,3 +1,4 @@
|
||||||
|
* clear sparse flag on files that complete on windows
|
||||||
* support retry-after header for web seeds
|
* support retry-after header for web seeds
|
||||||
* replaced boost.filesystem with custom functions
|
* replaced boost.filesystem with custom functions
|
||||||
* replaced dependency on boost.thread by asio's internal thread primitives
|
* replaced dependency on boost.thread by asio's internal thread primitives
|
||||||
|
|
|
@ -6257,6 +6257,7 @@ The interface looks like this::
|
||||||
virtual bool rename_file(int file, std::string const& new_name) = 0;
|
virtual bool rename_file(int file, std::string const& new_name) = 0;
|
||||||
virtual bool release_files() = 0;
|
virtual bool release_files() = 0;
|
||||||
virtual bool delete_files() = 0;
|
virtual bool delete_files() = 0;
|
||||||
|
virtual void finalize_file(int index) {}
|
||||||
virtual ~storage_interface() {}
|
virtual ~storage_interface() {}
|
||||||
|
|
||||||
// non virtual functions
|
// non virtual functions
|
||||||
|
@ -6482,6 +6483,21 @@ following members::
|
||||||
void release_memory();
|
void release_memory();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
finalize_file()
|
||||||
|
---------------
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
virtual void finalize_file(int index);
|
||||||
|
|
||||||
|
This function is called each time a file is completely downloaded. The
|
||||||
|
storage implementation can perform last operations on a file. The file will
|
||||||
|
not be opened for writing after this.
|
||||||
|
|
||||||
|
``index`` is the index of the file that completed.
|
||||||
|
|
||||||
|
On windows the default storage implementation clears the sparse file flag
|
||||||
|
on the specified file.
|
||||||
|
|
||||||
magnet links
|
magnet links
|
||||||
============
|
============
|
||||||
|
|
|
@ -93,6 +93,7 @@ namespace libtorrent
|
||||||
, abort_torrent
|
, abort_torrent
|
||||||
, update_settings
|
, update_settings
|
||||||
, read_and_hash
|
, read_and_hash
|
||||||
|
, finalize_file
|
||||||
};
|
};
|
||||||
|
|
||||||
action_t action;
|
action_t action;
|
||||||
|
|
|
@ -210,6 +210,10 @@ namespace libtorrent
|
||||||
void close();
|
void close();
|
||||||
bool set_size(size_type size, error_code& ec);
|
bool set_size(size_type size, error_code& ec);
|
||||||
|
|
||||||
|
// called when we're done writing to the file.
|
||||||
|
// On windows this will clear the sparse bit
|
||||||
|
void finalize();
|
||||||
|
|
||||||
int open_mode() const { return m_open_mode; }
|
int open_mode() const { return m_open_mode; }
|
||||||
|
|
||||||
// when opened in unbuffered mode, this is the
|
// when opened in unbuffered mode, this is the
|
||||||
|
|
|
@ -158,6 +158,8 @@ namespace libtorrent
|
||||||
// non-zero return value indicates an error
|
// non-zero return value indicates an error
|
||||||
virtual bool delete_files() = 0;
|
virtual bool delete_files() = 0;
|
||||||
|
|
||||||
|
virtual void finalize_file(int file) {}
|
||||||
|
|
||||||
disk_buffer_pool* disk_pool() { return m_disk_pool; }
|
disk_buffer_pool* disk_pool() { return m_disk_pool; }
|
||||||
session_settings const& settings() const { return *m_settings; }
|
session_settings const& settings() const { return *m_settings; }
|
||||||
|
|
||||||
|
@ -204,6 +206,8 @@ namespace libtorrent
|
||||||
boost::intrusive_ptr<torrent_info const> info() const { return m_info; }
|
boost::intrusive_ptr<torrent_info const> info() const { return m_info; }
|
||||||
void write_resume_data(entry& rd) const;
|
void write_resume_data(entry& rd) const;
|
||||||
|
|
||||||
|
void async_finalize_file(int file);
|
||||||
|
|
||||||
void async_check_fastresume(lazy_entry const* resume_data
|
void async_check_fastresume(lazy_entry const* resume_data
|
||||||
, boost::function<void(int, disk_io_job const&)> const& handler);
|
, boost::function<void(int, disk_io_job const&)> const& handler);
|
||||||
|
|
||||||
|
@ -325,6 +329,8 @@ namespace libtorrent
|
||||||
|
|
||||||
size_type physical_offset(int piece_index, int offset);
|
size_type physical_offset(int piece_index, int offset);
|
||||||
|
|
||||||
|
void finalize_file(int index);
|
||||||
|
|
||||||
// returns the number of pieces left in the
|
// returns the number of pieces left in the
|
||||||
// file currently being checked
|
// file currently being checked
|
||||||
int skip_file() const;
|
int skip_file() const;
|
||||||
|
|
|
@ -1341,6 +1341,7 @@ namespace libtorrent
|
||||||
, fence_operation // abort_torrent
|
, fence_operation // abort_torrent
|
||||||
, 0 // update_settings
|
, 0 // update_settings
|
||||||
, read_operation // read_and_hash
|
, read_operation // read_and_hash
|
||||||
|
, 0 // finalize_file
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_fence_operation(disk_io_job const& j)
|
bool is_fence_operation(disk_io_job const& j)
|
||||||
|
@ -1672,6 +1673,14 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case disk_io_job::finalize_file:
|
||||||
|
{
|
||||||
|
#ifdef TORRENT_DISK_STATS
|
||||||
|
m_log << log_time() << " finalize_file " << j.piece << std::endl;
|
||||||
|
#endif
|
||||||
|
j.storage->finalize_file(j.piece);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case disk_io_job::read:
|
case disk_io_job::read:
|
||||||
{
|
{
|
||||||
if (test_error(j))
|
if (test_error(j))
|
||||||
|
|
16
src/file.cpp
16
src/file.cpp
|
@ -732,7 +732,8 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to make the file sparse if supported
|
// try to make the file sparse if supported
|
||||||
if (mode & file::sparse)
|
// only set this flag if the file is opened for writing
|
||||||
|
if ((mode & file::sparse) && (mode & rw_mask) != read_only)
|
||||||
{
|
{
|
||||||
DWORD temp;
|
DWORD temp;
|
||||||
::DeviceIoControl(m_file_handle, FSCTL_SET_SPARSE, 0, 0
|
::DeviceIoControl(m_file_handle, FSCTL_SET_SPARSE, 0, 0
|
||||||
|
@ -1451,6 +1452,19 @@ namespace libtorrent
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void file::finalize()
|
||||||
|
{
|
||||||
|
#ifdef TORRENT_WINDOWS
|
||||||
|
// according to MSDN, clearing the sparse flag of a file only
|
||||||
|
// works on windows vista and later
|
||||||
|
DWORD temp;
|
||||||
|
FILE_SET_SPARSE_BUFFER b;
|
||||||
|
b.SetSparse = FALSE;
|
||||||
|
::DeviceIoControl(m_file_handle, FSCTL_SET_SPARSE, &b, sizeof(b)
|
||||||
|
, 0, 0, &temp, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
size_type file::get_size(error_code& ec) const
|
size_type file::get_size(error_code& ec) const
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_WINDOWS
|
#ifdef TORRENT_WINDOWS
|
||||||
|
|
|
@ -349,6 +349,7 @@ namespace libtorrent
|
||||||
m_save_path = complete(path);
|
m_save_path = complete(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void finalize_file(int file);
|
||||||
bool has_any_file();
|
bool has_any_file();
|
||||||
bool rename_file(int index, std::string const& new_filename);
|
bool rename_file(int index, std::string const& new_filename);
|
||||||
bool release_files();
|
bool release_files();
|
||||||
|
@ -398,6 +399,9 @@ namespace libtorrent
|
||||||
boost::scoped_ptr<file_storage> m_mapped_files;
|
boost::scoped_ptr<file_storage> m_mapped_files;
|
||||||
file_storage const& m_files;
|
file_storage const& m_files;
|
||||||
|
|
||||||
|
// helper function to open a file in the file pool with the right mode
|
||||||
|
boost::shared_ptr<file> open_file(file_entry const& fe, int mode, error_code& ec) const;
|
||||||
|
|
||||||
std::vector<boost::uint8_t> m_file_priority;
|
std::vector<boost::uint8_t> m_file_priority;
|
||||||
std::string m_save_path;
|
std::string m_save_path;
|
||||||
// the file pool is typically stored in
|
// the file pool is typically stored in
|
||||||
|
@ -540,20 +544,13 @@ namespace libtorrent
|
||||||
if (ec || s.file_size > file_iter->size || file_iter->size == 0)
|
if (ec || s.file_size > file_iter->size || file_iter->size == 0)
|
||||||
{
|
{
|
||||||
ec.clear();
|
ec.clear();
|
||||||
int mode = file::read_write;
|
boost::shared_ptr<file> f = open_file(*file_iter, file::read_write, ec);
|
||||||
if (m_settings
|
std::string path = combine_path(m_save_path, file_iter->path);
|
||||||
&& (settings().disk_io_read_mode == session_settings::disable_os_cache
|
if (ec) set_error(path, ec);
|
||||||
|| (settings().disk_io_read_mode == session_settings::disable_os_cache_for_aligned_files
|
|
||||||
&& ((file_iter->offset + file_iter->file_base) & (m_page_size-1)) == 0)))
|
|
||||||
mode |= file::no_buffer;
|
|
||||||
if (!m_allocate_files) mode |= file::sparse;
|
|
||||||
boost::shared_ptr<file> f = m_pool.open_file(this
|
|
||||||
, combine_path(m_save_path, file_iter->path), mode, ec);
|
|
||||||
if (ec) set_error(combine_path(m_save_path, file_iter->path), ec);
|
|
||||||
else if (f)
|
else if (f)
|
||||||
{
|
{
|
||||||
f->set_size(file_iter->size, ec);
|
f->set_size(file_iter->size, ec);
|
||||||
if (ec) set_error(combine_path(m_save_path, file_iter->path), ec);
|
if (ec) set_error(path, ec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,6 +563,18 @@ namespace libtorrent
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void storage::finalize_file(int index)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(index >= 0 && index < m_files.num_files());
|
||||||
|
if (index < 0 || index >= m_files.num_files()) return;
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
boost::shared_ptr<file> f = open_file(files().at(index), file::read_write, ec);
|
||||||
|
if (ec || !f) return;
|
||||||
|
|
||||||
|
f->finalize();
|
||||||
|
}
|
||||||
|
|
||||||
bool storage::has_any_file()
|
bool storage::has_any_file()
|
||||||
{
|
{
|
||||||
file_storage::iterator i = files().begin();
|
file_storage::iterator i = files().begin();
|
||||||
|
@ -696,19 +705,8 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(file_iter != files().end());
|
TORRENT_ASSERT(file_iter != files().end());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string path = combine_path(m_save_path, file_iter->path);
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
int mode = file::read_only;
|
boost::shared_ptr<file> file_handle = open_file(*file_iter, file::read_only, ec);
|
||||||
|
|
||||||
boost::shared_ptr<file> file_handle;
|
|
||||||
int cache_setting = m_settings ? settings().disk_io_write_mode : 0;
|
|
||||||
if (cache_setting == session_settings::disable_os_cache
|
|
||||||
|| (cache_setting == session_settings::disable_os_cache_for_aligned_files
|
|
||||||
&& ((file_iter->offset + file_iter->file_base) & (m_page_size-1)) == 0))
|
|
||||||
mode |= file::no_buffer;
|
|
||||||
if (!m_allocate_files) mode |= file::sparse;
|
|
||||||
|
|
||||||
file_handle = m_pool.open_file(const_cast<storage*>(this), path, mode, ec);
|
|
||||||
if (!file_handle || ec) return slot;
|
if (!file_handle || ec) return slot;
|
||||||
|
|
||||||
size_type data_start = file_handle->sparse_end(file_offset);
|
size_type data_start = file_handle->sparse_end(file_offset);
|
||||||
|
@ -1044,13 +1042,10 @@ ret:
|
||||||
size_type file_offset = tor_off - file_iter->offset;
|
size_type file_offset = tor_off - file_iter->offset;
|
||||||
TORRENT_ASSERT(file_offset >= 0);
|
TORRENT_ASSERT(file_offset >= 0);
|
||||||
|
|
||||||
std::string p = combine_path(m_save_path, file_iter->path);
|
|
||||||
error_code ec;
|
|
||||||
|
|
||||||
// open the file read only to avoid re-opening
|
// open the file read only to avoid re-opening
|
||||||
// it in case it's already opened in read-only mode
|
// it in case it's already opened in read-only mode
|
||||||
boost::shared_ptr<file> f = m_pool.open_file(
|
error_code ec;
|
||||||
this, p, file::read_only, ec);
|
boost::shared_ptr<file> f = open_file(*file_iter, file::read_only, ec);
|
||||||
|
|
||||||
size_type ret = 0;
|
size_type ret = 0;
|
||||||
if (f && !ec) ret = f->phys_offset(file_offset);
|
if (f && !ec) ret = f->phys_offset(file_offset);
|
||||||
|
@ -1191,20 +1186,11 @@ ret:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string path = combine_path(m_save_path, file_iter->path);
|
|
||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
int mode = op.mode;
|
file_handle = open_file(*file_iter, op.mode, ec);
|
||||||
|
|
||||||
if (op.cache_setting == session_settings::disable_os_cache
|
|
||||||
|| (op.cache_setting == session_settings::disable_os_cache_for_aligned_files
|
|
||||||
&& ((file_iter->offset + file_iter->file_base) & (m_page_size-1)) == 0))
|
|
||||||
mode |= file::no_buffer;
|
|
||||||
if (!m_allocate_files) mode |= file::sparse;
|
|
||||||
|
|
||||||
file_handle = m_pool.open_file(this, path, mode, ec);
|
|
||||||
if (!file_handle || ec)
|
if (!file_handle || ec)
|
||||||
{
|
{
|
||||||
|
std::string path = combine_path(m_save_path, file_iter->path);
|
||||||
TORRENT_ASSERT(ec);
|
TORRENT_ASSERT(ec);
|
||||||
set_error(path, ec);
|
set_error(path, ec);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1310,6 +1296,18 @@ ret:
|
||||||
return readv(&b, slot, offset, 1);
|
return readv(&b, slot, offset, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr<file> storage::open_file(file_entry const& fe, int mode, error_code& ec) const
|
||||||
|
{
|
||||||
|
int cache_setting = m_settings ? settings().disk_io_write_mode : 0;
|
||||||
|
if (cache_setting == session_settings::disable_os_cache
|
||||||
|
|| (cache_setting == session_settings::disable_os_cache_for_aligned_files
|
||||||
|
&& ((fe.offset + fe.file_base) & (m_page_size-1)) == 0))
|
||||||
|
mode |= file::no_buffer;
|
||||||
|
if (!m_allocate_files) mode |= file::sparse;
|
||||||
|
|
||||||
|
return m_pool.open_file(const_cast<storage*>(this), combine_path(m_save_path, fe.path), mode, ec);
|
||||||
|
}
|
||||||
|
|
||||||
storage_interface* default_storage_constructor(file_storage const& fs
|
storage_interface* default_storage_constructor(file_storage const& fs
|
||||||
, file_storage const* mapped, std::string const& path, file_pool& fp)
|
, file_storage const* mapped, std::string const& path, file_pool& fp)
|
||||||
{
|
{
|
||||||
|
@ -1426,10 +1424,23 @@ ret:
|
||||||
m_storage->m_disk_pool = &m_io_thread;
|
m_storage->m_disk_pool = &m_io_thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void piece_manager::finalize_file(int index)
|
||||||
|
{ m_storage->finalize_file(index); }
|
||||||
|
|
||||||
piece_manager::~piece_manager()
|
piece_manager::~piece_manager()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void piece_manager::async_finalize_file(int file)
|
||||||
|
{
|
||||||
|
disk_io_job j;
|
||||||
|
j.storage = this;
|
||||||
|
j.action = disk_io_job::finalize_file;
|
||||||
|
j.piece = file;
|
||||||
|
boost::function<void(int, disk_io_job const&)> empty;
|
||||||
|
m_io_thread.add_job(j, empty);
|
||||||
|
}
|
||||||
|
|
||||||
void piece_manager::async_save_resume_data(
|
void piece_manager::async_save_resume_data(
|
||||||
boost::function<void(int, disk_io_job const&)> const& handler)
|
boost::function<void(int, disk_io_job const&)> const& handler)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2003,6 +2003,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_file_progress[file_index] >= m_torrent_file->files().at(file_index).size)
|
if (m_file_progress[file_index] >= m_torrent_file->files().at(file_index).size)
|
||||||
{
|
{
|
||||||
|
filesystem().async_finalize_file(file_index);
|
||||||
if (m_ses.m_alerts.should_post<piece_finished_alert>())
|
if (m_ses.m_alerts.should_post<piece_finished_alert>())
|
||||||
{
|
{
|
||||||
// this file just completed, post alert
|
// this file just completed, post alert
|
||||||
|
|
Loading…
Reference in New Issue