123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- /* Emulate flock on platforms that lack it, primarily Windows and MinGW.
- This is derived from sqlite3 sources.
- https://www.sqlite.org/src/finfo?name=src/os_win.c
- https://www.sqlite.org/copyright.html
- Written by Richard W.M. Jones <rjones.at.redhat.com>
- Copyright (C) 2008-2023 Free Software Foundation, Inc.
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>. */
- #include <config.h>
- #include <sys/file.h>
- #if defined _WIN32 && ! defined __CYGWIN__
- /* LockFileEx */
- # define WIN32_LEAN_AND_MEAN
- # include <windows.h>
- # include <errno.h>
- /* _get_osfhandle */
- # if GNULIB_MSVC_NOTHROW
- # include "msvc-nothrow.h"
- # else
- # include <io.h>
- # endif
- /* Determine the current size of a file. Because the other braindead
- * APIs we'll call need lower/upper 32 bit pairs, keep the file size
- * like that too.
- */
- static BOOL
- file_size (HANDLE h, DWORD * lower, DWORD * upper)
- {
- *lower = GetFileSize (h, upper);
- return 1;
- }
- /* LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. */
- # ifndef LOCKFILE_FAIL_IMMEDIATELY
- # define LOCKFILE_FAIL_IMMEDIATELY 1
- # endif
- /* Acquire a lock. */
- static BOOL
- do_lock (HANDLE h, int non_blocking, int exclusive)
- {
- BOOL res;
- DWORD size_lower, size_upper;
- OVERLAPPED ovlp;
- int flags = 0;
- /* We're going to lock the whole file, so get the file size. */
- res = file_size (h, &size_lower, &size_upper);
- if (!res)
- return 0;
- /* Start offset is 0, and also zero the remaining members of this struct. */
- memset (&ovlp, 0, sizeof ovlp);
- if (non_blocking)
- flags |= LOCKFILE_FAIL_IMMEDIATELY;
- if (exclusive)
- flags |= LOCKFILE_EXCLUSIVE_LOCK;
- return LockFileEx (h, flags, 0, size_lower, size_upper, &ovlp);
- }
- /* Unlock reader or exclusive lock. */
- static BOOL
- do_unlock (HANDLE h)
- {
- int res;
- DWORD size_lower, size_upper;
- res = file_size (h, &size_lower, &size_upper);
- if (!res)
- return 0;
- return UnlockFile (h, 0, 0, size_lower, size_upper);
- }
- /* Now our BSD-like flock operation. */
- int
- flock (int fd, int operation)
- {
- HANDLE h = (HANDLE) _get_osfhandle (fd);
- DWORD res;
- int non_blocking;
- if (h == INVALID_HANDLE_VALUE)
- {
- errno = EBADF;
- return -1;
- }
- non_blocking = operation & LOCK_NB;
- operation &= ~LOCK_NB;
- switch (operation)
- {
- case LOCK_SH:
- res = do_lock (h, non_blocking, 0);
- break;
- case LOCK_EX:
- res = do_lock (h, non_blocking, 1);
- break;
- case LOCK_UN:
- res = do_unlock (h);
- break;
- default:
- errno = EINVAL;
- return -1;
- }
- /* Map Windows errors into Unix errnos. As usual MSDN fails to
- * document the permissible error codes.
- */
- if (!res)
- {
- DWORD err = GetLastError ();
- switch (err)
- {
- /* This means someone else is holding a lock. */
- case ERROR_LOCK_VIOLATION:
- errno = EAGAIN;
- break;
- /* Out of memory. */
- case ERROR_NOT_ENOUGH_MEMORY:
- errno = ENOMEM;
- break;
- case ERROR_BAD_COMMAND:
- errno = EINVAL;
- break;
- /* Unlikely to be other errors, but at least don't lose the
- * error code.
- */
- default:
- errno = err;
- }
- return -1;
- }
- return 0;
- }
- #else /* !Windows */
- # ifdef HAVE_STRUCT_FLOCK_L_TYPE
- /* We know how to implement flock in terms of fcntl. */
- # include <fcntl.h>
- # ifdef HAVE_UNISTD_H
- # include <unistd.h>
- # endif
- # include <errno.h>
- # include <string.h>
- int
- flock (int fd, int operation)
- {
- int cmd, r;
- struct flock fl;
- if (operation & LOCK_NB)
- cmd = F_SETLK;
- else
- cmd = F_SETLKW;
- operation &= ~LOCK_NB;
- memset (&fl, 0, sizeof fl);
- fl.l_whence = SEEK_SET;
- /* l_start & l_len are 0, which as a special case means "whole file". */
- switch (operation)
- {
- case LOCK_SH:
- fl.l_type = F_RDLCK;
- break;
- case LOCK_EX:
- fl.l_type = F_WRLCK;
- break;
- case LOCK_UN:
- fl.l_type = F_UNLCK;
- break;
- default:
- errno = EINVAL;
- return -1;
- }
- r = fcntl (fd, cmd, &fl);
- if (r == -1 && errno == EACCES)
- errno = EAGAIN;
- return r;
- }
- # else /* !HAVE_STRUCT_FLOCK_L_TYPE */
- # error "This platform lacks flock function, and Gnulib doesn't provide a replacement. This is a bug in Gnulib."
- # endif /* !HAVE_STRUCT_FLOCK_L_TYPE */
- #endif /* !Windows */
|