1 /* Emulate flock on platforms that lack it, primarily Windows and MinGW.
3 This is derived from sqlite3 sources.
4 https://www.sqlite.org/src/finfo?name=src/os_win.c
5 https://www.sqlite.org/copyright.html
7 Written by Richard W.M. Jones <rjones.at.redhat.com>
9 Copyright (C) 2008-2019 Free Software Foundation, Inc.
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public
13 License as published by the Free Software Foundation; either
14 version 3 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <https://www.gnu.org/licenses/>. */
27 #if defined _WIN32 && ! defined __CYGWIN__
30 # define WIN32_LEAN_AND_MEAN
36 # if GNULIB_MSVC_NOTHROW
37 # include "msvc-nothrow.h"
42 /* Determine the current size of a file. Because the other braindead
43 * APIs we'll call need lower/upper 32 bit pairs, keep the file size
47 file_size (HANDLE h
, DWORD
* lower
, DWORD
* upper
)
49 *lower
= GetFileSize (h
, upper
);
53 /* LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. */
54 # ifndef LOCKFILE_FAIL_IMMEDIATELY
55 # define LOCKFILE_FAIL_IMMEDIATELY 1
60 do_lock (HANDLE h
, int non_blocking
, int exclusive
)
63 DWORD size_lower
, size_upper
;
67 /* We're going to lock the whole file, so get the file size. */
68 res
= file_size (h
, &size_lower
, &size_upper
);
72 /* Start offset is 0, and also zero the remaining members of this struct. */
73 memset (&ovlp
, 0, sizeof ovlp
);
76 flags
|= LOCKFILE_FAIL_IMMEDIATELY
;
78 flags
|= LOCKFILE_EXCLUSIVE_LOCK
;
80 return LockFileEx (h
, flags
, 0, size_lower
, size_upper
, &ovlp
);
83 /* Unlock reader or exclusive lock. */
88 DWORD size_lower
, size_upper
;
90 res
= file_size (h
, &size_lower
, &size_upper
);
94 return UnlockFile (h
, 0, 0, size_lower
, size_upper
);
97 /* Now our BSD-like flock operation. */
99 flock (int fd
, int operation
)
101 HANDLE h
= (HANDLE
) _get_osfhandle (fd
);
105 if (h
== INVALID_HANDLE_VALUE
)
111 non_blocking
= operation
& LOCK_NB
;
112 operation
&= ~LOCK_NB
;
117 res
= do_lock (h
, non_blocking
, 0);
120 res
= do_lock (h
, non_blocking
, 1);
130 /* Map Windows errors into Unix errnos. As usual MSDN fails to
131 * document the permissible error codes.
135 DWORD err
= GetLastError ();
138 /* This means someone else is holding a lock. */
139 case ERROR_LOCK_VIOLATION
:
144 case ERROR_NOT_ENOUGH_MEMORY
:
148 case ERROR_BAD_COMMAND
:
152 /* Unlikely to be other errors, but at least don't lose the
167 # ifdef HAVE_STRUCT_FLOCK_L_TYPE
168 /* We know how to implement flock in terms of fcntl. */
172 # ifdef HAVE_UNISTD_H
180 flock (int fd
, int operation
)
185 if (operation
& LOCK_NB
)
189 operation
&= ~LOCK_NB
;
191 memset (&fl
, 0, sizeof fl
);
192 fl
.l_whence
= SEEK_SET
;
193 /* l_start & l_len are 0, which as a special case means "whole file". */
211 r
= fcntl (fd
, cmd
, &fl
);
212 if (r
== -1 && errno
== EACCES
)
218 # else /* !HAVE_STRUCT_FLOCK_L_TYPE */
220 # error "This platform lacks flock function, and Gnulib doesn't provide a replacement. This is a bug in Gnulib."
222 # endif /* !HAVE_STRUCT_FLOCK_L_TYPE */
224 #endif /* !Windows */