diff --git a/docs/manual.html b/docs/manual.html
index 3d94ed206..7054120d2 100644
--- a/docs/manual.html
+++ b/docs/manual.html
@@ -4393,7 +4393,8 @@ struct session_settings
bool always_send_user_agent;
bool apply_ip_filter_to_trackers;
int read_job_every;
- use_disk_read_ahead;
+ bool use_disk_read_ahead;
+ bool lock_files;
};
version is automatically set to the libtorrent version you're using
@@ -5115,6 +5116,10 @@ instead pick one read job off of the sorted queue, where x is use_disk_read_ahead defaults to true and will attempt to optimize disk reads
by giving the operating system heads up of disk read requests as they are queued
in the disk job queue. This gives a significant performance boost for seeding.
+lock_files determines whether or not to lock files which libtorrent is downloading
+to or seeding from. This is implemented using fcntl(F_SETLK) on unix systems and
+by not passing in SHARE_READ and SHARE_WRITE on windows. This might prevent
+3rd party processes from corrupting the files under libtorrent's feet.
diff --git a/docs/manual.rst b/docs/manual.rst
index 4c587fcea..4a404ef9f 100644
--- a/docs/manual.rst
+++ b/docs/manual.rst
@@ -4405,7 +4405,8 @@ session_settings
bool always_send_user_agent;
bool apply_ip_filter_to_trackers;
int read_job_every;
- use_disk_read_ahead;
+ bool use_disk_read_ahead;
+ bool lock_files;
};
``version`` is automatically set to the libtorrent version you're using
@@ -5274,6 +5275,11 @@ instead pick one read job off of the sorted queue, where *x* is ``read_job_every
by giving the operating system heads up of disk read requests as they are queued
in the disk job queue. This gives a significant performance boost for seeding.
+``lock_files`` determines whether or not to lock files which libtorrent is downloading
+to or seeding from. This is implemented using ``fcntl(F_SETLK)`` on unix systems and
+by not passing in ``SHARE_READ`` and ``SHARE_WRITE`` on windows. This might prevent
+3rd party processes from corrupting the files under libtorrent's feet.
+
pe_settings
===========
diff --git a/include/libtorrent/file.hpp b/include/libtorrent/file.hpp
index dd5fd1f12..4fb9c6489 100644
--- a/include/libtorrent/file.hpp
+++ b/include/libtorrent/file.hpp
@@ -182,10 +182,10 @@ namespace libtorrent
read_write = 2,
rw_mask = read_only | write_only | read_write,
no_buffer = 4,
- mode_mask = rw_mask | no_buffer,
sparse = 8,
no_atime = 16,
random_access = 32,
+ lock_file = 64,
attribute_hidden = 0x1000,
attribute_executable = 0x2000,
diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp
index a4b1e02a6..1cfd0fa9a 100644
--- a/include/libtorrent/session_settings.hpp
+++ b/include/libtorrent/session_settings.hpp
@@ -269,6 +269,7 @@ namespace libtorrent
, apply_ip_filter_to_trackers(true)
, read_job_every(10)
, use_disk_read_ahead(true)
+ , lock_files(false)
{}
// libtorrent version. Used for forward binary compatibility
@@ -1075,6 +1076,10 @@ namespace libtorrent
// issue posix_fadvise() or fcntl(F_RDADVISE) for disk reads
// ahead of time
bool use_disk_read_ahead;
+
+ // if set to true, files will be locked when opened.
+ // preventing any other process from modifying them
+ bool lock_files;
};
#ifndef TORRENT_DISABLE_DHT
diff --git a/src/file.cpp b/src/file.cpp
index be033ff69..d479a47a4 100644
--- a/src/file.cpp
+++ b/src/file.cpp
@@ -755,29 +755,17 @@ namespace libtorrent
struct open_mode_t
{
DWORD rw_mode;
- DWORD share_mode;
DWORD create_mode;
- DWORD flags;
};
const static open_mode_t mode_array[] =
{
// read_only
- {GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, 0},
+ {GENERIC_READ, OPEN_EXISTING},
// write_only
- {GENERIC_WRITE, FILE_SHARE_READ, OPEN_ALWAYS, 0},
+ {GENERIC_WRITE, OPEN_ALWAYS},
// read_write
- {GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, OPEN_ALWAYS, 0},
- // invalid option
- {0,0,0,0},
- // read_only no_buffer
- {GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING },
- // write_only no_buffer
- {GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING },
- // read_write no_buffer
- {GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING },
- // invalid option
- {0,0,0,0}
+ {GENERIC_WRITE | GENERIC_READ, OPEN_ALWAYS},
};
const static DWORD attrib_array[] =
@@ -788,6 +776,16 @@ namespace libtorrent
FILE_ATTRIBUTE_HIDDEN, // hidden + executable
};
+ const static DWORD share_array[] =
+ {
+ // read only (no locking)
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ // write only (no locking)
+ FILE_SHARE_READ,
+ // read/write (no locking)
+ FILE_SHARE_READ,
+ };
+
#if TORRENT_USE_WSTRING
#define CreateFile_ CreateFileW
m_path = convert_to_wstring(path);
@@ -797,14 +795,17 @@ namespace libtorrent
#endif
TORRENT_ASSERT((mode & mode_mask) < sizeof(mode_array)/sizeof(mode_array[0]));
- open_mode_t const& m = mode_array[mode & mode_mask];
+ open_mode_t const& m = mode_array[mode & rw_mask];
DWORD a = attrib_array[(mode & attribute_mask) >> 12];
- DWORD extra_flags = ((mode & random_access) ? FILE_FLAG_RANDOM_ACCESS : 0)
- | (a ? a : FILE_ATTRIBUTE_NORMAL);
+ DWORD flags
+ = ((mode & random_access) ? FILE_FLAG_RANDOM_ACCESS : 0)
+ | (a ? a : FILE_ATTRIBUTE_NORMAL)
+ | ((mode & no_buffer) ? FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING : 0);
- m_file_handle = CreateFile_(m_path.c_str(), m.rw_mode, m.share_mode, 0
- , m.create_mode, m.flags | extra_flags, 0);
+ m_file_handle = CreateFile_(m_path.c_str(), m.rw_mode
+ , (mode & lock_file) ? 0 : share_array[mode & rw_mask]
+ , 0, m.create_mode, flags, 0);
if (m_file_handle == INVALID_HANDLE_VALUE)
{
@@ -869,6 +870,25 @@ namespace libtorrent
return false;
}
+#ifdef F_SETLK
+ if (mode & lock_file)
+ {
+ struct flock l =
+ {
+ 0, // start offset
+ 0, // length (0 = until EOF)
+ getpid(), // owner
+ (mode & write_only) ? F_WRLCK : F_RDLCK, // lock type
+ SEEK_SET // whence
+ };
+ if (fcntl(m_fd, F_SETLK, &l) != 0)
+ {
+ ec.assign(errno, get_posix_category());
+ return false;
+ }
+ }
+#endif
+
#ifdef DIRECTIO_ON
// for solaris
if (mode & no_buffer)
diff --git a/src/storage.cpp b/src/storage.cpp
index 039205a60..75291eddd 100644
--- a/src/storage.cpp
+++ b/src/storage.cpp
@@ -1382,6 +1382,8 @@ ret:
|| (cache_setting == session_settings::disable_os_cache_for_aligned_files
&& ((fe->offset + files().file_base(*fe)) & (m_page_size-1)) == 0))
mode |= file::no_buffer;
+ bool lock_files = m_settings ? settings().lock_files : false;
+ if (lock_files) mode |= file::lock_file;
if (!m_allocate_files) mode |= file::sparse;
if (m_settings && settings().no_atime_storage) mode |= file::no_atime;