Reactos
1//
2// locking.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// Defines _locking(), which locks and unlocks regions of a file.
7//
8#include <corecrt_internal_lowio.h>
9#include <sys/locking.h>
10
11
12
13static int __cdecl locking_nolock(int const fh, int const locking_mode, long const number_of_bytes) throw()
14{
15 __int64 const lock_offset = _lseeki64_nolock(fh, 0L, SEEK_CUR);
16 if (lock_offset == -1)
17 return -1;
18
19 OVERLAPPED overlapped = { 0 };
20 overlapped.Offset = static_cast<DWORD>(lock_offset);
21 overlapped.OffsetHigh = static_cast<DWORD>((lock_offset >> 32) & 0xffffffff);
22
23 // Set the retry count, based on the mode:
24 bool const allow_retry = locking_mode == _LK_LOCK || locking_mode == _LK_RLCK;
25 int const retry_count = allow_retry ? 10 : 1;
26
27 // Ask the OS to lock the file either until the request succeeds or the
28 // retry count is reached, whichever comes first. Note that the only error
29 // possible is a locking violation, since an invalid handle would have
30 // already failed above.
31 bool succeeded = false;
32 for (int i = 0; i != retry_count; ++i)
33 {
34 if (locking_mode == _LK_UNLCK)
35 {
36 succeeded = UnlockFileEx(
37 reinterpret_cast<HANDLE>(_get_osfhandle(fh)),
38 0,
39 number_of_bytes,
40 0,
41 &overlapped) == TRUE;
42 }
43 else
44 {
45 // Ensure exclusive lock access, and return immediately if lock
46 // acquisition fails:
47 succeeded = LockFileEx(
48 reinterpret_cast<HANDLE>(_get_osfhandle(fh)),
49 LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY,
50 0,
51 number_of_bytes,
52 0,
53 &overlapped) == TRUE;
54 }
55
56 if (succeeded)
57 {
58 break;
59 }
60
61 // Doesnt sleep on the last try
62 if (i != retry_count - 1)
63 {
64 Sleep(1000);
65 }
66 }
67
68 // If an OS error occurred (e.g., if the file was already locked), return
69 // EDEADLOCK if this was ablocking call; otherwise map the error noramlly:
70 if (!succeeded)
71 {
72 __acrt_errno_map_os_error(GetLastError());
73 if (locking_mode == _LK_LOCK || locking_mode == _LK_RLCK)
74 {
75 errno = EDEADLOCK;
76 }
77
78 return -1;
79 }
80
81 return 0;
82}
83
84
85
86// Locks or unlocks the requested number of bytes in the specified file.
87//
88// Note that this function acquires the lock for the specified file and holds
89// this lock for the entire duration of the call, even during the one second
90// delays between calls into the operating system. This is to prevent other
91// threads from changing the file during the call.
92//
93// Returns 0 on success; returns -1 and sets errno on failure.
94extern "C" int __cdecl _locking(int const fh, int const locking_mode, long const number_of_bytes)
95{
96 _CHECK_FH_CLEAR_OSSERR_RETURN(fh, EBADF, -1);
97 _VALIDATE_CLEAR_OSSERR_RETURN(fh >= 0 && (unsigned)fh < (unsigned)_nhandle, EBADF, -1);
98 _VALIDATE_CLEAR_OSSERR_RETURN(_osfile(fh) & FOPEN, EBADF, -1);
99 _VALIDATE_CLEAR_OSSERR_RETURN(number_of_bytes >= 0, EINVAL, -1);
100
101 __acrt_lowio_lock_fh(fh);
102 int result = -1;
103 __try
104 {
105 if ((_osfile(fh) & FOPEN) == 0)
106 {
107 errno = EBADF;
108 _doserrno = 0;
109 _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0));
110 __leave;
111 }
112
113 result = locking_nolock(fh, locking_mode, number_of_bytes);
114 }
115 __finally
116 {
117 __acrt_lowio_unlock_fh(fh);
118 }
119 __endtry
120 return result;
121}