reactos/sdk/lib/ucrt/lowio/locking.cpp
2025-01-16 14:18:53 +02:00

121 lines
3.6 KiB
C++

//
// locking.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Defines _locking(), which locks and unlocks regions of a file.
//
#include <corecrt_internal_lowio.h>
#include <sys\locking.h>
static int __cdecl locking_nolock(int const fh, int const locking_mode, long const number_of_bytes) throw()
{
__int64 const lock_offset = _lseeki64_nolock(fh, 0L, SEEK_CUR);
if (lock_offset == -1)
return -1;
OVERLAPPED overlapped = { 0 };
overlapped.Offset = static_cast<DWORD>(lock_offset);
overlapped.OffsetHigh = static_cast<DWORD>((lock_offset >> 32) & 0xffffffff);
// Set the retry count, based on the mode:
bool const allow_retry = locking_mode == _LK_LOCK || locking_mode == _LK_RLCK;
int const retry_count = allow_retry ? 10 : 1;
// Ask the OS to lock the file either until the request succeeds or the
// retry count is reached, whichever comes first. Note that the only error
// possible is a locking violation, since an invalid handle would have
// already failed above.
bool succeeded = false;
for (int i = 0; i != retry_count; ++i)
{
if (locking_mode == _LK_UNLCK)
{
succeeded = UnlockFileEx(
reinterpret_cast<HANDLE>(_get_osfhandle(fh)),
0,
number_of_bytes,
0,
&overlapped) == TRUE;
}
else
{
// Ensure exclusive lock access, and return immediately if lock
// acquisition fails:
succeeded = LockFileEx(
reinterpret_cast<HANDLE>(_get_osfhandle(fh)),
LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY,
0,
number_of_bytes,
0,
&overlapped) == TRUE;
}
if (succeeded)
{
break;
}
// Doesnt sleep on the last try
if (i != retry_count - 1)
{
Sleep(1000);
}
}
// If an OS error occurred (e.g., if the file was already locked), return
// EDEADLOCK if this was ablocking call; otherwise map the error noramlly:
if (!succeeded)
{
__acrt_errno_map_os_error(GetLastError());
if (locking_mode == _LK_LOCK || locking_mode == _LK_RLCK)
{
errno = EDEADLOCK;
}
return -1;
}
return 0;
}
// Locks or unlocks the requested number of bytes in the specified file.
//
// Note that this function acquires the lock for the specified file and holds
// this lock for the entire duration of the call, even during the one second
// delays between calls into the operating system. This is to prevent other
// threads from changing the file during the call.
//
// Returns 0 on success; returns -1 and sets errno on failure.
extern "C" int __cdecl _locking(int const fh, int const locking_mode, long const number_of_bytes)
{
_CHECK_FH_CLEAR_OSSERR_RETURN(fh, EBADF, -1);
_VALIDATE_CLEAR_OSSERR_RETURN(fh >= 0 && (unsigned)fh < (unsigned)_nhandle, EBADF, -1);
_VALIDATE_CLEAR_OSSERR_RETURN(_osfile(fh) & FOPEN, EBADF, -1);
_VALIDATE_CLEAR_OSSERR_RETURN(number_of_bytes >= 0, EINVAL, -1);
__acrt_lowio_lock_fh(fh);
int result = -1;
__try
{
if ((_osfile(fh) & FOPEN) == 0)
{
errno = EBADF;
_doserrno = 0;
_ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0));
__leave;
}
result = locking_nolock(fh, locking_mode, number_of_bytes);
}
__finally
{
__acrt_lowio_unlock_fh(fh);
}
__endtry
return result;
}