forked from premiere/premiere-libtorrent
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
|
||||
* replaced boost.filesystem with custom functions
|
||||
* 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 release_files() = 0;
|
||||
virtual bool delete_files() = 0;
|
||||
virtual void finalize_file(int index) {}
|
||||
virtual ~storage_interface() {}
|
||||
|
||||
// non virtual functions
|
||||
|
@ -6482,6 +6483,21 @@ following members::
|
|||
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
|
||||
============
|
||||
|
|
|
@ -93,6 +93,7 @@ namespace libtorrent
|
|||
, abort_torrent
|
||||
, update_settings
|
||||
, read_and_hash
|
||||
, finalize_file
|
||||
};
|
||||
|
||||
action_t action;
|
||||
|
|
|
@ -210,6 +210,10 @@ namespace libtorrent
|
|||
void close();
|
||||
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; }
|
||||
|
||||
// when opened in unbuffered mode, this is the
|
||||
|
|
|
@ -158,6 +158,8 @@ namespace libtorrent
|
|||
// non-zero return value indicates an error
|
||||
virtual bool delete_files() = 0;
|
||||
|
||||
virtual void finalize_file(int file) {}
|
||||
|
||||
disk_buffer_pool* disk_pool() { return m_disk_pool; }
|
||||
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; }
|
||||
void write_resume_data(entry& rd) const;
|
||||
|
||||
void async_finalize_file(int file);
|
||||
|
||||
void async_check_fastresume(lazy_entry const* resume_data
|
||||
, 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);
|
||||
|
||||
void finalize_file(int index);
|
||||
|
||||
// returns the number of pieces left in the
|
||||
// file currently being checked
|
||||
int skip_file() const;
|
||||
|
|
|
@ -1341,6 +1341,7 @@ namespace libtorrent
|
|||
, fence_operation // abort_torrent
|
||||
, 0 // update_settings
|
||||
, read_operation // read_and_hash
|
||||
, 0 // finalize_file
|
||||
};
|
||||
|
||||
bool is_fence_operation(disk_io_job const& j)
|
||||
|
@ -1672,6 +1673,14 @@ namespace libtorrent
|
|||
#endif
|
||||
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:
|
||||
{
|
||||
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
|
||||
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;
|
||||
::DeviceIoControl(m_file_handle, FSCTL_SET_SPARSE, 0, 0
|
||||
|
@ -1451,6 +1452,19 @@ namespace libtorrent
|
|||
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
|
||||
{
|
||||
#ifdef TORRENT_WINDOWS
|
||||
|
|
|
@ -349,6 +349,7 @@ namespace libtorrent
|
|||
m_save_path = complete(path);
|
||||
}
|
||||
|
||||
void finalize_file(int file);
|
||||
bool has_any_file();
|
||||
bool rename_file(int index, std::string const& new_filename);
|
||||
bool release_files();
|
||||
|
@ -398,6 +399,9 @@ namespace libtorrent
|
|||
boost::scoped_ptr<file_storage> m_mapped_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::string m_save_path;
|
||||
// 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)
|
||||
{
|
||||
ec.clear();
|
||||
int mode = file::read_write;
|
||||
if (m_settings
|
||||
&& (settings().disk_io_read_mode == session_settings::disable_os_cache
|
||||
|| (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);
|
||||
boost::shared_ptr<file> f = open_file(*file_iter, file::read_write, ec);
|
||||
std::string path = combine_path(m_save_path, file_iter->path);
|
||||
if (ec) set_error(path, ec);
|
||||
else if (f)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
file_storage::iterator i = files().begin();
|
||||
|
@ -696,19 +705,8 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(file_iter != files().end());
|
||||
}
|
||||
|
||||
std::string path = combine_path(m_save_path, file_iter->path);
|
||||
error_code ec;
|
||||
int mode = file::read_only;
|
||||
|
||||
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);
|
||||
boost::shared_ptr<file> file_handle = open_file(*file_iter, file::read_only, ec);
|
||||
if (!file_handle || ec) return slot;
|
||||
|
||||
size_type data_start = file_handle->sparse_end(file_offset);
|
||||
|
@ -1044,13 +1042,10 @@ ret:
|
|||
size_type file_offset = tor_off - file_iter->offset;
|
||||
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
|
||||
// it in case it's already opened in read-only mode
|
||||
boost::shared_ptr<file> f = m_pool.open_file(
|
||||
this, p, file::read_only, ec);
|
||||
error_code ec;
|
||||
boost::shared_ptr<file> f = open_file(*file_iter, file::read_only, ec);
|
||||
|
||||
size_type ret = 0;
|
||||
if (f && !ec) ret = f->phys_offset(file_offset);
|
||||
|
@ -1191,20 +1186,11 @@ ret:
|
|||
continue;
|
||||
}
|
||||
|
||||
std::string path = combine_path(m_save_path, file_iter->path);
|
||||
|
||||
error_code ec;
|
||||
int mode = op.mode;
|
||||
|
||||
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);
|
||||
file_handle = open_file(*file_iter, op.mode, ec);
|
||||
if (!file_handle || ec)
|
||||
{
|
||||
std::string path = combine_path(m_save_path, file_iter->path);
|
||||
TORRENT_ASSERT(ec);
|
||||
set_error(path, ec);
|
||||
return -1;
|
||||
|
@ -1310,6 +1296,18 @@ ret:
|
|||
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
|
||||
, file_storage const* mapped, std::string const& path, file_pool& fp)
|
||||
{
|
||||
|
@ -1426,10 +1424,23 @@ ret:
|
|||
m_storage->m_disk_pool = &m_io_thread;
|
||||
}
|
||||
|
||||
void piece_manager::finalize_file(int index)
|
||||
{ m_storage->finalize_file(index); }
|
||||
|
||||
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(
|
||||
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)
|
||||
{
|
||||
filesystem().async_finalize_file(file_index);
|
||||
if (m_ses.m_alerts.should_post<piece_finished_alert>())
|
||||
{
|
||||
// this file just completed, post alert
|
||||
|
|
Loading…
Reference in New Issue