Reactos
at master 121 lines 3.7 kB view raw
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}