Use Gnulib's `isnan' and `isinf' modules.
[bpt/guile.git] / lib / flock.c
1 /* Emulate flock on platforms that lack it, primarily Windows and MinGW.
2
3 This is derived from sqlite3 sources.
4 http://www.sqlite.org/cvstrac/rlog?f=sqlite/src/os_win.c
5 http://www.sqlite.org/copyright.html
6
7 Written by Richard W.M. Jones <rjones.at.redhat.com>
8
9 Copyright (C) 2008-2010 Free Software Foundation, Inc.
10
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 2.1 of the License, or (at your option) any later version.
15
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 Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>. */
23
24 #include <config.h>
25 #include <sys/file.h>
26
27 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
28
29 /* _get_osfhandle */
30 #include <io.h>
31
32 /* LockFileEx */
33 #define WIN32_LEAN_AND_MEAN
34 #include <windows.h>
35
36 #include <errno.h>
37
38 /* Determine the current size of a file. Because the other braindead
39 * APIs we'll call need lower/upper 32 bit pairs, keep the file size
40 * like that too.
41 */
42 static BOOL
43 file_size (HANDLE h, DWORD * lower, DWORD * upper)
44 {
45 *lower = GetFileSize (h, upper);
46 return 1;
47 }
48
49 /* LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. */
50 #ifndef LOCKFILE_FAIL_IMMEDIATELY
51 # define LOCKFILE_FAIL_IMMEDIATELY 1
52 #endif
53
54 /* Acquire a lock. */
55 static BOOL
56 do_lock (HANDLE h, int non_blocking, int exclusive)
57 {
58 BOOL res;
59 DWORD size_lower, size_upper;
60 OVERLAPPED ovlp;
61 int flags = 0;
62
63 /* We're going to lock the whole file, so get the file size. */
64 res = file_size (h, &size_lower, &size_upper);
65 if (!res)
66 return 0;
67
68 /* Start offset is 0, and also zero the remaining members of this struct. */
69 memset (&ovlp, 0, sizeof ovlp);
70
71 if (non_blocking)
72 flags |= LOCKFILE_FAIL_IMMEDIATELY;
73 if (exclusive)
74 flags |= LOCKFILE_EXCLUSIVE_LOCK;
75
76 return LockFileEx (h, flags, 0, size_lower, size_upper, &ovlp);
77 }
78
79 /* Unlock reader or exclusive lock. */
80 static BOOL
81 do_unlock (HANDLE h)
82 {
83 int res;
84 DWORD size_lower, size_upper;
85
86 res = file_size (h, &size_lower, &size_upper);
87 if (!res)
88 return 0;
89
90 return UnlockFile (h, 0, 0, size_lower, size_upper);
91 }
92
93 /* Now our BSD-like flock operation. */
94 int
95 flock (int fd, int operation)
96 {
97 HANDLE h = (HANDLE) _get_osfhandle (fd);
98 DWORD res;
99 int non_blocking;
100
101 if (h == INVALID_HANDLE_VALUE)
102 {
103 errno = EBADF;
104 return -1;
105 }
106
107 non_blocking = operation & LOCK_NB;
108 operation &= ~LOCK_NB;
109
110 switch (operation)
111 {
112 case LOCK_SH:
113 res = do_lock (h, non_blocking, 0);
114 break;
115 case LOCK_EX:
116 res = do_lock (h, non_blocking, 1);
117 break;
118 case LOCK_UN:
119 res = do_unlock (h);
120 break;
121 default:
122 errno = EINVAL;
123 return -1;
124 }
125
126 /* Map Windows errors into Unix errnos. As usual MSDN fails to
127 * document the permissible error codes.
128 */
129 if (!res)
130 {
131 DWORD err = GetLastError ();
132 switch (err)
133 {
134 /* This means someone else is holding a lock. */
135 case ERROR_LOCK_VIOLATION:
136 errno = EAGAIN;
137 break;
138
139 /* Out of memory. */
140 case ERROR_NOT_ENOUGH_MEMORY:
141 errno = ENOMEM;
142 break;
143
144 case ERROR_BAD_COMMAND:
145 errno = EINVAL;
146 break;
147
148 /* Unlikely to be other errors, but at least don't lose the
149 * error code.
150 */
151 default:
152 errno = err;
153 }
154
155 return -1;
156 }
157
158 return 0;
159 }
160
161 #else /* !Windows */
162
163 #ifdef HAVE_STRUCT_FLOCK_L_TYPE
164 /* We know how to implement flock in terms of fcntl. */
165
166 #ifdef HAVE_FCNTL_H
167 #include <fcntl.h>
168 #endif
169
170 #ifdef HAVE_UNISTD_H
171 #include <unistd.h>
172 #endif
173
174 #include <errno.h>
175 #include <string.h>
176
177 int
178 flock (int fd, int operation)
179 {
180 int cmd, r;
181 struct flock fl;
182
183 if (operation & LOCK_NB)
184 cmd = F_SETLK;
185 else
186 cmd = F_SETLKW;
187 operation &= ~LOCK_NB;
188
189 memset (&fl, 0, sizeof fl);
190 fl.l_whence = SEEK_SET;
191 /* l_start & l_len are 0, which as a special case means "whole file". */
192
193 switch (operation)
194 {
195 case LOCK_SH:
196 fl.l_type = F_RDLCK;
197 break;
198 case LOCK_EX:
199 fl.l_type = F_WRLCK;
200 break;
201 case LOCK_UN:
202 fl.l_type = F_UNLCK;
203 break;
204 default:
205 errno = EINVAL;
206 return -1;
207 }
208
209 r = fcntl (fd, cmd, &fl);
210 if (r == -1 && errno == EACCES)
211 errno = EAGAIN;
212
213 return r;
214 }
215
216 #else /* !HAVE_STRUCT_FLOCK_L_TYPE */
217
218 #error "This platform lacks flock function, and Gnulib doesn't provide a replacement. This is a bug in Gnulib."
219
220 #endif /* !HAVE_STRUCT_FLOCK_L_TYPE */
221
222 #endif /* !Windows */