update devspec.en_US/1.0.general.md.
[devspec.git] / devspec.en_US / project / recutils / lib / flock.c
blobd804e571369d4c0d7c63c2e2c1874aa4ad11ee7f
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/>. */
24 #include <config.h>
25 #include <sys/file.h>
27 #if defined _WIN32 && ! defined __CYGWIN__
29 /* LockFileEx */
30 # define WIN32_LEAN_AND_MEAN
31 # include <windows.h>
33 # include <errno.h>
35 /* _get_osfhandle */
36 # if GNULIB_MSVC_NOTHROW
37 # include "msvc-nothrow.h"
38 # else
39 # include <io.h>
40 # endif
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
44 * like that too.
46 static BOOL
47 file_size (HANDLE h, DWORD * lower, DWORD * upper)
49 *lower = GetFileSize (h, upper);
50 return 1;
53 /* LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. */
54 # ifndef LOCKFILE_FAIL_IMMEDIATELY
55 # define LOCKFILE_FAIL_IMMEDIATELY 1
56 # endif
58 /* Acquire a lock. */
59 static BOOL
60 do_lock (HANDLE h, int non_blocking, int exclusive)
62 BOOL res;
63 DWORD size_lower, size_upper;
64 OVERLAPPED ovlp;
65 int flags = 0;
67 /* We're going to lock the whole file, so get the file size. */
68 res = file_size (h, &size_lower, &size_upper);
69 if (!res)
70 return 0;
72 /* Start offset is 0, and also zero the remaining members of this struct. */
73 memset (&ovlp, 0, sizeof ovlp);
75 if (non_blocking)
76 flags |= LOCKFILE_FAIL_IMMEDIATELY;
77 if (exclusive)
78 flags |= LOCKFILE_EXCLUSIVE_LOCK;
80 return LockFileEx (h, flags, 0, size_lower, size_upper, &ovlp);
83 /* Unlock reader or exclusive lock. */
84 static BOOL
85 do_unlock (HANDLE h)
87 int res;
88 DWORD size_lower, size_upper;
90 res = file_size (h, &size_lower, &size_upper);
91 if (!res)
92 return 0;
94 return UnlockFile (h, 0, 0, size_lower, size_upper);
97 /* Now our BSD-like flock operation. */
98 int
99 flock (int fd, int operation)
101 HANDLE h = (HANDLE) _get_osfhandle (fd);
102 DWORD res;
103 int non_blocking;
105 if (h == INVALID_HANDLE_VALUE)
107 errno = EBADF;
108 return -1;
111 non_blocking = operation & LOCK_NB;
112 operation &= ~LOCK_NB;
114 switch (operation)
116 case LOCK_SH:
117 res = do_lock (h, non_blocking, 0);
118 break;
119 case LOCK_EX:
120 res = do_lock (h, non_blocking, 1);
121 break;
122 case LOCK_UN:
123 res = do_unlock (h);
124 break;
125 default:
126 errno = EINVAL;
127 return -1;
130 /* Map Windows errors into Unix errnos. As usual MSDN fails to
131 * document the permissible error codes.
133 if (!res)
135 DWORD err = GetLastError ();
136 switch (err)
138 /* This means someone else is holding a lock. */
139 case ERROR_LOCK_VIOLATION:
140 errno = EAGAIN;
141 break;
143 /* Out of memory. */
144 case ERROR_NOT_ENOUGH_MEMORY:
145 errno = ENOMEM;
146 break;
148 case ERROR_BAD_COMMAND:
149 errno = EINVAL;
150 break;
152 /* Unlikely to be other errors, but at least don't lose the
153 * error code.
155 default:
156 errno = err;
159 return -1;
162 return 0;
165 #else /* !Windows */
167 # ifdef HAVE_STRUCT_FLOCK_L_TYPE
168 /* We know how to implement flock in terms of fcntl. */
170 # include <fcntl.h>
172 # ifdef HAVE_UNISTD_H
173 # include <unistd.h>
174 # endif
176 # include <errno.h>
177 # include <string.h>
180 flock (int fd, int operation)
182 int cmd, r;
183 struct flock fl;
185 if (operation & LOCK_NB)
186 cmd = F_SETLK;
187 else
188 cmd = F_SETLKW;
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". */
195 switch (operation)
197 case LOCK_SH:
198 fl.l_type = F_RDLCK;
199 break;
200 case LOCK_EX:
201 fl.l_type = F_WRLCK;
202 break;
203 case LOCK_UN:
204 fl.l_type = F_UNLCK;
205 break;
206 default:
207 errno = EINVAL;
208 return -1;
211 r = fcntl (fd, cmd, &fl);
212 if (r == -1 && errno == EACCES)
213 errno = EAGAIN;
215 return r;
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 */