Coverage Report

Created: 2026-05-16 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/log4cplus/src/lockfile.cxx
Line
Count
Source
1
// -*- C++ -*-
2
//
3
//  Copyright (C) 2012-2017, Vaclav Zeman. All rights reserved.
4
//
5
//  Redistribution and use in source and binary forms, with or without modifica-
6
//  tion, are permitted provided that the following conditions are met:
7
//
8
//  1. Redistributions of  source code must  retain the above copyright  notice,
9
//     this list of conditions and the following disclaimer.
10
//
11
//  2. Redistributions in binary form must reproduce the above copyright notice,
12
//     this list of conditions and the following disclaimer in the documentation
13
//     and/or other materials provided with the distribution.
14
//
15
//  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
16
//  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17
//  FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
18
//  APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
19
//  INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
20
//  DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
21
//  OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
22
//  ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
23
//  (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
24
//  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26
#include <log4cplus/config.hxx>
27
28
#if defined (LOG4CPLUS_HAVE_SYS_TYPES_H)
29
#include <sys/types.h>
30
#endif
31
#if defined (LOG4CPLUS_HAVE_SYS_STAT_H)
32
#include <sys/stat.h>
33
#endif
34
#if defined (LOG4CPLUS_HAVE_SYS_FILE_H)
35
#include <sys/file.h>
36
#endif
37
#if defined (LOG4CPLUS_HAVE_UNISTD_H)
38
#include <unistd.h>
39
#endif
40
#if defined (LOG4CPLUS_HAVE_FCNTL_H)
41
#include <fcntl.h>
42
#endif
43
#if defined (LOG4CPLUS_HAVE_IO_H)
44
#include <io.h>
45
#endif
46
#if defined (_WIN32)
47
#include <tchar.h>
48
#include <share.h>
49
#endif
50
#include <log4cplus/config/windowsh-inc.h>
51
52
#include <stdexcept>
53
#include <cerrno>
54
#include <limits>
55
#include <cstring>
56
57
#include <log4cplus/helpers/lockfile.h>
58
#include <log4cplus/helpers/stringhelper.h>
59
#include <log4cplus/helpers/loglog.h>
60
#include <log4cplus/internal/env.h>
61
62
#if defined (_WIN32)
63
#  define LOG4CPLUS_USE_WIN32_LOCKFILEEX
64
#else
65
#  if defined (O_EXLOCK)
66
#    define LOG4CPLUS_USE_O_EXLOCK
67
#  elif defined (LOG4CPLUS_HAVE_FCNTL) && defined (F_SETLKW)
68
#    define LOG4CPLUS_USE_SETLKW
69
#  elif defined (LOG4CPLUS_HAVE_LOCKF)
70
#    define LOG4CPLUS_USE_LOCKF
71
#  elif defined (LOG4CPLUS_HAVE_FLOCK)
72
#    define LOG4CPLUS_USE_FLOCK
73
#  endif
74
#  if defined (LOG4CPLUS_USE_O_EXLOCK) || defined (LOG4CPLUS_USE_SETLKW) \
75
    || defined (LOG4CPLUS_USE_LOCKF) || defined (LOG4CPLUS_USE_FLOCK)
76
#    define LOG4CPLUS_USE_POSIX_LOCKING
77
#  endif
78
#endif
79
80
#if ! defined (LOG4CPLUS_USE_POSIX_LOCKING) && ! defined (_WIN32)
81
#error "no usable file locking"
82
#endif
83
84
namespace log4cplus { namespace helpers {
85
86
87
#if defined (_WIN32)
88
#if defined (__BORLANDC__)
89
int const OPEN_FLAGS = O_RDWR | O_CREAT | O_NOINHERIT;
90
int const OPEN_SHFLAGS = SH_DENYNO;
91
int const OPEN_MODE = S_IREAD | S_IWRITE;
92
#else
93
int const OPEN_FLAGS = _O_RDWR | _O_CREAT /*| _O_TEMPORARY*/ | _O_NOINHERIT;
94
int const OPEN_SHFLAGS = _SH_DENYNO;
95
int const OPEN_MODE = _S_IREAD | _S_IWRITE;
96
#endif
97
98
namespace
99
{
100
101
static
102
HANDLE
103
get_os_HANDLE (int fd)
104
{
105
    HANDLE fh = reinterpret_cast<HANDLE>(_get_osfhandle (fd));
106
    if (fh == INVALID_HANDLE_VALUE)
107
        getLogLog ().error (tstring (LOG4CPLUS_TEXT ("_get_osfhandle() failed: "))
108
            + convertIntegerToString (errno), true);
109
110
    return fh;
111
}
112
113
} // namespace
114
115
#elif defined (LOG4CPLUS_USE_POSIX_LOCKING)
116
int const OPEN_FLAGS = O_RDWR | O_CREAT
117
#if defined (O_CLOEXEC)
118
    | O_CLOEXEC
119
#endif
120
    ;
121
122
mode_t const OPEN_MODE = (S_IRWXU ^ S_IXUSR)
123
    | (S_IRWXG ^ S_IXGRP)
124
    | (S_IRWXO ^ S_IXOTH);
125
126
#endif
127
128
129
//! Helper function that sets FD_CLOEXEC on descriptor on platforms
130
//! that support it.
131
LOG4CPLUS_PRIVATE
132
bool
133
trySetCloseOnExec (int fd)
134
0
{
135
#if defined (WIN32)
136
    int ret = SetHandleInformation (get_os_HANDLE (fd), HANDLE_FLAG_INHERIT, 0);
137
    if (! ret)
138
    {
139
        DWORD eno = GetLastError ();
140
        getLogLog ().warn (
141
            tstring (
142
                LOG4CPLUS_TEXT ("could not unset HANDLE_FLAG_INHERIT on fd: "))
143
            + convertIntegerToString (fd)
144
            + LOG4CPLUS_TEXT (", errno: ")
145
            + convertIntegerToString (eno));
146
        return false;
147
    }
148
149
#elif defined (FD_CLOEXEC)
150
0
    int ret = fcntl (fd, F_SETFD, FD_CLOEXEC);
151
0
    if (ret == -1)
152
0
    {
153
0
        int eno = errno;
154
0
        getLogLog ().warn (
155
0
            tstring (LOG4CPLUS_TEXT ("could not set FD_CLOEXEC on fd: "))
156
0
            + convertIntegerToString (fd)
157
0
            + LOG4CPLUS_TEXT (", errno: ")
158
0
            + convertIntegerToString (eno));
159
0
        return false;
160
0
    }
161
#else
162
    return false;
163
164
#endif
165
166
0
    return true;
167
0
}
168
169
170
//
171
//
172
//
173
174
struct LockFile::Impl
175
{
176
#if defined (LOG4CPLUS_USE_POSIX_LOCKING) \
177
    || defined (_WIN32)
178
    int fd;
179
180
#endif
181
};
182
183
184
//
185
//
186
//
187
188
LockFile::LockFile (tstring const & lf, bool create_dirs_)
189
0
    : lock_file_name (lf)
190
0
    , data (new LockFile::Impl)
191
0
    , create_dirs (create_dirs_)
192
0
{
193
#if defined (LOG4CPLUS_USE_O_EXLOCK)
194
    data->fd = -1;
195
196
#else
197
0
    open (OPEN_FLAGS);
198
199
0
#endif
200
0
}
201
202
203
LockFile::~LockFile ()
204
0
{
205
0
    close ();
206
0
    delete data;
207
0
}
208
209
210
void
211
LockFile::open (int open_flags) const
212
0
{
213
0
    if (create_dirs)
214
0
        internal::make_dirs (lock_file_name);
215
216
#if defined (_WIN32)
217
#  if defined (LOG4CPLUS_HAVE__TSOPEN_S) && defined (_tsopen_s)
218
    errno_t eno = _tsopen_s (&data->fd, lock_file_name.c_str (), open_flags,
219
        OPEN_SHFLAGS, OPEN_MODE);
220
    if (eno != 0)
221
#  elif defined (LOG4CPLUS_HAVE__TSOPEN) && defined (_tsopen)
222
    data->fd = _tsopen (lock_file_name.c_str (), open_flags, OPEN_SHFLAGS,
223
        OPEN_MODE);
224
    if (data->fd == -1)
225
#  else
226
#    error "Neither _tsopen_s() nor _tsopen() is available."
227
#  endif
228
        getLogLog ().error (tstring (LOG4CPLUS_TEXT("could not open or create file "))
229
            + lock_file_name, true);
230
231
#elif defined (LOG4CPLUS_USE_POSIX_LOCKING)
232
0
    data->fd = ::open (LOG4CPLUS_TSTRING_TO_STRING (lock_file_name).c_str (),
233
0
        open_flags, OPEN_MODE);
234
0
    if (data->fd == -1)
235
0
        getLogLog ().error (
236
0
            tstring (LOG4CPLUS_TEXT ("could not open or create file "))
237
0
            + lock_file_name, true);
238
239
#if ! defined (O_CLOEXEC)
240
    if (! trySetCloseOnExec (data->fd))
241
        getLogLog ().warn (
242
            tstring (LOG4CPLUS_TEXT("could not set FD_CLOEXEC on file "))
243
            + lock_file_name);
244
245
#endif
246
0
#endif
247
0
}
248
249
250
void
251
LockFile::close () const
252
0
{
253
#if defined (_WIN32)
254
    if (data->fd >= 0)
255
        _close (data->fd);
256
257
    data->fd = -1;
258
259
#elif defined (LOG4CPLUS_USE_POSIX_LOCKING)
260
0
    if (data->fd >= 0)
261
0
        ::close (data->fd);
262
263
0
    data->fd = -1;
264
265
0
#endif
266
0
}
267
268
269
void
270
LockFile::lock () const
271
0
{
272
0
    LogLog & loglog = getLogLog ();
273
0
    int ret = 0;
274
0
    (void) loglog;
275
0
    (void) ret;
276
277
#if defined (LOG4CPLUS_USE_WIN32_LOCKFILEEX)
278
    HANDLE fh = get_os_HANDLE (data->fd);
279
280
    OVERLAPPED overlapped;
281
    std::memset (&overlapped, 0, sizeof (overlapped));
282
    overlapped.hEvent = 0;
283
284
    ret = LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0,
285
        (std::numeric_limits<DWORD>::max) (),
286
        (std::numeric_limits<DWORD>::max) (), &overlapped);
287
    if (! ret)
288
        getLogLog ().error (tstring (LOG4CPLUS_TEXT ("LockFileEx() failed: "))
289
            + convertIntegerToString (GetLastError ()), true);
290
291
#elif defined (LOG4CPLUS_USE_O_EXLOCK)
292
    open (OPEN_FLAGS | O_EXLOCK);
293
294
#elif defined (LOG4CPLUS_USE_SETLKW)
295
    do
296
0
    {
297
0
        struct flock fl;
298
0
        fl.l_type = F_WRLCK;
299
0
        fl.l_whence = SEEK_SET;
300
0
        fl.l_start = 0;
301
0
        fl.l_len = 0;
302
0
        ret = fcntl (data->fd, F_SETLKW, &fl);
303
0
        if (ret == -1 && errno != EINTR)
304
0
            getLogLog ().error (tstring (LOG4CPLUS_TEXT("fcntl(F_SETLKW) failed: "))
305
0
                + convertIntegerToString (errno), true);
306
0
    }
307
0
    while (ret == -1);
308
309
#elif defined (LOG4CPLUS_USE_LOCKF)
310
    do
311
    {
312
        ret = lockf (data->fd, F_LOCK, 0);
313
        if (ret == -1 && errno != EINTR)
314
            getLogLog ().error (tstring (LOG4CPLUS_TEXT("lockf() failed: "))
315
                + convertIntegerToString (errno), true);
316
    }
317
    while (ret == -1);
318
319
#elif defined (LOG4CPLUS_USE_FLOCK)
320
    do
321
    {
322
        ret = flock (data->fd, LOCK_EX);
323
        if (ret == -1 && errno != EINTR)
324
            getLogLog ().error (tstring (LOG4CPLUS_TEXT("flock() failed: "))
325
                + convertIntegerToString (errno), true);
326
    }
327
    while (ret == -1);
328
329
#endif
330
0
}
331
332
333
void LockFile::unlock () const
334
0
{
335
0
    int ret = 0;
336
337
#if defined (LOG4CPLUS_USE_WIN32_LOCKFILEEX)
338
    HANDLE fh = get_os_HANDLE (data->fd);
339
340
    ret = UnlockFile(fh, 0, 0, (std::numeric_limits<DWORD>::max) (),
341
        (std::numeric_limits<DWORD>::max) ());
342
    if (! ret)
343
        getLogLog ().error (tstring (LOG4CPLUS_TEXT ("UnlockFile() failed: "))
344
            + convertIntegerToString (GetLastError ()), true);
345
346
#elif defined (LOG4CPLUS_USE_O_EXLOCK)
347
    close ();
348
349
#elif defined (LOG4CPLUS_USE_SETLKW)
350
    struct flock fl;
351
0
    fl.l_type = F_UNLCK;
352
0
    fl.l_whence = SEEK_SET;
353
0
    fl.l_start = 0;
354
0
    fl.l_len = 0;
355
0
    ret = fcntl (data->fd, F_SETLKW, &fl);
356
0
    if (ret != 0)
357
0
        getLogLog ().error (tstring (LOG4CPLUS_TEXT("fcntl(F_SETLKW) failed: "))
358
0
            + convertIntegerToString (errno), true);
359
360
#elif defined (LOG4CPLUS_USE_LOCKF)
361
    ret = lockf (data->fd, F_ULOCK, 0);
362
    if (ret != 0)
363
        getLogLog ().error (tstring (LOG4CPLUS_TEXT("lockf() failed: "))
364
            + convertIntegerToString (errno), true);
365
366
#elif defined (LOG4CPLUS_USE_FLOCK)
367
    ret = flock (data->fd, LOCK_UN);
368
    if (ret != 0)
369
        getLogLog ().error (tstring (LOG4CPLUS_TEXT("flock() failed: "))
370
            + convertIntegerToString (errno), true);
371
372
#endif
373
374
0
}
375
376
377
378
} } // namespace log4cplus { namespace helpers {