boost::interprocess::file_lock cannot open the files that contain characters which cannot be parsed by the user’s code page on Windows.
This PR is seperated from #13426 for easier review.
boost::interprocess::file_lock cannot open the files that contain characters which cannot be parsed by the user’s code page on Windows.
This PR is seperated from #13426 for easier review.
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.
boost::interprocess::file_lock
altogether, no?
20@@ -19,6 +21,21 @@ namespace fs = boost::filesystem;
21 namespace fsbridge {
22 FILE *fopen(const fs::path& p, const char *mode);
23 FILE *freopen(const fs::path& p, const char *mode, FILE *stream);
24+
25+ class FileLock
26+ {
27+ public:
28+ FileLock(const fs::path& file);
41+ lock.l_type = F_WRLCK;
42+ lock.l_whence = SEEK_SET;
43+ lock.l_start = 0;
44+ lock.l_len = 0;
45+ return -1 != fcntl(fd, F_SETLK, &lock);
46+}
The relevant boost implementation, for reference:
0inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired)
1{
2 struct ::flock lock;
3 lock.l_type = F_WRLCK;
4 lock.l_whence = SEEK_SET;
5 lock.l_start = 0;
6 lock.l_len = 0;
7 int ret = ::fcntl(hnd, F_SETLK, &lock);
8 if(ret == -1){
9 return (errno == EAGAIN || errno == EACCES) ?
10 acquired = false, true : false;
11 }
12 return (acquired = true);
13}
https://www.boost.org/doc/libs/1_67_0/boost/interprocess/detail/os_file_functions.hpp
Should we distinguish between hard (e.g. EINVAL) and soft (EAGAIN, EACCES) failures, as they do? We could throw in the former case? https://www.gnu.org/software/libc/manual/html_node/File-Locks.html
63+ if (hFile == INVALID_HANDLE_VALUE) {
64+ return false;
65+ }
66+ _OVERLAPPED overlapped = {0};
67+ return LockFileEx((HANDLE)hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, 0, 0, &overlapped);
68+}
The relevant boost implementation, for reference:
0inline bool try_acquire_file_lock(file_handle_t hnd, bool &acquired)
1{
2 const unsigned long len = ((unsigned long)-1);
3 winapi::interprocess_overlapped overlapped;
4 std::memset(&overlapped, 0, sizeof(overlapped));
5 if(!winapi::lock_file_ex
6 (hnd, winapi::lockfile_exclusive_lock | winapi::lockfile_fail_immediately,
7 0, len, len, &overlapped)){
8 return winapi::get_last_error() == winapi::error_lock_violation ?
9 acquired = false, true : false;
10
11 }
12 return (acquired = true);
13}
https://www.boost.org/doc/libs/1_67_0/boost/interprocess/detail/os_file_functions.hpp
Similar question re. GetLastError
?
(HANDLE)
cast necessary?
@ken2812221 FYI boost does throw on the failures noted above:
0inline bool file_lock::try_lock()
1{
2 bool result;
3 if(!ipcdetail::try_acquire_file_lock(m_file_hnd, result)){
4 error_info err(system_error_code());
5 throw interprocess_exception(err);
6 }
7 return result;
8}
9
10namespace boost {
11namespace interprocess {
12inline int system_error_code() // artifact of POSIX and WINDOWS error reporting
13{
14 #if (defined BOOST_INTERPROCESS_WINDOWS)
15 return winapi::get_last_error();
16 #else
17 return errno; // GCC 3.1 won't accept ::errno
18 #endif
19}
https://www.boost.org/doc/libs/1_67_0/boost/interprocess/sync/file_lock.hpp https://www.boost.org/doc/libs/1_46_1/boost/interprocess/errors.hpp
Yeah so the net effect is the loss of this message:
return error("Error while attempting to lock directory %s: %s", directory.string(), e.what());
Certainly not a big deal but breadcrumbs can mean the difference between an easy fix and a maddening mystery.
62+{
63+ if (hFile == INVALID_HANDLE_VALUE) {
64+ return false;
65+ }
66+ _OVERLAPPED overlapped = {0};
67+ return LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, 0, 0, &overlapped);
The CreateFileW with 0 sharing effectively opens the file as exclusive (locking it). It feels the TryLock() here is redundant because we don’t require locking of specific bytes.
Perhaps the TryLock() should be the one doing the CreateFileW. Apologies if I’ve misunderstood something here :-)
20@@ -12,4 +21,82 @@ FILE *freopen(const fs::path& p, const char *mode, FILE *stream)
21 return ::freopen(p.string().c_str(), mode, stream);
22 }
23
24+#ifndef WIN32
25+
26+std::string GetErrorReason() {
static
58+ }
59+ return true;
60+}
61+#else
62+
63+std::string GetErrorReason() {
static
169- }
170- } catch (const boost::interprocess::interprocess_exception& e) {
171- return error("Error while attempting to lock directory %s: %s", directory.string(), e.what());
172+ auto lock = MakeUnique<fsbridge::FileLock>(pathLockFile);
173+ if (!lock->TryLock()) {
174+ return error("Error while attempting to lock directory %s: %s", directory.string(), lock->GetReason());
lightly tested ACK 80119487840db0c3944a89f92772660ee594c4c3
tested on-
48+ struct flock lock;
49+ lock.l_type = F_WRLCK;
50+ lock.l_whence = SEEK_SET;
51+ lock.l_start = 0;
52+ lock.l_len = 0;
53+ if (-1 == fcntl(fd, F_SETLK, &lock)) {
fcntl(fd, F_SETLK, &lock) == -1
(more consistent with the other if statements in the code)
boost::interprocess::file_lock cannot open the files that contain characters which cannot be parsed by the user's code page on Windows.
This commit add a new class to handle those specific file for Windows.