]>
Commit | Line | Data |
---|---|---|
a998dd70 | 1 | /* flock.cc. NT specific implementation of advisory file locking. |
f3a1e23e | 2 | |
86bf572e | 3 | Copyright 2003, 2008, 2009, 2010, 2011 Red Hat, Inc. |
f3a1e23e CV |
4 | |
5 | This file is part of Cygwin. | |
6 | ||
7 | This software is a copyrighted work licensed under the terms of the | |
8 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
9 | details. */ | |
10 | ||
a998dd70 CV |
11 | /* The basic mechanism as well as the datastructures used in the below |
12 | implementation are taken from the FreeBSD repository on 2008-03-18. | |
13 | The essential code of the lf_XXX functions has been taken from the | |
14 | module src/sys/kern/kern_lockf.c. It has been adapted to use NT | |
15 | global namespace subdirs and event objects for synchronization | |
025c1fac CF |
16 | purposes. |
17 | ||
a998dd70 CV |
18 | So, the following copyright applies to most of the code in the lf_XXX |
19 | functions. | |
20 | ||
21 | * Copyright (c) 1982, 1986, 1989, 1993 | |
22 | * The Regents of the University of California. All rights reserved. | |
23 | * | |
24 | * This code is derived from software contributed to Berkeley by | |
25 | * Scooter Morris at Genentech Inc. | |
26 | * | |
27 | * Redistribution and use in source and binary forms, with or without | |
28 | * modification, are permitted provided that the following conditions | |
29 | * are met: | |
30 | * 1. Redistributions of source code must retain the above copyright | |
31 | * notice, this list of conditions and the following disclaimer. | |
32 | * 2. Redistributions in binary form must reproduce the above copyright | |
33 | * notice, this list of conditions and the following disclaimer in the | |
34 | * documentation and/or other materials provided with the distribution. | |
35 | * 4. Neither the name of the University nor the names of its contributors | |
36 | * may be used to endorse or promote products derived from this software | |
37 | * without specific prior written permission. | |
38 | * | |
39 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
40 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
42 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
43 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
44 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
45 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
47 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
48 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
49 | * SUCH DAMAGE. | |
50 | * | |
51 | * @(#)ufs_lockf.c 8.3 (Berkeley) 1/6/94 | |
025c1fac | 52 | */ |
a998dd70 CV |
53 | |
54 | /* | |
55 | * The flock() function is based upon source taken from the Red Hat | |
56 | * implementation used in their imap-2002d SRPM. | |
57 | * | |
58 | * $RH: flock.c,v 1.2 2000/08/23 17:07:00 nalin Exp $ | |
59 | */ | |
60 | ||
fabfb1a1 | 61 | /* The lockf function is based upon FreeBSD sources with the following |
a998dd70 | 62 | * copyright. |
8c0b8bc3 CV |
63 | */ |
64 | /* | |
a998dd70 CV |
65 | * Copyright (c) 1997 The NetBSD Foundation, Inc. |
66 | * All rights reserved. | |
67 | * | |
68 | * This code is derived from software contributed to The NetBSD Foundation | |
69 | * by Klaus Klein. | |
70 | * | |
71 | * Redistribution and use in source and binary forms, with or without | |
72 | * modification, are permitted provided that the following conditions | |
73 | * are met: | |
74 | * 1. Redistributions of source code must retain the above copyright | |
75 | * notice, this list of conditions and the following disclaimer. | |
76 | * 2. Redistributions in binary form must reproduce the above copyright | |
77 | * notice, this list of conditions and the following disclaimer in the | |
78 | * documentation and/or other materials provided with the distribution. | |
a998dd70 CV |
79 | * |
80 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
81 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
82 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
83 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
84 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
85 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
86 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
87 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
88 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
89 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
90 | * POSSIBILITY OF SUCH DAMAGE. | |
8c0b8bc3 | 91 | */ |
a998dd70 | 92 | |
e2a39e2e | 93 | #include "winsup.h" |
a998dd70 | 94 | #include <assert.h> |
f3a1e23e | 95 | #include <sys/file.h> |
f3a1e23e | 96 | #include <unistd.h> |
a998dd70 CV |
97 | #include <stdlib.h> |
98 | #include "cygerrno.h" | |
a998dd70 | 99 | #include "security.h" |
db5ae618 | 100 | #include "shared_info.h" |
a998dd70 CV |
101 | #include "path.h" |
102 | #include "fhandler.h" | |
103 | #include "dtable.h" | |
104 | #include "cygheap.h" | |
a998dd70 CV |
105 | #include "pinfo.h" |
106 | #include "sigproc.h" | |
107 | #include "cygtls.h" | |
30bbc55e | 108 | #include "tls_pbuf.h" |
a998dd70 CV |
109 | #include "ntdll.h" |
110 | #include <sys/queue.h> | |
111 | #include <wchar.h> | |
112 | ||
a998dd70 CV |
113 | #define F_WAIT 0x10 /* Wait until lock is granted */ |
114 | #define F_FLOCK 0x20 /* Use flock(2) semantics for lock */ | |
115 | #define F_POSIX 0x40 /* Use POSIX semantics for lock */ | |
116 | ||
117 | #ifndef OFF_MAX | |
118 | #define OFF_MAX LLONG_MAX | |
119 | #endif | |
120 | ||
121 | static NO_COPY muto lockf_guard; | |
122 | ||
123 | #define INODE_LIST_LOCK() (lockf_guard.init ("lockf_guard")->acquire ()) | |
124 | #define INODE_LIST_UNLOCK() (lockf_guard.release ()) | |
125 | ||
636c94d8 | 126 | #define LOCK_OBJ_NAME_LEN 64 |
a998dd70 | 127 | |
db5ae618 CV |
128 | #define FLOCK_INODE_DIR_ACCESS (DIRECTORY_QUERY \ |
129 | | DIRECTORY_TRAVERSE \ | |
130 | | DIRECTORY_CREATE_OBJECT \ | |
131 | | READ_CONTROL) | |
132 | ||
db5ae618 CV |
133 | #define FLOCK_EVENT_ACCESS (EVENT_QUERY_STATE \ |
134 | | SYNCHRONIZE \ | |
135 | | READ_CONTROL) | |
136 | ||
a998dd70 | 137 | /* This function takes the own process security descriptor DACL and adds |
b9e2579c CV |
138 | SYNCHRONIZE permissions for everyone. This allows all processes |
139 | to wait for this process to die when blocking in a F_SETLKW on a lock | |
140 | which is hold by this process. */ | |
a998dd70 CV |
141 | static void |
142 | allow_others_to_sync () | |
143 | { | |
144 | static NO_COPY bool done; | |
145 | ||
146 | if (done) | |
147 | return; | |
148 | ||
149 | NTSTATUS status; | |
150 | PACL dacl; | |
151 | LPVOID ace; | |
152 | ULONG len; | |
153 | ||
30bbc55e CV |
154 | /* Get this process DACL. We use a rather small stack buffer here which |
155 | should be more than sufficient for process ACLs. Can't use tls functions | |
156 | at this point because this gets called during initialization when the tls | |
157 | is not really available. */ | |
4e8f539f CV |
158 | #define MAX_PROCESS_SD_SIZE 3072 |
159 | PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR) alloca (MAX_PROCESS_SD_SIZE); | |
f16706de CV |
160 | status = NtQuerySecurityObject (NtCurrentProcess (), |
161 | DACL_SECURITY_INFORMATION, sd, | |
4e8f539f | 162 | MAX_PROCESS_SD_SIZE, &len); |
a998dd70 CV |
163 | if (!NT_SUCCESS (status)) |
164 | { | |
165 | debug_printf ("NtQuerySecurityObject: %p", status); | |
166 | return; | |
167 | } | |
30bbc55e | 168 | /* Create a valid dacl pointer and set its size to be as big as |
a998dd70 CV |
169 | there's room in the temporary buffer. Note that the descriptor |
170 | is in self-relative format. */ | |
171 | dacl = (PACL) ((char *) sd + (uintptr_t) sd->Dacl); | |
172 | dacl->AclSize = NT_MAX_PATH * sizeof (WCHAR) - ((char *) dacl - (char *) sd); | |
173 | /* Allow everyone to SYNCHRONIZE with this process. */ | |
174 | if (!AddAccessAllowedAce (dacl, ACL_REVISION, SYNCHRONIZE, | |
175 | well_known_world_sid)) | |
176 | { | |
177 | debug_printf ("AddAccessAllowedAce: %lu", GetLastError ()); | |
178 | return; | |
179 | } | |
180 | /* Set the size of the DACL correctly. */ | |
1754539e CV |
181 | status = RtlFirstFreeAce (dacl, &ace); |
182 | if (!NT_SUCCESS (status)) | |
a998dd70 | 183 | { |
1754539e | 184 | debug_printf ("RtlFirstFreeAce: %p", status); |
a998dd70 CV |
185 | return; |
186 | } | |
187 | dacl->AclSize = (char *) ace - (char *) dacl; | |
188 | /* Write the DACL back. */ | |
f16706de | 189 | status = NtSetSecurityObject (NtCurrentProcess (), DACL_SECURITY_INFORMATION, sd); |
a998dd70 CV |
190 | if (!NT_SUCCESS (status)) |
191 | { | |
192 | debug_printf ("NtSetSecurityObject: %p", status); | |
193 | return; | |
194 | } | |
195 | done = true; | |
196 | } | |
197 | ||
636c94d8 CV |
198 | /* Get the handle count of an object. */ |
199 | static ULONG | |
200 | get_obj_handle_count (HANDLE h) | |
201 | { | |
202 | OBJECT_BASIC_INFORMATION obi; | |
203 | NTSTATUS status; | |
204 | ULONG hdl_cnt = 0; | |
205 | ||
206 | status = NtQueryObject (h, ObjectBasicInformation, &obi, sizeof obi, NULL); | |
207 | if (!NT_SUCCESS (status)) | |
208 | debug_printf ("NtQueryObject: %p\n", status); | |
209 | else | |
210 | hdl_cnt = obi.HandleCount; | |
211 | return hdl_cnt; | |
212 | } | |
213 | ||
a998dd70 CV |
214 | /* Per lock class. */ |
215 | class lockf_t | |
216 | { | |
217 | public: | |
218 | short lf_flags; /* Semantics: F_POSIX, F_FLOCK, F_WAIT */ | |
219 | short lf_type; /* Lock type: F_RDLCK, F_WRLCK */ | |
220 | _off64_t lf_start; /* Byte # of the start of the lock */ | |
221 | _off64_t lf_end; /* Byte # of the end of the lock (-1=EOF) */ | |
636c94d8 CV |
222 | long long lf_id; /* Cygwin PID for POSIX locks, a unique id per |
223 | file table entry for BSD flock locks. */ | |
a998dd70 CV |
224 | DWORD lf_wid; /* Win PID of the resource holding the lock */ |
225 | class lockf_t **lf_head; /* Back pointer to the head of the lockf_t list */ | |
226 | class inode_t *lf_inode; /* Back pointer to the inode_t */ | |
227 | class lockf_t *lf_next; /* Pointer to the next lock on this inode_t */ | |
228 | HANDLE lf_obj; /* Handle to the lock event object. */ | |
229 | ||
230 | lockf_t () | |
231 | : lf_flags (0), lf_type (0), lf_start (0), lf_end (0), lf_id (0), | |
636c94d8 CV |
232 | lf_wid (0), lf_head (NULL), lf_inode (NULL), |
233 | lf_next (NULL), lf_obj (NULL) | |
a998dd70 CV |
234 | {} |
235 | lockf_t (class inode_t *node, class lockf_t **head, short flags, short type, | |
636c94d8 | 236 | _off64_t start, _off64_t end, long long id, DWORD wid) |
a998dd70 CV |
237 | : lf_flags (flags), lf_type (type), lf_start (start), lf_end (end), |
238 | lf_id (id), lf_wid (wid), lf_head (head), lf_inode (node), | |
239 | lf_next (NULL), lf_obj (NULL) | |
240 | {} | |
241 | ~lockf_t (); | |
242 | ||
31390e4c CV |
243 | /* Used to create all locks list in a given TLS buffer. */ |
244 | void *operator new (size_t size, void *p) | |
245 | { return p; } | |
246 | /* Used to store own lock list in the cygheap. */ | |
a998dd70 | 247 | void *operator new (size_t size) |
31390e4c CV |
248 | { return cmalloc (HEAP_FHANDLER, sizeof (lockf_t)); } |
249 | /* Never call on node->i_all_lf! */ | |
a998dd70 CV |
250 | void operator delete (void *p) |
251 | { cfree (p); } | |
252 | ||
253 | void create_lock_obj (); | |
636c94d8 CV |
254 | bool open_lock_obj (); |
255 | void del_lock_obj (HANDLE fhdl, bool signal = false); | |
a998dd70 CV |
256 | }; |
257 | ||
258 | /* Per inode_t class */ | |
259 | class inode_t | |
260 | { | |
261 | friend class lockf_t; | |
262 | ||
263 | public: | |
264 | LIST_ENTRY (inode_t) i_next; | |
265 | lockf_t *i_lockf; /* List of locks of this process. */ | |
266 | lockf_t *i_all_lf; /* Temp list of all locks for this file. */ | |
267 | ||
636c94d8 CV |
268 | __dev32_t i_dev; /* Device ID */ |
269 | __ino64_t i_ino; /* inode number */ | |
a998dd70 | 270 | |
636c94d8 CV |
271 | private: |
272 | HANDLE i_dir; | |
273 | HANDLE i_mtx; | |
a74869c0 CV |
274 | unsigned long i_wait; /* Number of blocked threads waiting for |
275 | a blocking lock. */ | |
a998dd70 CV |
276 | |
277 | public: | |
636c94d8 | 278 | inode_t (__dev32_t dev, __ino64_t ino); |
a998dd70 CV |
279 | ~inode_t (); |
280 | ||
281 | void *operator new (size_t size) | |
31390e4c | 282 | { return cmalloc (HEAP_FHANDLER, sizeof (inode_t)); } |
a998dd70 CV |
283 | void operator delete (void *p) |
284 | { cfree (p); } | |
285 | ||
636c94d8 | 286 | static inode_t *get (__dev32_t dev, __ino64_t ino, bool create_if_missing); |
a998dd70 CV |
287 | |
288 | void LOCK () { WaitForSingleObject (i_mtx, INFINITE); } | |
289 | void UNLOCK () { ReleaseMutex (i_mtx); } | |
290 | ||
a74869c0 CV |
291 | void wait () { ++i_wait; } |
292 | void unwait () { if (i_wait > 0) --i_wait; } | |
b4fa8164 | 293 | bool waiting () { return i_wait > 0; } |
a74869c0 | 294 | |
31390e4c | 295 | lockf_t *get_all_locks_list (); |
a998dd70 | 296 | |
636c94d8 | 297 | bool del_my_locks (long long id, HANDLE fhdl); |
a998dd70 CV |
298 | }; |
299 | ||
636c94d8 | 300 | inode_t::~inode_t () |
a998dd70 | 301 | { |
636c94d8 CV |
302 | lockf_t *lock, *n_lock; |
303 | for (lock = i_lockf; lock && (n_lock = lock->lf_next, 1); lock = n_lock) | |
304 | delete lock; | |
305 | NtClose (i_mtx); | |
306 | NtClose (i_dir); | |
a998dd70 CV |
307 | } |
308 | ||
636c94d8 CV |
309 | bool |
310 | inode_t::del_my_locks (long long id, HANDLE fhdl) | |
a998dd70 | 311 | { |
636c94d8 CV |
312 | lockf_t *lock, *n_lock; |
313 | lockf_t **prev = &i_lockf; | |
314 | int lc = 0; | |
315 | for (lock = *prev; lock && (n_lock = lock->lf_next, 1); lock = n_lock) | |
316 | { | |
317 | if (lock->lf_flags & F_POSIX) | |
318 | { | |
319 | /* Delete all POSIX locks. */ | |
320 | *prev = n_lock; | |
321 | ++lc; | |
322 | delete lock; | |
323 | } | |
324 | else if (id && lock->lf_id == id) | |
325 | { | |
326 | int cnt = 0; | |
327 | cygheap_fdenum cfd (true); | |
328 | while (cfd.next () >= 0) | |
329 | if (cfd->get_unique_id () == lock->lf_id && ++cnt > 1) | |
330 | break; | |
331 | /* Delete BSD flock lock when no other fd in this process references | |
332 | it anymore. */ | |
333 | if (cnt <= 1) | |
334 | { | |
335 | *prev = n_lock; | |
336 | lock->del_lock_obj (fhdl); | |
337 | delete lock; | |
338 | } | |
339 | } | |
340 | else | |
341 | prev = &lock->lf_next; | |
342 | } | |
343 | return i_lockf == NULL; | |
344 | } | |
a998dd70 | 345 | |
636c94d8 CV |
346 | /* Used to delete the locks on a file hold by this process. Called from |
347 | close(2) and fixup_after_fork, as well as from fixup_after_exec in | |
348 | case the close_on_exec flag is set. The whole inode is deleted as | |
349 | soon as no lock exists on it anymore. */ | |
350 | void | |
4a77aea0 | 351 | fhandler_base::del_my_locks (del_lock_called_from from) |
636c94d8 CV |
352 | { |
353 | INODE_LIST_LOCK (); | |
354 | inode_t *node = inode_t::get (get_dev (), get_ino (), false); | |
355 | if (node) | |
356 | { | |
4a77aea0 CV |
357 | /* When we're called from fixup_after_exec, the fhandler is a |
358 | close-on-exec fhandler. In this case our io handle is already | |
359 | invalid. We can't use it to test for the object reference count. | |
360 | However, that shouldn't be necessary for the following reason. | |
361 | After exec, there are no threads in the current process waiting for | |
362 | the lock. So, either we're the only process accessing the file table | |
363 | entry and there are no threads which require signalling, or we have | |
364 | a parent process still accessing the file object and signalling the | |
365 | lock event would be premature. */ | |
636c94d8 | 366 | bool no_locks_left = |
4a77aea0 CV |
367 | node->del_my_locks (from == after_fork ? 0 : get_unique_id (), |
368 | from == after_exec ? NULL : get_handle ()); | |
636c94d8 CV |
369 | if (no_locks_left) |
370 | { | |
371 | LIST_REMOVE (node, i_next); | |
372 | node->UNLOCK (); | |
373 | delete node; | |
374 | } | |
375 | else | |
376 | node->UNLOCK (); | |
377 | } | |
378 | INODE_LIST_UNLOCK (); | |
a998dd70 CV |
379 | } |
380 | ||
381 | /* Called in an execed child. The exec'ed process must allow SYNCHRONIZE | |
382 | access to everyone if at least one inode exists. | |
636c94d8 CV |
383 | The lock owner's Windows PID changed and all POSIX lock event objects |
384 | have to be relabeled so that waiting processes know which process to | |
385 | wait on. If the node has been abandoned due to close_on_exec on the | |
386 | referencing fhandlers, remove the inode entirely. */ | |
a998dd70 CV |
387 | void |
388 | fixup_lockf_after_exec () | |
389 | { | |
636c94d8 | 390 | inode_t *node, *next_node; |
a998dd70 CV |
391 | |
392 | INODE_LIST_LOCK (); | |
393 | if (LIST_FIRST (&cygheap->inode_list)) | |
394 | allow_others_to_sync (); | |
636c94d8 | 395 | LIST_FOREACH_SAFE (node, &cygheap->inode_list, i_next, next_node) |
a998dd70 | 396 | { |
636c94d8 CV |
397 | int cnt = 0; |
398 | cygheap_fdenum cfd (true); | |
399 | while (cfd.next () >= 0) | |
400 | if (cfd->get_dev () == node->i_dev | |
401 | && cfd->get_ino () == node->i_ino | |
402 | && ++cnt > 1) | |
403 | break; | |
404 | if (cnt == 0) | |
a998dd70 | 405 | { |
636c94d8 CV |
406 | LIST_REMOVE (node, i_next); |
407 | delete node; | |
408 | } | |
409 | else | |
410 | { | |
411 | node->LOCK (); | |
412 | for (lockf_t *lock = node->i_lockf; lock; lock = lock->lf_next) | |
413 | if (lock->lf_flags & F_POSIX) | |
414 | { | |
415 | lock->del_lock_obj (NULL); | |
416 | lock->lf_wid = myself->dwProcessId; | |
417 | lock->create_lock_obj (); | |
418 | } | |
419 | node->UNLOCK (); | |
a998dd70 | 420 | } |
a998dd70 | 421 | } |
a998dd70 CV |
422 | INODE_LIST_UNLOCK (); |
423 | } | |
424 | ||
425 | /* static method to return a pointer to the inode_t structure for a specific | |
426 | file. The file is specified by the device and inode_t number. If inode_t | |
427 | doesn't exist, create it. */ | |
428 | inode_t * | |
636c94d8 | 429 | inode_t::get (__dev32_t dev, __ino64_t ino, bool create_if_missing) |
a998dd70 CV |
430 | { |
431 | inode_t *node; | |
432 | ||
433 | INODE_LIST_LOCK (); | |
434 | LIST_FOREACH (node, &cygheap->inode_list, i_next) | |
435 | if (node->i_dev == dev && node->i_ino == ino) | |
436 | break; | |
636c94d8 | 437 | if (!node && create_if_missing) |
a998dd70 CV |
438 | { |
439 | node = new inode_t (dev, ino); | |
31390e4c CV |
440 | if (node) |
441 | LIST_INSERT_HEAD (&cygheap->inode_list, node, i_next); | |
a998dd70 | 442 | } |
636c94d8 CV |
443 | if (node) |
444 | node->LOCK (); | |
a998dd70 CV |
445 | INODE_LIST_UNLOCK (); |
446 | return node; | |
447 | } | |
448 | ||
636c94d8 | 449 | inode_t::inode_t (__dev32_t dev, __ino64_t ino) |
a74869c0 | 450 | : i_lockf (NULL), i_all_lf (NULL), i_dev (dev), i_ino (ino), i_wait (0L) |
a998dd70 CV |
451 | { |
452 | HANDLE parent_dir; | |
db5ae618 | 453 | WCHAR name[48]; |
a998dd70 CV |
454 | UNICODE_STRING uname; |
455 | OBJECT_ATTRIBUTES attr; | |
456 | NTSTATUS status; | |
457 | ||
db5ae618 | 458 | parent_dir = get_shared_parent_dir (); |
a998dd70 CV |
459 | /* Create a subdir which is named after the device and inode_t numbers |
460 | of the given file, in hex notation. */ | |
db5ae618 | 461 | int len = __small_swprintf (name, L"flock-%08x-%016X", dev, ino); |
a998dd70 | 462 | RtlInitCountedUnicodeString (&uname, name, len * sizeof (WCHAR)); |
5cb524ee CV |
463 | InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF, |
464 | parent_dir, everyone_sd (FLOCK_INODE_DIR_ACCESS)); | |
465 | status = NtCreateDirectoryObject (&i_dir, FLOCK_INODE_DIR_ACCESS, &attr); | |
a998dd70 | 466 | if (!NT_SUCCESS (status)) |
5cb524ee | 467 | api_fatal ("NtCreateDirectoryObject(inode): %p", status); |
a998dd70 CV |
468 | /* Create a mutex object in the file specific dir, which is used for |
469 | access synchronization on the dir and its objects. */ | |
8deb4118 | 470 | InitializeObjectAttributes (&attr, &ro_u_mtx, OBJ_INHERIT | OBJ_OPENIF, i_dir, |
abbde487 CV |
471 | everyone_sd (CYG_MUTANT_ACCESS)); |
472 | status = NtCreateMutant (&i_mtx, CYG_MUTANT_ACCESS, &attr, FALSE); | |
a998dd70 | 473 | if (!NT_SUCCESS (status)) |
5cb524ee | 474 | api_fatal ("NtCreateMutant(inode): %p", status); |
a998dd70 CV |
475 | } |
476 | ||
a998dd70 CV |
477 | /* Enumerate all lock event objects for this file and create a lockf_t |
478 | list in the i_all_lf member. This list is searched in lf_getblock | |
479 | for locks which potentially block our lock request. */ | |
31390e4c CV |
480 | |
481 | /* Number of lockf_t structs which fit in the temporary buffer. */ | |
482 | #define MAX_LOCKF_CNT ((intptr_t)((NT_MAX_PATH * sizeof (WCHAR)) \ | |
483 | / sizeof (lockf_t))) | |
484 | ||
485 | lockf_t * | |
a998dd70 CV |
486 | inode_t::get_all_locks_list () |
487 | { | |
488 | struct fdbi | |
489 | { | |
490 | DIRECTORY_BASIC_INFORMATION dbi; | |
491 | WCHAR buf[2][NAME_MAX + 1]; | |
492 | } f; | |
493 | ULONG context; | |
494 | NTSTATUS status; | |
31390e4c | 495 | lockf_t *lock = i_all_lf; |
a998dd70 | 496 | |
a998dd70 CV |
497 | for (BOOLEAN restart = TRUE; |
498 | NT_SUCCESS (status = NtQueryDirectoryObject (i_dir, &f, sizeof f, TRUE, | |
499 | restart, &context, NULL)); | |
500 | restart = FALSE) | |
501 | { | |
502 | if (f.dbi.ObjectName.Length != LOCK_OBJ_NAME_LEN * sizeof (WCHAR)) | |
503 | continue; | |
504 | wchar_t *wc = f.dbi.ObjectName.Buffer, *endptr; | |
636c94d8 | 505 | /* "%02x-%01x-%016X-%016X-%016X-%08x", |
a998dd70 CV |
506 | lf_flags, lf_type, lf_start, lf_end, lf_id, lf_wid */ |
507 | wc[LOCK_OBJ_NAME_LEN] = L'\0'; | |
508 | short flags = wcstol (wc, &endptr, 16); | |
072030c3 | 509 | if ((flags & ~(F_FLOCK | F_POSIX)) != 0 |
7b9e380f | 510 | || ((flags & (F_FLOCK | F_POSIX)) == (F_FLOCK | F_POSIX))) |
a998dd70 CV |
511 | continue; |
512 | short type = wcstol (endptr + 1, &endptr, 16); | |
e7afe579 | 513 | if ((type != F_RDLCK && type != F_WRLCK) || !endptr || *endptr != L'-') |
025c1fac | 514 | continue; |
a998dd70 CV |
515 | _off64_t start = (_off64_t) wcstoull (endptr + 1, &endptr, 16); |
516 | if (start < 0 || !endptr || *endptr != L'-') | |
025c1fac | 517 | continue; |
a998dd70 CV |
518 | _off64_t end = (_off64_t) wcstoull (endptr + 1, &endptr, 16); |
519 | if (end < -1LL || (end > 0 && end < start) || !endptr || *endptr != L'-') | |
025c1fac | 520 | continue; |
636c94d8 CV |
521 | long long id = wcstoll (endptr + 1, &endptr, 16); |
522 | if (!endptr || *endptr != L'-' | |
523 | || ((flags & F_POSIX) && (id < 1 || id > ULONG_MAX))) | |
025c1fac | 524 | continue; |
a998dd70 CV |
525 | DWORD wid = wcstoul (endptr + 1, &endptr, 16); |
526 | if (endptr && *endptr != L'\0') | |
025c1fac | 527 | continue; |
31390e4c | 528 | if (lock - i_all_lf >= MAX_LOCKF_CNT) |
025c1fac | 529 | { |
31390e4c CV |
530 | system_printf ("Warning, can't handle more than %d locks per file.", |
531 | MAX_LOCKF_CNT); | |
532 | break; | |
533 | } | |
534 | if (lock > i_all_lf) | |
025c1fac | 535 | lock[-1].lf_next = lock; |
31390e4c | 536 | new (lock++) lockf_t (this, &i_all_lf, flags, type, start, end, id, wid); |
a998dd70 | 537 | } |
31390e4c CV |
538 | /* If no lock has been found, return NULL. */ |
539 | if (lock == i_all_lf) | |
540 | return NULL; | |
541 | return i_all_lf; | |
a998dd70 CV |
542 | } |
543 | ||
544 | /* Create the lock event object in the file's subdir in the NT global | |
545 | namespace. The name is constructed from the lock properties which | |
546 | identify it uniquely, all values in hex. See the __small_swprintf | |
547 | call right at the start. */ | |
548 | void | |
549 | lockf_t::create_lock_obj () | |
550 | { | |
636c94d8 | 551 | WCHAR name[LOCK_OBJ_NAME_LEN + 1]; |
a998dd70 CV |
552 | UNICODE_STRING uname; |
553 | OBJECT_ATTRIBUTES attr; | |
554 | NTSTATUS status; | |
555 | ||
636c94d8 | 556 | __small_swprintf (name, L"%02x-%01x-%016X-%016X-%016X-%08x", |
072030c3 CV |
557 | lf_flags & (F_POSIX | F_FLOCK), lf_type, lf_start, |
558 | lf_end, lf_id, lf_wid); | |
a998dd70 CV |
559 | RtlInitCountedUnicodeString (&uname, name, |
560 | LOCK_OBJ_NAME_LEN * sizeof (WCHAR)); | |
561 | InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT, lf_inode->i_dir, | |
c46d7be9 | 562 | everyone_sd (FLOCK_EVENT_ACCESS)); |
abbde487 | 563 | status = NtCreateEvent (&lf_obj, CYG_EVENT_ACCESS, &attr, |
a998dd70 CV |
564 | NotificationEvent, FALSE); |
565 | if (!NT_SUCCESS (status)) | |
c46d7be9 | 566 | api_fatal ("NtCreateEvent(lock): %p", status); |
a998dd70 CV |
567 | } |
568 | ||
569 | /* Open a lock event object for SYNCHRONIZE access (to wait for it). */ | |
636c94d8 CV |
570 | bool |
571 | lockf_t::open_lock_obj () | |
a998dd70 | 572 | { |
636c94d8 | 573 | WCHAR name[LOCK_OBJ_NAME_LEN + 1]; |
a998dd70 CV |
574 | UNICODE_STRING uname; |
575 | OBJECT_ATTRIBUTES attr; | |
576 | NTSTATUS status; | |
a998dd70 | 577 | |
636c94d8 | 578 | __small_swprintf (name, L"%02x-%01x-%016X-%016X-%016X-%08x", |
072030c3 CV |
579 | lf_flags & (F_POSIX | F_FLOCK), lf_type, lf_start, |
580 | lf_end, lf_id, lf_wid); | |
a998dd70 CV |
581 | RtlInitCountedUnicodeString (&uname, name, |
582 | LOCK_OBJ_NAME_LEN * sizeof (WCHAR)); | |
31390e4c | 583 | InitializeObjectAttributes (&attr, &uname, 0, lf_inode->i_dir, NULL); |
636c94d8 | 584 | status = NtOpenEvent (&lf_obj, FLOCK_EVENT_ACCESS, &attr); |
a998dd70 | 585 | if (!NT_SUCCESS (status)) |
c46d7be9 CV |
586 | { |
587 | SetLastError (RtlNtStatusToDosError (status)); | |
636c94d8 | 588 | lf_obj = NULL; /* Paranoia... */ |
a998dd70 | 589 | } |
636c94d8 | 590 | return lf_obj != NULL; |
a998dd70 CV |
591 | } |
592 | ||
593 | /* Close a lock event handle. The important thing here is to signal it | |
594 | before closing the handle. This way all threads waiting for this | |
595 | lock can wake up. */ | |
596 | void | |
636c94d8 | 597 | lockf_t::del_lock_obj (HANDLE fhdl, bool signal) |
a998dd70 CV |
598 | { |
599 | if (lf_obj) | |
600 | { | |
636c94d8 CV |
601 | /* Only signal the event if it's either a POSIX lock, or, in case of |
602 | BSD flock locks, if it's an explicit unlock or if the calling fhandler | |
603 | holds the last reference to the file table entry. The file table | |
604 | entry in UNIX terms is equivalent to the FILE_OBJECT in Windows NT | |
605 | terms. It's what the handle/descriptor references when calling | |
606 | CreateFile/open. Calling DuplicateHandle/dup only creates a new | |
607 | handle/descriptor to the same FILE_OBJECT/file table entry. */ | |
608 | if ((lf_flags & F_POSIX) || signal | |
609 | || (fhdl && get_obj_handle_count (fhdl) <= 1)) | |
610 | SetEvent (lf_obj); | |
a998dd70 CV |
611 | NtClose (lf_obj); |
612 | lf_obj = NULL; | |
613 | } | |
614 | } | |
615 | ||
616 | lockf_t::~lockf_t () | |
617 | { | |
636c94d8 | 618 | del_lock_obj (NULL); |
a998dd70 CV |
619 | } |
620 | ||
621 | /* | |
622 | * This variable controls the maximum number of processes that will | |
623 | * be checked in doing deadlock detection. | |
624 | */ | |
636c94d8 | 625 | #ifndef __CYGWIN__ |
a998dd70 CV |
626 | #define MAXDEPTH 50 |
627 | static int maxlockdepth = MAXDEPTH; | |
628 | #endif | |
629 | ||
630 | #define NOLOCKF (struct lockf_t *)0 | |
631 | #define SELF 0x1 | |
632 | #define OTHERS 0x2 | |
636c94d8 | 633 | static int lf_clearlock (lockf_t *, lockf_t **, HANDLE); |
a998dd70 | 634 | static int lf_findoverlap (lockf_t *, lockf_t *, int, lockf_t ***, lockf_t **); |
31390e4c | 635 | static lockf_t *lf_getblock (lockf_t *, inode_t *node); |
a998dd70 | 636 | static int lf_getlock (lockf_t *, inode_t *, struct __flock64 *); |
636c94d8 | 637 | static int lf_setlock (lockf_t *, inode_t *, lockf_t **, HANDLE); |
a998dd70 | 638 | static void lf_split (lockf_t *, lockf_t *, lockf_t **); |
636c94d8 | 639 | static void lf_wakelock (lockf_t *, HANDLE); |
a998dd70 CV |
640 | |
641 | int | |
642 | fhandler_disk_file::lock (int a_op, struct __flock64 *fl) | |
643 | { | |
644 | _off64_t start, end, oadd; | |
645 | lockf_t *n; | |
646 | int error = 0; | |
a998dd70 CV |
647 | |
648 | short a_flags = fl->l_type & (F_POSIX | F_FLOCK); | |
649 | short type = fl->l_type & (F_RDLCK | F_WRLCK | F_UNLCK); | |
025c1fac | 650 | |
a998dd70 CV |
651 | if (!a_flags) |
652 | a_flags = F_POSIX; /* default */ | |
653 | if (a_op == F_SETLKW) | |
654 | { | |
655 | a_op = F_SETLK; | |
656 | a_flags |= F_WAIT; | |
657 | } | |
658 | if (a_op == F_SETLK) | |
659 | switch (type) | |
660 | { | |
661 | case F_UNLCK: | |
662 | a_op = F_UNLCK; | |
663 | break; | |
664 | case F_RDLCK: | |
fc69f1ae CV |
665 | /* flock semantics don't specify a requirement that the file has |
666 | been opened with a specific open mode, in contrast to POSIX locks | |
667 | which require that a file is opened for reading to place a read | |
668 | lock and opened for writing to place a write lock. */ | |
669 | if ((a_flags & F_POSIX) && !(get_access () & GENERIC_READ)) | |
a998dd70 CV |
670 | { |
671 | set_errno (EBADF); | |
672 | return -1; | |
673 | } | |
674 | break; | |
675 | case F_WRLCK: | |
fc69f1ae CV |
676 | /* See above comment. */ |
677 | if ((a_flags & F_POSIX) && !(get_access () & GENERIC_WRITE)) | |
a998dd70 CV |
678 | { |
679 | set_errno (EBADF); | |
680 | return -1; | |
681 | } | |
682 | break; | |
683 | default: | |
025c1fac | 684 | set_errno (EINVAL); |
a998dd70 CV |
685 | return -1; |
686 | } | |
687 | ||
a998dd70 CV |
688 | /* |
689 | * Convert the flock structure into a start and end. | |
690 | */ | |
691 | switch (fl->l_whence) | |
692 | { | |
693 | case SEEK_SET: | |
694 | start = fl->l_start; | |
695 | break; | |
696 | ||
697 | case SEEK_CUR: | |
698 | if ((start = lseek (0, SEEK_CUR)) == ILLEGAL_SEEK) | |
699 | return -1; | |
700 | break; | |
701 | ||
702 | case SEEK_END: | |
636c94d8 CV |
703 | { |
704 | NTSTATUS status; | |
705 | IO_STATUS_BLOCK io; | |
706 | FILE_STANDARD_INFORMATION fsi; | |
707 | ||
708 | status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi, | |
709 | FileStandardInformation); | |
710 | if (!NT_SUCCESS (status)) | |
711 | { | |
712 | __seterrno_from_nt_status (status); | |
713 | return -1; | |
714 | } | |
715 | if (fl->l_start > 0 && fsi.EndOfFile.QuadPart > OFF_MAX - fl->l_start) | |
716 | { | |
717 | set_errno (EOVERFLOW); | |
718 | return -1; | |
719 | } | |
720 | start = fsi.EndOfFile.QuadPart + fl->l_start; | |
721 | } | |
a998dd70 CV |
722 | break; |
723 | ||
724 | default: | |
725 | return (EINVAL); | |
726 | } | |
727 | if (start < 0) | |
728 | { | |
729 | set_errno (EINVAL); | |
730 | return -1; | |
731 | } | |
732 | if (fl->l_len < 0) | |
733 | { | |
734 | if (start == 0) | |
735 | { | |
736 | set_errno (EINVAL); | |
737 | return -1; | |
738 | } | |
739 | end = start - 1; | |
740 | start += fl->l_len; | |
741 | if (start < 0) | |
742 | { | |
743 | set_errno (EINVAL); | |
744 | return -1; | |
745 | } | |
746 | } | |
747 | else if (fl->l_len == 0) | |
748 | end = -1; | |
749 | else | |
750 | { | |
751 | oadd = fl->l_len - 1; | |
752 | if (oadd > OFF_MAX - start) | |
753 | { | |
754 | set_errno (EOVERFLOW); | |
755 | return -1; | |
756 | } | |
757 | end = start + oadd; | |
758 | } | |
759 | ||
636c94d8 | 760 | inode_t *node = inode_t::get (get_dev (), get_ino (), true); |
a998dd70 CV |
761 | if (!node) |
762 | { | |
636c94d8 CV |
763 | set_errno (ENOLCK); |
764 | return -1; | |
a998dd70 | 765 | } |
636c94d8 CV |
766 | need_fork_fixup (true); |
767 | ||
fabfb1a1 CV |
768 | /* Unlock the fd table which has been locked in fcntl_worker/lock_worker, |
769 | otherwise a blocking F_SETLKW never wakes up on a signal. */ | |
a998dd70 CV |
770 | cygheap->fdtab.unlock (); |
771 | ||
772 | lockf_t **head = &node->i_lockf; | |
773 | ||
9fa63f7a | 774 | #if 0 |
a998dd70 CV |
775 | /* |
776 | * Avoid the common case of unlocking when inode_t has no locks. | |
9fa63f7a CV |
777 | * |
778 | * This shortcut is invalid for Cygwin because the above inode_t::get | |
779 | * call returns with an empty lock list if this process has no locks | |
780 | * on the file yet. | |
a998dd70 CV |
781 | */ |
782 | if (*head == NULL) | |
783 | { | |
784 | if (a_op != F_SETLK) | |
785 | { | |
636c94d8 | 786 | node->UNLOCK (); |
a998dd70 CV |
787 | fl->l_type = F_UNLCK; |
788 | return 0; | |
789 | } | |
790 | } | |
9fa63f7a | 791 | #endif |
a998dd70 CV |
792 | /* |
793 | * Allocate a spare structure in case we have to split. | |
794 | */ | |
795 | lockf_t *clean = NULL; | |
796 | if (a_op == F_SETLK || a_op == F_UNLCK) | |
31390e4c CV |
797 | { |
798 | clean = new lockf_t (); | |
799 | if (!clean) | |
025c1fac | 800 | { |
636c94d8 | 801 | node->UNLOCK (); |
31390e4c CV |
802 | set_errno (ENOLCK); |
803 | return -1; | |
804 | } | |
805 | } | |
a998dd70 CV |
806 | /* |
807 | * Create the lockf_t structure | |
808 | */ | |
809 | lockf_t *lock = new lockf_t (node, head, a_flags, type, start, end, | |
636c94d8 CV |
810 | (a_flags & F_FLOCK) ? get_unique_id () |
811 | : getpid (), | |
812 | myself->dwProcessId); | |
31390e4c CV |
813 | if (!lock) |
814 | { | |
636c94d8 | 815 | node->UNLOCK (); |
31390e4c CV |
816 | set_errno (ENOLCK); |
817 | return -1; | |
818 | } | |
a998dd70 | 819 | |
a998dd70 CV |
820 | switch (a_op) |
821 | { | |
822 | case F_SETLK: | |
636c94d8 | 823 | error = lf_setlock (lock, node, &clean, get_handle ()); |
a998dd70 CV |
824 | break; |
825 | ||
826 | case F_UNLCK: | |
636c94d8 | 827 | error = lf_clearlock (lock, &clean, get_handle ()); |
a998dd70 | 828 | lock->lf_next = clean; |
025c1fac | 829 | clean = lock; |
a998dd70 | 830 | break; |
025c1fac | 831 | |
a998dd70 CV |
832 | case F_GETLK: |
833 | error = lf_getlock (lock, node, fl); | |
834 | lock->lf_next = clean; | |
835 | clean = lock; | |
836 | break; | |
837 | ||
838 | default: | |
839 | lock->lf_next = clean; | |
840 | clean = lock; | |
841 | error = EINVAL; | |
842 | break; | |
843 | } | |
844 | for (lock = clean; lock != NULL; ) | |
845 | { | |
846 | n = lock->lf_next; | |
636c94d8 | 847 | lock->del_lock_obj (get_handle (), a_op == F_UNLCK); |
a998dd70 CV |
848 | delete lock; |
849 | lock = n; | |
850 | } | |
a74869c0 | 851 | if (node->i_lockf == NULL && !node->waiting ()) |
636c94d8 CV |
852 | { |
853 | INODE_LIST_LOCK (); | |
854 | LIST_REMOVE (node, i_next); | |
855 | node->UNLOCK (); | |
856 | delete node; | |
857 | INODE_LIST_UNLOCK (); | |
858 | } | |
859 | else | |
860 | node->UNLOCK (); | |
a998dd70 CV |
861 | if (error) |
862 | { | |
863 | set_errno (error); | |
864 | return -1; | |
865 | } | |
866 | return 0; | |
867 | } | |
868 | ||
869 | /* | |
870 | * Set a byte-range lock. | |
871 | */ | |
872 | static int | |
636c94d8 | 873 | lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) |
025c1fac | 874 | { |
a998dd70 CV |
875 | lockf_t *block; |
876 | lockf_t **head = lock->lf_head; | |
877 | lockf_t **prev, *overlap; | |
878 | int ovcase, priority, old_prio, needtolink; | |
30bbc55e | 879 | tmp_pathbuf tp; |
a998dd70 CV |
880 | |
881 | /* | |
882 | * Set the priority | |
883 | */ | |
884 | priority = old_prio = GetThreadPriority (GetCurrentThread ()); | |
885 | if (lock->lf_type == F_WRLCK && priority <= THREAD_PRIORITY_ABOVE_NORMAL) | |
886 | priority = THREAD_PRIORITY_HIGHEST; | |
887 | /* | |
888 | * Scan lock list for this file looking for locks that would block us. | |
889 | */ | |
31390e4c | 890 | /* Create temporary space for the all locks list. */ |
30bbc55e | 891 | node->i_all_lf = (lockf_t *) (void *) tp.w_get (); |
a998dd70 CV |
892 | while ((block = lf_getblock(lock, node))) |
893 | { | |
636c94d8 CV |
894 | DWORD ret; |
895 | HANDLE obj = block->lf_obj; | |
896 | block->lf_obj = NULL; | |
897 | ||
a998dd70 CV |
898 | /* |
899 | * Free the structure and return if nonblocking. | |
900 | */ | |
901 | if ((lock->lf_flags & F_WAIT) == 0) | |
902 | { | |
a998dd70 CV |
903 | lock->lf_next = *clean; |
904 | *clean = lock; | |
636c94d8 CV |
905 | if (obj) |
906 | NtClose (obj); | |
a998dd70 CV |
907 | return EAGAIN; |
908 | } | |
909 | /* | |
910 | * We are blocked. Since flock style locks cover | |
911 | * the whole file, there is no chance for deadlock. | |
912 | * For byte-range locks we must check for deadlock. | |
913 | * | |
914 | * Deadlock detection is done by looking through the | |
915 | * wait channels to see if there are any cycles that | |
916 | * involve us. MAXDEPTH is set just to make sure we | |
917 | * do not go off into neverland. | |
918 | */ | |
919 | /* FIXME: We check the handle count of all the lock event objects | |
025c1fac | 920 | this process holds. If it's > 1, another process is |
a998dd70 CV |
921 | waiting for one of our locks. This method isn't overly |
922 | intelligent. If it turns out to be too dumb, we might | |
923 | have to remove it or to find another method. */ | |
924 | for (lockf_t *lk = node->i_lockf; lk; lk = lk->lf_next) | |
636c94d8 CV |
925 | if ((lk->lf_flags & F_POSIX) && get_obj_handle_count (lk->lf_obj) > 1) |
926 | { | |
927 | if (obj) | |
928 | NtClose (obj); | |
929 | return EDEADLK; | |
930 | } | |
a998dd70 CV |
931 | |
932 | /* | |
933 | * For flock type locks, we must first remove | |
934 | * any shared locks that we hold before we sleep | |
935 | * waiting for an exclusive lock. | |
936 | */ | |
937 | if ((lock->lf_flags & F_FLOCK) && lock->lf_type == F_WRLCK) | |
938 | { | |
939 | lock->lf_type = F_UNLCK; | |
636c94d8 | 940 | (void) lf_clearlock (lock, clean, fhdl); |
a998dd70 CV |
941 | lock->lf_type = F_WRLCK; |
942 | } | |
943 | ||
944 | /* | |
945 | * Add our lock to the blocked list and sleep until we're free. | |
946 | * Remember who blocked us (for deadlock detection). | |
947 | */ | |
636c94d8 | 948 | /* Cygwin: No locked list. See deadlock recognition above. */ |
a998dd70 CV |
949 | |
950 | /* Wait for the blocking object and its holding process. */ | |
c46d7be9 CV |
951 | if (!obj) |
952 | { | |
953 | /* We can't synchronize on the lock event object. | |
954 | Treat this as a deadlock-like situation for now. */ | |
955 | system_printf ("Can't sync with lock object hold by " | |
956 | "Win32 pid %lu: %E", block->lf_wid); | |
c46d7be9 CV |
957 | return EDEADLK; |
958 | } | |
636c94d8 CV |
959 | SetThreadPriority (GetCurrentThread (), priority); |
960 | if (lock->lf_flags & F_POSIX) | |
025c1fac | 961 | { |
636c94d8 CV |
962 | HANDLE proc = OpenProcess (SYNCHRONIZE, FALSE, block->lf_wid); |
963 | if (!proc) | |
964 | { | |
965 | /* If we can't synchronize on the process holding the lock, | |
966 | we will never recognize when the lock has been abandoned. | |
967 | Treat this as a deadlock-like situation for now. */ | |
968 | system_printf ("Can't sync with process holding a lock " | |
969 | "(Win32 pid %lu): %E", block->lf_wid); | |
970 | NtClose (obj); | |
971 | return EDEADLK; | |
972 | } | |
973 | HANDLE w4[3] = { obj, proc, signal_arrived }; | |
a74869c0 | 974 | node->wait (); |
636c94d8 CV |
975 | node->UNLOCK (); |
976 | ret = WaitForMultipleObjects (3, w4, FALSE, INFINITE); | |
977 | CloseHandle (proc); | |
978 | } | |
979 | else | |
025c1fac | 980 | { |
636c94d8 | 981 | HANDLE w4[2] = { obj, signal_arrived }; |
a74869c0 | 982 | node->wait (); |
636c94d8 CV |
983 | node->UNLOCK (); |
984 | /* Unfortunately, since BSD flock locks are not attached to a | |
985 | specific process, we can't recognize an abandoned lock by | |
986 | sync'ing with a process. We have to find out if we're the only | |
987 | process left accessing this event object. */ | |
988 | do | |
989 | { | |
990 | ret = WaitForMultipleObjects (2, w4, FALSE, 100L); | |
991 | } | |
992 | while (ret == WAIT_TIMEOUT && get_obj_handle_count (obj) > 1); | |
5698171a CV |
993 | /* There's a good chance that the above loop is left with |
994 | ret == WAIT_TIMEOUT if another process closes the file handle | |
995 | associated with this lock. This is for all practical purposes | |
996 | equivalent to a signalled lock object. */ | |
997 | if (ret == WAIT_TIMEOUT) | |
998 | ret = WAIT_OBJECT_0; | |
b9e2579c | 999 | } |
a998dd70 | 1000 | node->LOCK (); |
a74869c0 | 1001 | node->unwait (); |
636c94d8 CV |
1002 | NtClose (obj); |
1003 | SetThreadPriority (GetCurrentThread (), old_prio); | |
a998dd70 CV |
1004 | switch (ret) |
1005 | { | |
1006 | case WAIT_OBJECT_0: | |
636c94d8 | 1007 | /* The lock object has been set to signalled. */ |
a998dd70 | 1008 | break; |
636c94d8 | 1009 | case WAIT_OBJECT_0 + 1: |
025c1fac | 1010 | /* For POSIX locks, the process holding the lock has exited. */ |
636c94d8 CV |
1011 | if (lock->lf_flags & F_POSIX) |
1012 | break; | |
1013 | /*FALLTHRU*/ | |
a998dd70 CV |
1014 | case WAIT_OBJECT_0 + 2: |
1015 | /* A signal came in. */ | |
1016 | _my_tls.call_signal_handler (); | |
1017 | return EINTR; | |
1018 | default: | |
5698171a CV |
1019 | system_printf ("Shouldn't happen! ret = %lu, error: %lu\n", |
1020 | ret, GetLastError ()); | |
a998dd70 CV |
1021 | return geterrno_from_win_error (); |
1022 | } | |
1023 | } | |
a998dd70 CV |
1024 | allow_others_to_sync (); |
1025 | /* | |
1026 | * No blocks!! Add the lock. Note that we will | |
1027 | * downgrade or upgrade any overlapping locks this | |
1028 | * process already owns. | |
1029 | * | |
1030 | * Handle any locks that overlap. | |
1031 | */ | |
1032 | prev = head; | |
1033 | block = *head; | |
1034 | needtolink = 1; | |
1035 | for (;;) | |
1036 | { | |
1037 | ovcase = lf_findoverlap (block, lock, SELF, &prev, &overlap); | |
1038 | if (ovcase) | |
1039 | block = overlap->lf_next; | |
1040 | /* | |
1041 | * Six cases: | |
1042 | * 0) no overlap | |
1043 | * 1) overlap == lock | |
1044 | * 2) overlap contains lock | |
1045 | * 3) lock contains overlap | |
1046 | * 4) overlap starts before lock | |
1047 | * 5) overlap ends after lock | |
1048 | */ | |
1049 | switch (ovcase) | |
1050 | { | |
025c1fac | 1051 | case 0: /* no overlap */ |
a998dd70 CV |
1052 | if (needtolink) |
1053 | { | |
1054 | *prev = lock; | |
1055 | lock->lf_next = overlap; | |
1056 | lock->create_lock_obj (); | |
025c1fac CF |
1057 | } |
1058 | break; | |
a998dd70 | 1059 | |
025c1fac | 1060 | case 1: /* overlap == lock */ |
a998dd70 CV |
1061 | /* |
1062 | * If downgrading lock, others may be | |
1063 | * able to acquire it. | |
1064 | * Cygwin: Always wake lock. | |
1065 | */ | |
636c94d8 | 1066 | lf_wakelock (overlap, fhdl); |
a998dd70 CV |
1067 | overlap->lf_type = lock->lf_type; |
1068 | overlap->create_lock_obj (); | |
1069 | lock->lf_next = *clean; | |
1070 | *clean = lock; | |
1071 | break; | |
1072 | ||
025c1fac | 1073 | case 2: /* overlap contains lock */ |
a998dd70 CV |
1074 | /* |
1075 | * Check for common starting point and different types. | |
1076 | */ | |
1077 | if (overlap->lf_type == lock->lf_type) | |
1078 | { | |
1079 | lock->lf_next = *clean; | |
1080 | *clean = lock; | |
1081 | break; | |
1082 | } | |
1083 | if (overlap->lf_start == lock->lf_start) | |
1084 | { | |
1085 | *prev = lock; | |
1086 | lock->lf_next = overlap; | |
1087 | overlap->lf_start = lock->lf_end + 1; | |
1088 | } | |
1089 | else | |
1090 | lf_split (overlap, lock, clean); | |
636c94d8 | 1091 | lf_wakelock (overlap, fhdl); |
a998dd70 CV |
1092 | overlap->create_lock_obj (); |
1093 | lock->create_lock_obj (); | |
1094 | if (lock->lf_next && !lock->lf_next->lf_obj) | |
1095 | lock->lf_next->create_lock_obj (); | |
1096 | break; | |
1097 | ||
025c1fac | 1098 | case 3: /* lock contains overlap */ |
a998dd70 CV |
1099 | /* |
1100 | * If downgrading lock, others may be able to | |
1101 | * acquire it, otherwise take the list. | |
1102 | * Cygwin: Always wake old lock and create new lock. | |
1103 | */ | |
636c94d8 | 1104 | lf_wakelock (overlap, fhdl); |
a998dd70 CV |
1105 | /* |
1106 | * Add the new lock if necessary and delete the overlap. | |
1107 | */ | |
1108 | if (needtolink) | |
1109 | { | |
1110 | *prev = lock; | |
1111 | lock->lf_next = overlap->lf_next; | |
1112 | prev = &lock->lf_next; | |
1113 | lock->create_lock_obj (); | |
1114 | needtolink = 0; | |
1115 | } | |
1116 | else | |
1117 | *prev = overlap->lf_next; | |
1118 | overlap->lf_next = *clean; | |
1119 | *clean = overlap; | |
1120 | continue; | |
1121 | ||
025c1fac | 1122 | case 4: /* overlap starts before lock */ |
a998dd70 CV |
1123 | /* |
1124 | * Add lock after overlap on the list. | |
1125 | */ | |
1126 | lock->lf_next = overlap->lf_next; | |
1127 | overlap->lf_next = lock; | |
1128 | overlap->lf_end = lock->lf_start - 1; | |
1129 | prev = &lock->lf_next; | |
636c94d8 | 1130 | lf_wakelock (overlap, fhdl); |
a998dd70 CV |
1131 | overlap->create_lock_obj (); |
1132 | lock->create_lock_obj (); | |
1133 | needtolink = 0; | |
1134 | continue; | |
1135 | ||
025c1fac | 1136 | case 5: /* overlap ends after lock */ |
a998dd70 CV |
1137 | /* |
1138 | * Add the new lock before overlap. | |
1139 | */ | |
1140 | if (needtolink) { | |
1141 | *prev = lock; | |
1142 | lock->lf_next = overlap; | |
1143 | } | |
1144 | overlap->lf_start = lock->lf_end + 1; | |
636c94d8 | 1145 | lf_wakelock (overlap, fhdl); |
a998dd70 CV |
1146 | lock->create_lock_obj (); |
1147 | overlap->create_lock_obj (); | |
1148 | break; | |
1149 | } | |
1150 | break; | |
1151 | } | |
1152 | return 0; | |
1153 | } | |
1154 | ||
1155 | /* | |
1156 | * Remove a byte-range lock on an inode_t. | |
1157 | * | |
1158 | * Generally, find the lock (or an overlap to that lock) | |
1159 | * and remove it (or shrink it), then wakeup anyone we can. | |
1160 | */ | |
1161 | static int | |
636c94d8 | 1162 | lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) |
a998dd70 CV |
1163 | { |
1164 | lockf_t **head = unlock->lf_head; | |
1165 | lockf_t *lf = *head; | |
1166 | lockf_t *overlap, **prev; | |
1167 | int ovcase; | |
1168 | ||
1169 | if (lf == NOLOCKF) | |
1170 | return 0; | |
1171 | prev = head; | |
1172 | while ((ovcase = lf_findoverlap (lf, unlock, SELF, &prev, &overlap))) | |
1173 | { | |
1174 | /* | |
1175 | * Wakeup the list of locks to be retried. | |
1176 | */ | |
636c94d8 | 1177 | lf_wakelock (overlap, fhdl); |
a998dd70 CV |
1178 | |
1179 | switch (ovcase) | |
1180 | { | |
025c1fac | 1181 | case 1: /* overlap == lock */ |
a998dd70 CV |
1182 | *prev = overlap->lf_next; |
1183 | overlap->lf_next = *clean; | |
1184 | *clean = overlap; | |
1185 | break; | |
1186 | ||
025c1fac | 1187 | case 2: /* overlap contains lock: split it */ |
a998dd70 CV |
1188 | if (overlap->lf_start == unlock->lf_start) |
1189 | { | |
1190 | overlap->lf_start = unlock->lf_end + 1; | |
1191 | overlap->create_lock_obj (); | |
1192 | break; | |
1193 | } | |
1194 | lf_split (overlap, unlock, clean); | |
1195 | overlap->lf_next = unlock->lf_next; | |
1196 | overlap->create_lock_obj (); | |
1197 | if (overlap->lf_next && !overlap->lf_next->lf_obj) | |
1198 | overlap->lf_next->create_lock_obj (); | |
1199 | break; | |
1200 | ||
025c1fac | 1201 | case 3: /* lock contains overlap */ |
a998dd70 CV |
1202 | *prev = overlap->lf_next; |
1203 | lf = overlap->lf_next; | |
1204 | overlap->lf_next = *clean; | |
1205 | *clean = overlap; | |
1206 | continue; | |
1207 | ||
025c1fac CF |
1208 | case 4: /* overlap starts before lock */ |
1209 | overlap->lf_end = unlock->lf_start - 1; | |
1210 | prev = &overlap->lf_next; | |
1211 | lf = overlap->lf_next; | |
a998dd70 | 1212 | overlap->create_lock_obj (); |
025c1fac | 1213 | continue; |
a998dd70 | 1214 | |
025c1fac CF |
1215 | case 5: /* overlap ends after lock */ |
1216 | overlap->lf_start = unlock->lf_end + 1; | |
a998dd70 | 1217 | overlap->create_lock_obj (); |
025c1fac | 1218 | break; |
a998dd70 CV |
1219 | } |
1220 | break; | |
1221 | } | |
1222 | return 0; | |
1223 | } | |
1224 | ||
1225 | /* | |
1226 | * Check whether there is a blocking lock, | |
1227 | * and if so return its process identifier. | |
1228 | */ | |
1229 | static int | |
1230 | lf_getlock (lockf_t *lock, inode_t *node, struct __flock64 *fl) | |
1231 | { | |
1232 | lockf_t *block; | |
30bbc55e | 1233 | tmp_pathbuf tp; |
a998dd70 | 1234 | |
31390e4c | 1235 | /* Create temporary space for the all locks list. */ |
30bbc55e | 1236 | node->i_all_lf = (lockf_t *) (void * ) tp.w_get (); |
a998dd70 CV |
1237 | if ((block = lf_getblock (lock, node))) |
1238 | { | |
636c94d8 CV |
1239 | if (block->lf_obj) |
1240 | NtClose (block->lf_obj); | |
a998dd70 CV |
1241 | fl->l_type = block->lf_type; |
1242 | fl->l_whence = SEEK_SET; | |
1243 | fl->l_start = block->lf_start; | |
1244 | if (block->lf_end == -1) | |
1245 | fl->l_len = 0; | |
1246 | else | |
1247 | fl->l_len = block->lf_end - block->lf_start + 1; | |
1248 | if (block->lf_flags & F_POSIX) | |
636c94d8 | 1249 | fl->l_pid = (pid_t) block->lf_id; |
a998dd70 CV |
1250 | else |
1251 | fl->l_pid = -1; | |
1252 | } | |
1253 | else | |
1254 | fl->l_type = F_UNLCK; | |
a998dd70 CV |
1255 | return 0; |
1256 | } | |
1257 | ||
1258 | /* | |
1259 | * Walk the list of locks for an inode_t and | |
1260 | * return the first blocking lock. | |
1261 | */ | |
1262 | static lockf_t * | |
1263 | lf_getblock (lockf_t *lock, inode_t *node) | |
025c1fac | 1264 | { |
31390e4c CV |
1265 | lockf_t **prev, *overlap; |
1266 | lockf_t *lf = node->get_all_locks_list (); | |
a998dd70 | 1267 | int ovcase; |
636c94d8 CV |
1268 | NTSTATUS status; |
1269 | EVENT_BASIC_INFORMATION ebi; | |
a998dd70 CV |
1270 | |
1271 | prev = lock->lf_head; | |
1272 | while ((ovcase = lf_findoverlap (lf, lock, OTHERS, &prev, &overlap))) | |
1273 | { | |
1274 | /* | |
1275 | * We've found an overlap, see if it blocks us | |
1276 | */ | |
1277 | if ((lock->lf_type == F_WRLCK || overlap->lf_type == F_WRLCK)) | |
636c94d8 CV |
1278 | { |
1279 | /* Open the event object for synchronization. */ | |
1280 | if (!overlap->open_lock_obj () || (overlap->lf_flags & F_POSIX)) | |
1281 | return overlap; | |
1282 | /* In case of BSD flock locks, check if the event object is | |
1283 | signalled. If so, the overlap doesn't actually exist anymore. | |
1284 | There are just a few open handles left. */ | |
1285 | status = NtQueryEvent (overlap->lf_obj, EventBasicInformation, | |
1286 | &ebi, sizeof ebi, NULL); | |
1287 | if (!NT_SUCCESS (status) || ebi.SignalState == 0) | |
1288 | return overlap; | |
1289 | NtClose (overlap->lf_obj); | |
1290 | overlap->lf_obj = NULL; | |
1291 | } | |
a998dd70 CV |
1292 | /* |
1293 | * Nope, point to the next one on the list and | |
1294 | * see if it blocks us | |
1295 | */ | |
1296 | lf = overlap->lf_next; | |
1297 | } | |
1298 | return NOLOCKF; | |
1299 | } | |
1300 | ||
1301 | /* | |
1302 | * Walk the list of locks for an inode_t to | |
1303 | * find an overlapping lock (if any). | |
1304 | * | |
1305 | * NOTE: this returns only the FIRST overlapping lock. There | |
1306 | * may be more than one. | |
025c1fac | 1307 | */ |
a998dd70 CV |
1308 | static int |
1309 | lf_findoverlap (lockf_t *lf, lockf_t *lock, int type, lockf_t ***prev, | |
1310 | lockf_t **overlap) | |
1311 | { | |
1312 | _off64_t start, end; | |
1313 | ||
1314 | *overlap = lf; | |
1315 | if (lf == NOLOCKF) | |
1316 | return 0; | |
1317 | ||
1318 | start = lock->lf_start; | |
1319 | end = lock->lf_end; | |
1320 | while (lf != NOLOCKF) | |
1321 | { | |
a74869c0 CV |
1322 | if (((type & SELF) && lf->lf_id != lock->lf_id) |
1323 | || ((type & OTHERS) && lf->lf_id == lock->lf_id) | |
636c94d8 | 1324 | /* As on Linux: POSIX locks and BSD flock locks don't interact. */ |
072030c3 CV |
1325 | || (lf->lf_flags & (F_POSIX | F_FLOCK)) |
1326 | != (lock->lf_flags & (F_POSIX | F_FLOCK))) | |
a998dd70 CV |
1327 | { |
1328 | *prev = &lf->lf_next; | |
1329 | *overlap = lf = lf->lf_next; | |
1330 | continue; | |
025c1fac | 1331 | } |
a998dd70 CV |
1332 | /* |
1333 | * OK, check for overlap | |
1334 | * | |
1335 | * Six cases: | |
1336 | * 0) no overlap | |
1337 | * 1) overlap == lock | |
1338 | * 2) overlap contains lock | |
1339 | * 3) lock contains overlap | |
1340 | * 4) overlap starts before lock | |
1341 | * 5) overlap ends after lock | |
1342 | */ | |
1343 | if ((lf->lf_end != -1 && start > lf->lf_end) || | |
1344 | (end != -1 && lf->lf_start > end)) | |
1345 | { | |
1346 | /* Case 0 */ | |
1347 | if ((type & SELF) && end != -1 && lf->lf_start > end) | |
1348 | return 0; | |
1349 | *prev = &lf->lf_next; | |
1350 | *overlap = lf = lf->lf_next; | |
1351 | continue; | |
025c1fac | 1352 | } |
a998dd70 CV |
1353 | if ((lf->lf_start == start) && (lf->lf_end == end)) |
1354 | { | |
1355 | /* Case 1 */ | |
1356 | return 1; | |
1357 | } | |
1358 | if ((lf->lf_start <= start) && (end != -1) && | |
1359 | ((lf->lf_end >= end) || (lf->lf_end == -1))) | |
1360 | { | |
1361 | /* Case 2 */ | |
1362 | return 2; | |
1363 | } | |
1364 | if (start <= lf->lf_start && (end == -1 || | |
1365 | (lf->lf_end != -1 && end >= lf->lf_end))) | |
1366 | { | |
1367 | /* Case 3 */ | |
1368 | return 3; | |
1369 | } | |
1370 | if ((lf->lf_start < start) && | |
1371 | ((lf->lf_end >= start) || (lf->lf_end == -1))) | |
1372 | { | |
1373 | /* Case 4 */ | |
1374 | return 4; | |
1375 | } | |
1376 | if ((lf->lf_start > start) && (end != -1) && | |
1377 | ((lf->lf_end > end) || (lf->lf_end == -1))) | |
1378 | { | |
1379 | /* Case 5 */ | |
1380 | return 5; | |
1381 | } | |
1382 | api_fatal ("lf_findoverlap: default\n"); | |
1383 | } | |
1384 | return 0; | |
1385 | } | |
1386 | ||
1387 | /* | |
1388 | * Split a lock and a contained region into | |
1389 | * two or three locks as necessary. | |
1390 | */ | |
1391 | static void | |
1392 | lf_split (lockf_t *lock1, lockf_t *lock2, lockf_t **split) | |
1393 | { | |
1394 | lockf_t *splitlock; | |
1395 | ||
025c1fac | 1396 | /* |
a998dd70 CV |
1397 | * Check to see if spliting into only two pieces. |
1398 | */ | |
1399 | if (lock1->lf_start == lock2->lf_start) | |
1400 | { | |
1401 | lock1->lf_start = lock2->lf_end + 1; | |
1402 | lock2->lf_next = lock1; | |
1403 | return; | |
1404 | } | |
1405 | if (lock1->lf_end == lock2->lf_end) | |
1406 | { | |
1407 | lock1->lf_end = lock2->lf_start - 1; | |
1408 | lock2->lf_next = lock1->lf_next; | |
1409 | lock1->lf_next = lock2; | |
1410 | return; | |
1411 | } | |
1412 | /* | |
1413 | * Make a new lock consisting of the last part of | |
1414 | * the encompassing lock. We use the preallocated | |
1415 | * splitlock so we don't have to block. | |
1416 | */ | |
1417 | splitlock = *split; | |
1418 | assert (splitlock != NULL); | |
1419 | *split = splitlock->lf_next; | |
1420 | memcpy (splitlock, lock1, sizeof *splitlock); | |
1421 | /* We have to unset the obj HANDLE here which has been copied by the | |
1422 | above memcpy, so that the calling function recognizes the new object. | |
1423 | See post-lf_split handling in lf_setlock and lf_clearlock. */ | |
1424 | splitlock->lf_obj = NULL; | |
1425 | splitlock->lf_start = lock2->lf_end + 1; | |
1426 | lock1->lf_end = lock2->lf_start - 1; | |
1427 | /* | |
1428 | * OK, now link it in | |
1429 | */ | |
1430 | splitlock->lf_next = lock1->lf_next; | |
1431 | lock2->lf_next = splitlock; | |
1432 | lock1->lf_next = lock2; | |
1433 | } | |
1434 | ||
1435 | /* | |
1436 | * Wakeup a blocklist | |
1437 | * Cygwin: Just signal the lock which gets removed. This unblocks | |
1438 | * all threads waiting for this lock. | |
1439 | */ | |
1440 | static void | |
636c94d8 | 1441 | lf_wakelock (lockf_t *listhead, HANDLE fhdl) |
a998dd70 | 1442 | { |
636c94d8 | 1443 | listhead->del_lock_obj (fhdl, true); |
a998dd70 | 1444 | } |
f3a1e23e | 1445 | |
fabfb1a1 | 1446 | extern "C" int |
f3a1e23e CV |
1447 | flock (int fd, int operation) |
1448 | { | |
fabfb1a1 CV |
1449 | int res = -1; |
1450 | int cmd; | |
1451 | struct __flock64 fl = { 0, SEEK_SET, 0, 0, 0 }; | |
1452 | ||
1453 | myfault efault; | |
1454 | if (efault.faulted (EFAULT)) | |
1455 | return -1; | |
1456 | ||
1457 | cygheap_fdget cfd (fd, true); | |
1458 | if (cfd < 0) | |
1459 | goto done; | |
1460 | ||
1461 | cmd = (operation & LOCK_NB) ? F_SETLK : F_SETLKW; | |
f3a1e23e CV |
1462 | switch (operation & (~LOCK_NB)) |
1463 | { | |
1464 | case LOCK_EX: | |
fabfb1a1 | 1465 | fl.l_type = F_WRLCK | F_FLOCK; |
f3a1e23e CV |
1466 | break; |
1467 | case LOCK_SH: | |
fabfb1a1 | 1468 | fl.l_type = F_RDLCK | F_FLOCK; |
f3a1e23e CV |
1469 | break; |
1470 | case LOCK_UN: | |
fabfb1a1 | 1471 | fl.l_type = F_UNLCK | F_FLOCK; |
f3a1e23e CV |
1472 | break; |
1473 | default: | |
e2a39e2e | 1474 | set_errno (EINVAL); |
fabfb1a1 | 1475 | goto done; |
f3a1e23e | 1476 | } |
fabfb1a1 | 1477 | res = cfd->lock (cmd, &fl); |
7b9e380f | 1478 | if ((res == -1) && ((get_errno () == EAGAIN) || (get_errno () == EACCES))) |
fabfb1a1 CV |
1479 | set_errno (EWOULDBLOCK); |
1480 | done: | |
1481 | syscall_printf ("%d = flock (%d, %d)", res, fd, operation); | |
1482 | return res; | |
f3a1e23e CV |
1483 | } |
1484 | ||
a998dd70 CV |
1485 | extern "C" int |
1486 | lockf (int filedes, int function, _off64_t size) | |
f3a1e23e | 1487 | { |
fabfb1a1 | 1488 | int res = -1; |
a998dd70 | 1489 | int cmd; |
fabfb1a1 CV |
1490 | struct __flock64 fl; |
1491 | ||
1492 | myfault efault; | |
1493 | if (efault.faulted (EFAULT)) | |
1494 | return -1; | |
1495 | ||
1496 | cygheap_fdget cfd (filedes, true); | |
1497 | if (cfd < 0) | |
1498 | goto done; | |
a998dd70 CV |
1499 | |
1500 | fl.l_start = 0; | |
1501 | fl.l_len = size; | |
1502 | fl.l_whence = SEEK_CUR; | |
1503 | ||
1504 | switch (function) | |
1505 | { | |
1506 | case F_ULOCK: | |
1507 | cmd = F_SETLK; | |
1508 | fl.l_type = F_UNLCK; | |
1509 | break; | |
1510 | case F_LOCK: | |
1511 | cmd = F_SETLKW; | |
1512 | fl.l_type = F_WRLCK; | |
1513 | break; | |
1514 | case F_TLOCK: | |
1515 | cmd = F_SETLK; | |
1516 | fl.l_type = F_WRLCK; | |
1517 | break; | |
1518 | case F_TEST: | |
1519 | fl.l_type = F_WRLCK; | |
fabfb1a1 CV |
1520 | if (cfd->lock (F_GETLK, &fl) == -1) |
1521 | goto done; | |
a998dd70 | 1522 | if (fl.l_type == F_UNLCK || fl.l_pid == getpid ()) |
fabfb1a1 CV |
1523 | res = 0; |
1524 | else | |
1525 | errno = EAGAIN; | |
1526 | goto done; | |
a998dd70 CV |
1527 | /* NOTREACHED */ |
1528 | default: | |
1529 | errno = EINVAL; | |
fabfb1a1 | 1530 | goto done; |
a998dd70 CV |
1531 | /* NOTREACHED */ |
1532 | } | |
fabfb1a1 CV |
1533 | res = cfd->lock (cmd, &fl); |
1534 | done: | |
1535 | syscall_printf ("%d = lockf (%d, %d, %D)", res, filedes, function, size); | |
1536 | return res; | |
f3a1e23e | 1537 | } |