Cygwin: (mostly) drop NT4 and Samba < 3.0 support
[newlib-cygwin.git] / winsup / cygwin / flock.cc
blob0f1efa01d45e6b974e50aa682d560f671d6604ce
1 /* flock.cc. NT specific implementation of advisory file locking.
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
9 /* The basic mechanism as well as the datastructures used in the below
10 implementation are taken from the FreeBSD repository on 2008-03-18.
11 The essential code of the lf_XXX functions has been taken from the
12 module src/sys/kern/kern_lockf.c. It has been adapted to use NT
13 global namespace subdirs and event objects for synchronization
14 purposes.
16 So, the following copyright applies to most of the code in the lf_XXX
17 functions.
19 * Copyright (c) 1982, 1986, 1989, 1993
20 * The Regents of the University of California. All rights reserved.
22 * This code is derived from software contributed to Berkeley by
23 * Scooter Morris at Genentech Inc.
25 * Redistribution and use in source and binary forms, with or without
26 * modification, are permitted provided that the following conditions
27 * are met:
28 * 1. Redistributions of source code must retain the above copyright
29 * notice, this list of conditions and the following disclaimer.
30 * 2. Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in the
32 * documentation and/or other materials provided with the distribution.
33 * 4. Neither the name of the University nor the names of its contributors
34 * may be used to endorse or promote products derived from this software
35 * without specific prior written permission.
37 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
49 * @(#)ufs_lockf.c 8.3 (Berkeley) 1/6/94
53 * The flock() function is based upon source taken from the Red Hat
54 * implementation used in their imap-2002d SRPM.
56 * $RH: flock.c,v 1.2 2000/08/23 17:07:00 nalin Exp $
59 /* The lockf function is based upon FreeBSD sources with the following
60 * copyright.
63 * Copyright (c) 1997 The NetBSD Foundation, Inc.
64 * All rights reserved.
66 * This code is derived from software contributed to The NetBSD Foundation
67 * by Klaus Klein.
69 * Redistribution and use in source and binary forms, with or without
70 * modification, are permitted provided that the following conditions
71 * are met:
72 * 1. Redistributions of source code must retain the above copyright
73 * notice, this list of conditions and the following disclaimer.
74 * 2. Redistributions in binary form must reproduce the above copyright
75 * notice, this list of conditions and the following disclaimer in the
76 * documentation and/or other materials provided with the distribution.
78 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
79 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
80 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
81 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
82 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
83 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
84 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
85 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
86 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
87 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
88 * POSSIBILITY OF SUCH DAMAGE.
91 #include "winsup.h"
92 #include <assert.h>
93 #include <sys/file.h>
94 #include <unistd.h>
95 #include <stdlib.h>
96 #include "cygerrno.h"
97 #include "security.h"
98 #include "shared_info.h"
99 #include "path.h"
100 #include "fhandler.h"
101 #include "dtable.h"
102 #include "cygheap.h"
103 #include "pinfo.h"
104 #include "sigproc.h"
105 #include "cygtls.h"
106 #include "tls_pbuf.h"
107 #include "miscfuncs.h"
108 #include "ntdll.h"
109 #include <sys/queue.h>
110 #include <wchar.h>
112 #define F_WAIT 0x10 /* Wait until lock is granted */
113 #define F_FLOCK 0x20 /* Use flock(2) semantics for lock */
114 #define F_POSIX 0x40 /* Use POSIX semantics for lock */
116 #ifndef OFF_MAX
117 #define OFF_MAX LLONG_MAX
118 #endif
120 static NO_COPY muto lockf_guard;
122 #define INODE_LIST_LOCK() (lockf_guard.init ("lockf_guard")->acquire ())
123 #define INODE_LIST_UNLOCK() (lockf_guard.release ())
125 #define LOCK_DIR_NAME_FMT L"flock-%08x-%016X"
126 #define LOCK_DIR_NAME_LEN 31 /* Length of the resulting name */
127 #define LOCK_DIR_NAME_DEV_OFF 6 /* Offset to device number */
128 #define LOCK_DIR_NAME_INO_OFF 15 /* Offset to inode number */
130 /* Don't change format without also changing lockf_t::from_obj_name! */
131 #define LOCK_OBJ_NAME_FMT L"%02x-%01x-%016X-%016X-%016X-%08x-%04x"
132 #define LOCK_OBJ_NAME_LEN 69 /* Length of the resulting name */
134 #define FLOCK_INODE_DIR_ACCESS (DIRECTORY_QUERY \
135 | DIRECTORY_TRAVERSE \
136 | DIRECTORY_CREATE_OBJECT \
137 | READ_CONTROL)
139 #define FLOCK_EVENT_ACCESS (EVENT_QUERY_STATE \
140 | SYNCHRONIZE \
141 | READ_CONTROL)
143 /* This function takes the own process security descriptor DACL and adds
144 SYNCHRONIZE permissions for everyone. This allows all processes
145 to wait for this process to die when blocking in a F_SETLKW on a lock
146 which is hold by this process. */
147 static void
148 allow_others_to_sync ()
150 static NO_COPY bool done;
152 if (done)
153 return;
155 NTSTATUS status;
156 PACL dacl;
157 LPVOID ace;
158 ULONG len;
160 /* Get this process DACL. We use a rather small stack buffer here which
161 should be more than sufficient for process ACLs. Can't use tls functions
162 at this point because this gets called during initialization when the tls
163 is not really available. */
164 #define MAX_PROCESS_SD_SIZE 3072
165 PISECURITY_DESCRIPTOR sd = (PISECURITY_DESCRIPTOR) alloca (MAX_PROCESS_SD_SIZE);
166 status = NtQuerySecurityObject (NtCurrentProcess (),
167 DACL_SECURITY_INFORMATION, sd,
168 MAX_PROCESS_SD_SIZE, &len);
169 if (!NT_SUCCESS (status))
171 debug_printf ("NtQuerySecurityObject: %y", status);
172 return;
174 /* Create a valid dacl pointer and set its size to be as big as
175 there's room in the temporary buffer. Note that the descriptor
176 is in self-relative format. */
177 BOOLEAN present, defaulted;
178 RtlGetDaclSecurityDescriptor (sd, &present, &dacl, &defaulted);
179 if (!present) /* If so, dacl has undefined value. */
181 dacl = (PACL) (sd + 1);
182 RtlCreateAcl (dacl, MAX_PROCESS_SD_SIZE - sizeof *sd, ACL_REVISION);
184 else if (dacl == NULL) /* Everyone has all access anyway */
186 done = true;
187 return;
189 else
191 dacl->AclSize = MAX_PROCESS_SD_SIZE - ((PBYTE) dacl - (PBYTE) sd);
193 /* Allow everyone to SYNCHRONIZE with this process. */
194 status = RtlAddAccessAllowedAce (dacl, ACL_REVISION, SYNCHRONIZE,
195 well_known_world_sid);
196 if (!NT_SUCCESS (status))
198 debug_printf ("RtlAddAccessAllowedAce: %y", status);
199 return;
201 /* Set the size of the DACL correctly. */
202 status = RtlFirstFreeAce (dacl, &ace);
203 if (!NT_SUCCESS (status))
205 debug_printf ("RtlFirstFreeAce: %y", status);
206 return;
208 dacl->AclSize = (char *) ace - (char *) dacl;
209 /* Write the DACL back. */
210 status = NtSetSecurityObject (NtCurrentProcess (), DACL_SECURITY_INFORMATION, sd);
211 if (!NT_SUCCESS (status))
213 debug_printf ("NtSetSecurityObject: %y", status);
214 return;
216 done = true;
219 /* Helper struct to construct a local OBJECT_ATTRIBUTES on the stack. */
220 struct lockfattr_t
222 OBJECT_ATTRIBUTES attr;
223 UNICODE_STRING uname;
224 WCHAR name[LOCK_OBJ_NAME_LEN + 1];
227 /* Per lock class. */
228 class lockf_t
230 public:
231 uint16_t lf_flags; /* Semantics: F_POSIX, F_FLOCK, F_WAIT */
232 uint16_t lf_type; /* Lock type: F_RDLCK, F_WRLCK */
233 off_t lf_start; /* Byte # of the start of the lock */
234 off_t lf_end; /* Byte # of the end of the lock (-1=EOF) */
235 int64_t lf_id; /* Cygwin PID for POSIX locks, a unique id per
236 file table entry for BSD flock locks. */
237 DWORD lf_wid; /* Win PID of the resource holding the lock */
238 uint16_t lf_ver; /* Version number of the lock. If a released
239 lock event yet exists because another process
240 is still waiting for it, we use the version
241 field to distinguish old from new locks. */
242 class lockf_t **lf_head; /* Back pointer to the head of the lockf_t list */
243 class inode_t *lf_inode; /* Back pointer to the inode_t */
244 class lockf_t *lf_next; /* Pointer to the next lock on this inode_t */
245 HANDLE lf_obj; /* Handle to the lock event object. */
247 lockf_t ()
248 : lf_flags (0), lf_type (0), lf_start (0), lf_end (0), lf_id (0),
249 lf_wid (0), lf_ver (0), lf_head (NULL), lf_inode (NULL),
250 lf_next (NULL), lf_obj (NULL)
252 lockf_t (class inode_t *node, class lockf_t **head,
253 short flags, short type, off_t start, off_t end,
254 long long id, DWORD wid, uint16_t ver)
255 : lf_flags (flags), lf_type (type), lf_start (start), lf_end (end),
256 lf_id (id), lf_wid (wid), lf_ver (ver), lf_head (head), lf_inode (node),
257 lf_next (NULL), lf_obj (NULL)
259 ~lockf_t ();
261 bool from_obj_name (class inode_t *node, class lockf_t **head,
262 const wchar_t *name);
264 /* Used to create all locks list in a given TLS buffer. */
265 void *operator new (size_t size, void *p)
266 { return p; }
267 /* Used to store own lock list in the cygheap. */
268 void *operator new (size_t size)
269 { return cmalloc (HEAP_FHANDLER, sizeof (lockf_t)); }
270 /* Never call on node->i_all_lf! */
271 void operator delete (void *p)
272 { cfree (p); }
274 POBJECT_ATTRIBUTES create_lock_obj_attr (lockfattr_t *attr,
275 ULONG flags, void *sd_buf);
277 void create_lock_obj ();
278 bool open_lock_obj ();
279 void close_lock_obj () { NtClose (lf_obj); lf_obj = NULL; }
280 void del_lock_obj (HANDLE fhdl, bool signal = false);
283 /* Per inode_t class */
284 class inode_t
286 friend class lockf_t;
288 public:
289 LIST_ENTRY (inode_t) i_next;
290 lockf_t *i_lockf; /* List of locks of this process. */
291 lockf_t *i_all_lf; /* Temp list of all locks for this file. */
293 dev_t i_dev; /* Device ID */
294 ino_t i_ino; /* inode number */
296 private:
297 HANDLE i_dir;
298 HANDLE i_mtx;
299 uint32_t i_cnt; /* # of threads referencing this instance. */
301 public:
302 inode_t (dev_t dev, ino_t ino);
303 ~inode_t ();
305 void *operator new (size_t size)
306 { return cmalloc (HEAP_FHANDLER, sizeof (inode_t)); }
307 void operator delete (void *p)
308 { cfree (p); }
310 static inode_t *get (dev_t dev, ino_t ino,
311 bool create_if_missing, bool lock);
313 void LOCK () { WaitForSingleObject (i_mtx, INFINITE); }
314 void UNLOCK () { ReleaseMutex (i_mtx); }
316 void use () { ++i_cnt; }
317 void unuse () { if (i_cnt > 0) --i_cnt; }
318 bool inuse () { return i_cnt > 0; }
319 void notused () { i_cnt = 0; }
321 void unlock_and_remove_if_unused ();
323 lockf_t *get_all_locks_list ();
325 bool del_my_locks (long long id, HANDLE fhdl);
328 inode_t::~inode_t ()
330 lockf_t *lock, *n_lock;
331 for (lock = i_lockf; lock && (n_lock = lock->lf_next, 1); lock = n_lock)
332 delete lock;
333 NtClose (i_mtx);
334 NtClose (i_dir);
337 void
338 inode_t::unlock_and_remove_if_unused ()
340 UNLOCK ();
341 INODE_LIST_LOCK ();
342 unuse ();
343 if (i_lockf == NULL && !inuse ())
345 LIST_REMOVE (this, i_next);
346 delete this;
348 INODE_LIST_UNLOCK ();
351 bool
352 inode_t::del_my_locks (long long id, HANDLE fhdl)
354 lockf_t *lock, *n_lock;
355 lockf_t **prev = &i_lockf;
356 for (lock = *prev; lock && (n_lock = lock->lf_next, 1); lock = n_lock)
358 if (lock->lf_flags & F_POSIX)
360 /* Delete all POSIX locks. */
361 *prev = n_lock;
362 /* When called during fork, the POSIX lock must get deleted but
363 *not* signalled. The lock is still active and locked in the
364 parent. So in case of fork, we call close_lock_obj explicitely,
365 since del_lock_obj is called from the destructor. */
366 if (!id)
367 lock->close_lock_obj ();
368 delete lock;
370 else if (id && lock->lf_id == id)
372 int cnt = 0;
373 cygheap_fdenum cfd (true);
374 while (cfd.next () >= 0)
375 if (cfd->get_unique_id () == lock->lf_id && ++cnt > 1)
376 break;
377 /* Delete BSD flock lock when no other fd in this process references
378 it anymore. */
379 if (cnt <= 1)
381 *prev = n_lock;
382 lock->del_lock_obj (fhdl);
383 delete lock;
386 else
387 prev = &lock->lf_next;
389 return i_lockf == NULL;
392 /* Used to delete the locks on a file hold by this process. Called from
393 close(2) and fixup_after_fork, as well as from fixup_after_exec in
394 case the close_on_exec flag is set. The whole inode is deleted as
395 soon as no lock exists on it anymore. */
396 void
397 fhandler_base::del_my_locks (del_lock_called_from from)
399 inode_t *node = inode_t::get (get_dev (), get_ino (), false, true);
400 if (node)
402 /* When we're called from fixup_after_exec, the fhandler is a
403 close-on-exec fhandler. In this case our io handle is already
404 invalid. We can't use it to test for the object reference count.
405 However, that shouldn't be necessary for the following reason.
406 After exec, there are no threads in the current process waiting for
407 the lock. So, either we're the only process accessing the file table
408 entry and there are no threads which require signalling, or we have
409 a parent process still accessing the file object and signalling the
410 lock event would be premature. */
411 node->del_my_locks (from == after_fork ? 0 : get_unique_id (),
412 from == after_exec ? NULL : get_handle ());
413 node->unlock_and_remove_if_unused ();
417 /* Called in an execed child. The exec'ed process must allow SYNCHRONIZE
418 access to everyone if at least one inode exists.
419 The lock owner's Windows PID changed and all POSIX lock event objects
420 have to be relabeled so that waiting processes know which process to
421 wait on. If the node has been abandoned due to close_on_exec on the
422 referencing fhandlers, remove the inode entirely. */
423 void
424 fixup_lockf_after_exec (bool exec)
426 inode_t *node, *next_node;
428 INODE_LIST_LOCK ();
429 if (LIST_FIRST (&cygheap->inode_list))
430 allow_others_to_sync ();
431 LIST_FOREACH_SAFE (node, &cygheap->inode_list, i_next, next_node)
433 node->notused ();
434 int cnt = 0;
435 cygheap_fdenum cfd (true);
436 while (cfd.next () >= 0)
437 if (cfd->get_dev () == node->i_dev
438 && cfd->get_ino () == node->i_ino
439 && ++cnt >= 1)
440 break;
441 if (cnt == 0)
443 LIST_REMOVE (node, i_next);
444 delete node;
446 else
448 node->LOCK ();
449 lockf_t *lock, *n_lock;
450 lockf_t **prev = &node->i_lockf;
451 for (lock = *prev; lock && (n_lock = lock->lf_next, 1); lock = n_lock)
452 if (lock->lf_flags & F_POSIX)
454 if (exec)
456 /* The parent called exec. The lock is passed to the child.
457 Recreate lock object with changed ownership. */
458 lock->del_lock_obj (NULL);
459 lock->lf_wid = myself->dwProcessId;
460 lock->lf_ver = 0;
461 lock->create_lock_obj ();
463 else
465 /* The parent called spawn. The parent continues to hold
466 the POSIX lock, ownership is not passed to the child.
467 Give up the lock in the child. */
468 *prev = n_lock;
469 lock->close_lock_obj ();
470 delete lock;
473 node->UNLOCK ();
476 INODE_LIST_UNLOCK ();
479 /* static method to return a pointer to the inode_t structure for a specific
480 file. The file is specified by the device and inode_t number. If inode_t
481 doesn't exist, create it. */
482 inode_t *
483 inode_t::get (dev_t dev, ino_t ino, bool create_if_missing, bool lock)
485 inode_t *node;
487 INODE_LIST_LOCK ();
488 LIST_FOREACH (node, &cygheap->inode_list, i_next)
489 if (node->i_dev == dev && node->i_ino == ino)
490 break;
491 if (!node && create_if_missing)
493 node = new inode_t (dev, ino);
494 if (node)
495 LIST_INSERT_HEAD (&cygheap->inode_list, node, i_next);
497 if (node)
498 node->use ();
499 INODE_LIST_UNLOCK ();
500 if (node && lock)
501 node->LOCK ();
502 return node;
505 inode_t::inode_t (dev_t dev, ino_t ino)
506 : i_lockf (NULL), i_all_lf (NULL), i_dev (dev), i_ino (ino), i_cnt (0L)
508 HANDLE parent_dir;
509 WCHAR name[48];
510 UNICODE_STRING uname;
511 OBJECT_ATTRIBUTES attr;
512 NTSTATUS status;
514 parent_dir = get_shared_parent_dir ();
515 /* Create a subdir which is named after the device and inode_t numbers
516 of the given file, in hex notation. */
517 int len = __small_swprintf (name, LOCK_DIR_NAME_FMT, dev, ino);
518 RtlInitCountedUnicodeString (&uname, name, len * sizeof (WCHAR));
519 InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF,
520 parent_dir, everyone_sd (FLOCK_INODE_DIR_ACCESS));
521 status = NtCreateDirectoryObject (&i_dir, FLOCK_INODE_DIR_ACCESS, &attr);
522 if (!NT_SUCCESS (status))
523 api_fatal ("NtCreateDirectoryObject(inode): %y", status);
524 /* Create a mutex object in the file specific dir, which is used for
525 access synchronization on the dir and its objects. */
526 InitializeObjectAttributes (&attr, &ro_u_mtx, OBJ_INHERIT | OBJ_OPENIF, i_dir,
527 everyone_sd (CYG_MUTANT_ACCESS));
528 status = NtCreateMutant (&i_mtx, CYG_MUTANT_ACCESS, &attr, FALSE);
529 if (!NT_SUCCESS (status))
530 api_fatal ("NtCreateMutant(inode): %y", status);
533 /* Enumerate all lock event objects for this file and create a lockf_t
534 list in the i_all_lf member. This list is searched in lf_getblock
535 for locks which potentially block our lock request. */
537 /* Number of lockf_t structs which fit in the temporary buffer. */
538 #define MAX_LOCKF_CNT ((intptr_t)((NT_MAX_PATH * sizeof (WCHAR)) \
539 / sizeof (lockf_t)))
541 bool
542 lockf_t::from_obj_name (inode_t *node, lockf_t **head, const wchar_t *name)
544 wchar_t *endptr;
546 /* "%02x-%01x-%016X-%016X-%016X-%08x-%04x",
547 lf_flags, lf_type, lf_start, lf_end, lf_id, lf_wid, lf_ver */
548 lf_flags = wcstol (name, &endptr, 16);
549 if ((lf_flags & ~(F_FLOCK | F_POSIX)) != 0
550 || ((lf_flags & (F_FLOCK | F_POSIX)) == (F_FLOCK | F_POSIX)))
551 return false;
552 lf_type = wcstol (endptr + 1, &endptr, 16);
553 if ((lf_type != F_RDLCK && lf_type != F_WRLCK) || !endptr || *endptr != L'-')
554 return false;
555 lf_start = (off_t) wcstoull (endptr + 1, &endptr, 16);
556 if (lf_start < 0 || !endptr || *endptr != L'-')
557 return false;
558 lf_end = (off_t) wcstoull (endptr + 1, &endptr, 16);
559 if (lf_end < -1LL
560 || (lf_end > 0 && lf_end < lf_start)
561 || !endptr || *endptr != L'-')
562 return false;
563 lf_id = wcstoll (endptr + 1, &endptr, 16);
564 if (!endptr || *endptr != L'-'
565 || ((lf_flags & F_POSIX) && (lf_id < 1 || lf_id > UINT32_MAX)))
566 return false;
567 lf_wid = wcstoul (endptr + 1, &endptr, 16);
568 if (!endptr || *endptr != L'-')
569 return false;
570 lf_ver = wcstoul (endptr + 1, &endptr, 16);
571 if (endptr && *endptr != L'\0')
572 return false;
573 lf_head = head;
574 lf_inode = node;
575 lf_next = NULL;
576 lf_obj = NULL;
577 return true;
580 lockf_t *
581 inode_t::get_all_locks_list ()
583 tmp_pathbuf tp;
584 ULONG context;
585 NTSTATUS status;
586 BOOLEAN restart = TRUE;
587 bool last_run = false;
588 lockf_t newlock, *lock = i_all_lf;
590 PDIRECTORY_BASIC_INFORMATION dbi_buf = (PDIRECTORY_BASIC_INFORMATION)
591 tp.w_get ();
592 while (!last_run)
594 status = NtQueryDirectoryObject (i_dir, dbi_buf, 65536, FALSE, restart,
595 &context, NULL);
596 if (!NT_SUCCESS (status))
598 debug_printf ("NtQueryDirectoryObject, status %y", status);
599 break;
601 if (status != STATUS_MORE_ENTRIES)
602 last_run = true;
603 restart = FALSE;
604 for (PDIRECTORY_BASIC_INFORMATION dbi = dbi_buf;
605 dbi->ObjectName.Length > 0;
606 dbi++)
608 if (dbi->ObjectName.Length != LOCK_OBJ_NAME_LEN * sizeof (WCHAR))
609 continue;
610 dbi->ObjectName.Buffer[LOCK_OBJ_NAME_LEN] = L'\0';
611 if (!newlock.from_obj_name (this, &i_all_lf, dbi->ObjectName.Buffer))
612 continue;
613 if (lock - i_all_lf >= MAX_LOCKF_CNT)
615 system_printf ("Warning, can't handle more than %d locks per file.",
616 MAX_LOCKF_CNT);
617 break;
619 if (lock > i_all_lf)
620 lock[-1].lf_next = lock;
621 new (lock++) lockf_t (newlock);
624 /* If no lock has been found, return NULL. */
625 if (lock == i_all_lf)
626 return NULL;
627 return i_all_lf;
630 /* Create the lock object name. The name is constructed from the lock
631 properties which identify it uniquely, all values in hex. */
632 POBJECT_ATTRIBUTES
633 lockf_t::create_lock_obj_attr (lockfattr_t *attr, ULONG flags, void *sd_buf)
635 __small_swprintf (attr->name, LOCK_OBJ_NAME_FMT,
636 lf_flags & (F_POSIX | F_FLOCK), lf_type, lf_start, lf_end,
637 lf_id, lf_wid, lf_ver);
638 RtlInitCountedUnicodeString (&attr->uname, attr->name,
639 LOCK_OBJ_NAME_LEN * sizeof (WCHAR));
640 InitializeObjectAttributes (&attr->attr, &attr->uname, flags, lf_inode->i_dir,
641 _everyone_sd (sd_buf, FLOCK_EVENT_ACCESS));
642 return &attr->attr;
645 DWORD
646 create_lock_in_parent (PVOID param)
648 HANDLE lf_obj;
649 ULONG size;
650 OBJECT_NAME_INFORMATION *ntfn;
651 NTSTATUS status;
652 wchar_t *lockname, *inodename, *endptr;
653 dev_t dev;
654 ino_t ino;
655 inode_t *node;
656 lockf_t newlock, *lock;
657 int cnt;
659 /* param is the handle to the lock object, created by caller. */
660 lf_obj = (HANDLE) param;
661 /* Fetch object path from handle. Typically the length of the path
662 is 146 characters, starting with
663 "\BaseNamedObject\cygwin-1S5-<16-hex-digits>\..." */
664 size = sizeof (OBJECT_NAME_INFORMATION) + 256 * sizeof (WCHAR);
665 ntfn = (OBJECT_NAME_INFORMATION *) alloca (size);
666 memset (ntfn, 0, size);
667 status = NtQueryObject (lf_obj, ObjectNameInformation, ntfn, size, &size);
668 if (!NT_SUCCESS (status))
669 goto err;
670 ntfn->Name.Buffer[ntfn->Name.Length / sizeof (WCHAR)] = L'\0';
671 /* Sanity check so that we don't peek into unchartered territory. */
672 if (ntfn->Name.Length < LOCK_OBJ_NAME_LEN + LOCK_DIR_NAME_LEN + 1)
673 goto err;
674 /* The names have fixed size, so we know where the substrings start. */
675 lockname = ntfn->Name.Buffer + ntfn->Name.Length / sizeof (WCHAR)
676 - LOCK_OBJ_NAME_LEN;
677 inodename = lockname - LOCK_DIR_NAME_LEN - 1;
678 dev = wcstoul (inodename + LOCK_DIR_NAME_DEV_OFF, &endptr, 16);
679 if (*endptr != L'-')
680 goto err;
681 ino = wcstoull (inodename + LOCK_DIR_NAME_INO_OFF, &endptr, 16);
682 if (*endptr != L'\\')
683 goto err;
684 if (!newlock.from_obj_name (NULL, NULL, lockname))
685 goto err;
686 /* Check if we have an open file handle with the same unique id. */
688 cnt = 0;
689 cygheap_fdenum cfd (true);
690 while (cfd.next () >= 0)
691 if (cfd->get_unique_id () == newlock.lf_id && ++cnt > 0)
692 break;
694 /* If not, close handle and return. */
695 if (!cnt)
697 NtClose (lf_obj);
698 return 0;
700 /* The handle gets created non-inheritable. That's fine, unless the parent
701 starts another process accessing this object. So, after it's clear we
702 have to store the handle for further use, make sure it gets inheritable
703 by child processes. */
704 if (!SetHandleInformation (lf_obj, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
705 goto err;
706 /* otherwise generate inode from directory name... */
707 node = inode_t::get (dev, ino, true, false);
708 /* ...and generate lock from object name. */
709 lock = new lockf_t (newlock);
710 lock->lf_inode = node;
711 lock->lf_head = &node->i_lockf;
712 lock->lf_next = node->i_lockf;
713 lock->lf_obj = lf_obj;
714 node->i_lockf = lock;
715 node->unuse ();
716 return 0;
718 err:
719 system_printf ("Adding <%S> lock failed", &ntfn->Name);
720 NtClose (lf_obj);
721 return 1;
724 DWORD
725 delete_lock_in_parent (PVOID param)
727 inode_t *node, *next_node;
728 lockf_t *lock, **prev;
730 /* Scan list of all inodes, and reap stale BSD lock if lf_id matches.
731 Remove inode if empty. */
732 INODE_LIST_LOCK ();
733 LIST_FOREACH_SAFE (node, &cygheap->inode_list, i_next, next_node)
734 if (!node->inuse ())
736 for (prev = &node->i_lockf, lock = *prev; lock; lock = *prev)
738 if ((lock->lf_flags & F_FLOCK) && IsEventSignalled (lock->lf_obj))
740 *prev = lock->lf_next;
741 delete lock;
743 else
744 prev = &lock->lf_next;
746 if (node->i_lockf == NULL)
748 LIST_REMOVE (node, i_next);
749 delete node;
752 INODE_LIST_UNLOCK ();
753 return 0;
756 /* Create the lock event object in the file's subdir in the NT global
757 namespace. */
758 void
759 lockf_t::create_lock_obj ()
761 lockfattr_t attr;
762 NTSTATUS status;
763 PSECURITY_DESCRIPTOR sd_buf = alloca (SD_MIN_SIZE);
764 POBJECT_ATTRIBUTES lock_obj_attr;
768 lock_obj_attr = create_lock_obj_attr (&attr, OBJ_INHERIT, sd_buf);
769 status = NtCreateEvent (&lf_obj, CYG_EVENT_ACCESS, lock_obj_attr,
770 NotificationEvent, FALSE);
771 if (!NT_SUCCESS (status))
773 if (status != STATUS_OBJECT_NAME_COLLISION)
774 api_fatal ("NtCreateEvent(lock): %y", status);
775 /* If we get a STATUS_OBJECT_NAME_COLLISION, the event still exists
776 because some other process is waiting for it in lf_setlock.
777 If so, check the event's signal state. If we can't open it, it
778 has been closed in the meantime, so just try again. If we can
779 open it and the object is not signalled, it's surely a bug in the
780 code somewhere. Otherwise, close the event and retry to create
781 a new event with another name. */
782 if (open_lock_obj ())
784 if (!IsEventSignalled (lf_obj))
785 api_fatal ("NtCreateEvent(lock): %y", status);
786 close_lock_obj ();
787 /* Increment the lf_ver field until we have no collision. */
788 ++lf_ver;
792 while (!NT_SUCCESS (status));
793 /* For BSD locks, notify the parent process. */
794 if (lf_flags & F_FLOCK)
796 HANDLE parent_proc, parent_thread, parent_lf_obj;
798 pinfo p (myself->ppid);
799 if (!p) /* No access or not a Cygwin parent. */
800 return;
802 parent_proc = OpenProcess (PROCESS_DUP_HANDLE
803 | PROCESS_CREATE_THREAD
804 | PROCESS_QUERY_INFORMATION
805 | PROCESS_VM_OPERATION
806 | PROCESS_VM_WRITE
807 | PROCESS_VM_READ,
808 FALSE, p->dwProcessId);
809 if (!parent_proc)
811 debug_printf ("OpenProcess (%u): %E", p->dwProcessId);
812 return;
814 if (!DuplicateHandle (GetCurrentProcess (), lf_obj, parent_proc,
815 &parent_lf_obj, TRUE, FALSE, DUPLICATE_SAME_ACCESS))
816 debug_printf ("DuplicateHandle (lf_obj): %E");
817 else
819 parent_thread = CreateRemoteThread (parent_proc, NULL, 256 * 1024,
820 create_lock_in_parent,
821 parent_lf_obj,
822 STACK_SIZE_PARAM_IS_A_RESERVATION,
823 NULL);
824 if (!parent_thread)
826 debug_printf ("CreateRemoteThread: %E");
827 /* If thread didn't get started, close object handle in parent,
828 otherwise suffer handle leaks. */
829 DuplicateHandle (parent_proc, parent_lf_obj, parent_proc,
830 NULL, 0, FALSE, DUPLICATE_CLOSE_SOURCE);
832 else
834 /* Must wait to avoid race conditions. */
835 WaitForSingleObject (parent_thread, INFINITE);
836 CloseHandle (parent_thread);
839 CloseHandle (parent_proc);
843 /* Open a lock event object for SYNCHRONIZE access (to wait for it). */
844 bool
845 lockf_t::open_lock_obj ()
847 lockfattr_t attr;
848 NTSTATUS status;
850 status = NtOpenEvent (&lf_obj, FLOCK_EVENT_ACCESS,
851 create_lock_obj_attr (&attr, 0, alloca (SD_MIN_SIZE)));
852 if (!NT_SUCCESS (status))
854 SetLastError (RtlNtStatusToDosError (status));
855 lf_obj = NULL; /* Paranoia... */
857 return lf_obj != NULL;
860 /* Delete a lock event handle. The important thing here is to signal it
861 before closing the handle. This way all threads waiting for this lock
862 can wake up. */
863 void
864 lockf_t::del_lock_obj (HANDLE fhdl, bool signal)
866 if (lf_obj)
868 /* Only signal the event if it's either a POSIX lock, or, in case of
869 BSD flock locks, if it's an explicit unlock or if the calling fhandler
870 holds the last reference to the file table entry. The file table
871 entry in UNIX terms is equivalent to the FILE_OBJECT in Windows NT
872 terms. It's what the handle/descriptor references when calling
873 CreateFile/open. Calling DuplicateHandle/dup only creates a new
874 handle/descriptor to the same FILE_OBJECT/file table entry. */
875 if ((lf_flags & F_POSIX) || signal
876 || (fhdl && get_obj_handle_count (fhdl) <= 1))
878 NTSTATUS status = NtSetEvent (lf_obj, NULL);
879 if (!NT_SUCCESS (status))
880 system_printf ("NtSetEvent, %y", status);
881 /* For BSD locks, notify the parent process. */
882 if (lf_flags & F_FLOCK)
884 HANDLE parent_proc, parent_thread;
886 pinfo p (myself->ppid);
887 if (p && (parent_proc = OpenProcess (PROCESS_CREATE_THREAD
888 | PROCESS_QUERY_INFORMATION
889 | PROCESS_VM_OPERATION
890 | PROCESS_VM_WRITE
891 | PROCESS_VM_READ,
892 FALSE, p->dwProcessId)))
894 parent_thread = CreateRemoteThread (parent_proc, NULL,
895 256 * 1024, delete_lock_in_parent,
896 NULL,
897 STACK_SIZE_PARAM_IS_A_RESERVATION,
898 NULL);
899 if (parent_thread)
901 /* Must wait to avoid race conditions. */
902 WaitForSingleObject (parent_thread, INFINITE);
903 CloseHandle (parent_thread);
905 CloseHandle (parent_proc);
909 close_lock_obj ();
913 lockf_t::~lockf_t ()
915 del_lock_obj (NULL);
919 * This variable controls the maximum number of processes that will
920 * be checked in doing deadlock detection.
922 #ifndef __CYGWIN__
923 #define MAXDEPTH 50
924 static int maxlockdepth = MAXDEPTH;
925 #endif
927 #define NOLOCKF (struct lockf_t *)0
928 #define SELF 0x1
929 #define OTHERS 0x2
930 static int lf_clearlock (lockf_t *, lockf_t **, HANDLE);
931 static int lf_findoverlap (lockf_t *, lockf_t *, int, lockf_t ***, lockf_t **);
932 static lockf_t *lf_getblock (lockf_t *, inode_t *node);
933 static int lf_getlock (lockf_t *, inode_t *, struct flock *);
934 static int lf_setlock (lockf_t *, inode_t *, lockf_t **, HANDLE);
935 static void lf_split (lockf_t *, lockf_t *, lockf_t **);
936 static void lf_wakelock (lockf_t *, HANDLE);
938 /* This is the fcntl advisory lock implementation. For the implementation
939 of mandatory locks using the Windows mandatory locking functions, see the
940 fhandler_disk_file::mand_lock method at the end of this file. */
942 fhandler_base::lock (int a_op, struct flock *fl)
944 off_t start, end, oadd;
945 int error = 0;
947 short a_flags = fl->l_type & (F_POSIX | F_FLOCK);
948 short type = fl->l_type & (F_RDLCK | F_WRLCK | F_UNLCK);
950 if (!a_flags)
951 a_flags = F_POSIX; /* default */
953 /* FIXME: For BSD flock(2) we need a valid, per file table entry OS handle.
954 Therefore we can't allow using flock(2) on nohandle devices. */
955 if ((a_flags & F_FLOCK) && nohandle ())
957 set_errno (EINVAL);
958 debug_printf ("BSD locking on nohandle and old-style console devices "
959 "not supported");
960 return -1;
963 if (a_op == F_SETLKW)
965 a_op = F_SETLK;
966 a_flags |= F_WAIT;
968 if (a_op == F_SETLK)
969 switch (type)
971 case F_UNLCK:
972 a_op = F_UNLCK;
973 break;
974 case F_RDLCK:
975 /* flock semantics don't specify a requirement that the file has
976 been opened with a specific open mode, in contrast to POSIX locks
977 which require that a file is opened for reading to place a read
978 lock and opened for writing to place a write lock. */
979 /* CV 2013-10-22: Test POSIX R/W mode flags rather than Windows R/W
980 access flags. The reason is that POSIX mode flags are set for
981 all types of fhandlers, while Windows access flags are only set
982 for most of the actual Windows device backed fhandlers. */
983 if ((a_flags & F_POSIX)
984 && ((get_flags () & O_ACCMODE) == O_WRONLY))
986 debug_printf ("request F_RDLCK on O_WRONLY file: EBADF");
987 set_errno (EBADF);
988 return -1;
990 break;
991 case F_WRLCK:
992 /* See above comment. */
993 if ((a_flags & F_POSIX)
994 && ((get_flags () & O_ACCMODE) == O_RDONLY))
996 debug_printf ("request F_WRLCK on O_RDONLY file: EBADF");
997 set_errno (EBADF);
998 return -1;
1000 break;
1001 default:
1002 set_errno (EINVAL);
1003 return -1;
1007 * Convert the flock structure into a start and end.
1009 switch (fl->l_whence)
1011 case SEEK_SET:
1012 start = fl->l_start;
1013 break;
1015 case SEEK_CUR:
1016 if ((start = lseek (0, SEEK_CUR)) == ILLEGAL_SEEK)
1017 start = 0;
1018 break;
1020 case SEEK_END:
1021 if (get_device () != FH_FS)
1022 start = 0;
1023 else
1025 NTSTATUS status;
1026 IO_STATUS_BLOCK io;
1027 FILE_STANDARD_INFORMATION fsi;
1029 status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi,
1030 FileStandardInformation);
1031 if (!NT_SUCCESS (status))
1033 __seterrno_from_nt_status (status);
1034 return -1;
1036 if (fl->l_start > 0 && fsi.EndOfFile.QuadPart > OFF_MAX - fl->l_start)
1038 set_errno (EOVERFLOW);
1039 return -1;
1041 start = fsi.EndOfFile.QuadPart + fl->l_start;
1043 break;
1045 default:
1046 return (EINVAL);
1048 if (start < 0)
1050 set_errno (EINVAL);
1051 return -1;
1053 if (fl->l_len < 0)
1055 if (start == 0)
1057 set_errno (EINVAL);
1058 return -1;
1060 end = start - 1;
1061 start += fl->l_len;
1062 if (start < 0)
1064 set_errno (EINVAL);
1065 return -1;
1068 else if (fl->l_len == 0)
1069 end = -1;
1070 else
1072 oadd = fl->l_len - 1;
1073 if (oadd > OFF_MAX - start)
1075 set_errno (EOVERFLOW);
1076 return -1;
1078 end = start + oadd;
1081 restart: /* Entry point after a restartable signal came in. */
1083 inode_t *node = inode_t::get (get_dev (), get_ino (), true, true);
1084 if (!node)
1086 set_errno (ENOLCK);
1087 return -1;
1090 /* Unlock the fd table which has been locked in fcntl_worker/lock_worker,
1091 otherwise a blocking F_SETLKW never wakes up on a signal. */
1092 cygheap->fdtab.unlock ();
1094 lockf_t **head = &node->i_lockf;
1096 #if 0
1098 * Avoid the common case of unlocking when inode_t has no locks.
1100 * This shortcut is invalid for Cygwin because the above inode_t::get
1101 * call returns with an empty lock list if this process has no locks
1102 * on the file yet.
1104 if (*head == NULL)
1106 if (a_op != F_SETLK)
1108 node->UNLOCK ();
1109 fl->l_type = F_UNLCK;
1110 return 0;
1113 #endif
1115 * Allocate a spare structure in case we have to split.
1117 lockf_t *clean = NULL;
1118 if (a_op == F_SETLK || a_op == F_UNLCK)
1120 clean = new lockf_t ();
1121 if (!clean)
1123 node->unlock_and_remove_if_unused ();
1124 set_errno (ENOLCK);
1125 return -1;
1129 * Create the lockf_t structure
1131 lockf_t *lock = new lockf_t (node, head, a_flags, type, start, end,
1132 (a_flags & F_FLOCK) ? get_unique_id ()
1133 : getpid (),
1134 myself->dwProcessId, 0);
1135 if (!lock)
1137 node->unlock_and_remove_if_unused ();
1138 set_errno (ENOLCK);
1139 return -1;
1142 switch (a_op)
1144 case F_SETLK:
1145 error = lf_setlock (lock, node, &clean, get_handle ());
1146 break;
1148 case F_UNLCK:
1149 error = lf_clearlock (lock, &clean, get_handle ());
1150 lock->lf_next = clean;
1151 clean = lock;
1152 break;
1154 case F_GETLK:
1155 error = lf_getlock (lock, node, fl);
1156 lock->lf_next = clean;
1157 clean = lock;
1158 break;
1160 default:
1161 lock->lf_next = clean;
1162 clean = lock;
1163 error = EINVAL;
1164 break;
1166 for (lock = clean; lock != NULL; )
1168 lockf_t *n = lock->lf_next;
1169 lock->del_lock_obj (get_handle (), a_op == F_UNLCK);
1170 delete lock;
1171 lock = n;
1173 node->unlock_and_remove_if_unused ();
1174 switch (error)
1176 case 0: /* All is well. */
1177 need_fork_fixup (true);
1178 return 0;
1179 case EINTR: /* Signal came in. */
1180 if (_my_tls.call_signal_handler ())
1181 goto restart;
1182 break;
1183 case ECANCELED: /* The thread has been sent a cancellation request. */
1184 pthread::static_cancel_self ();
1185 /*NOTREACHED*/
1186 default:
1187 break;
1189 set_errno (error);
1190 return -1;
1194 * Set a byte-range lock.
1196 static int
1197 lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl)
1199 lockf_t *block;
1200 lockf_t **head = lock->lf_head;
1201 lockf_t **prev, *overlap;
1202 int ovcase, priority, old_prio, needtolink;
1203 tmp_pathbuf tp;
1206 * Set the priority
1208 priority = old_prio = GetThreadPriority (GetCurrentThread ());
1209 if (lock->lf_type == F_WRLCK && priority <= THREAD_PRIORITY_ABOVE_NORMAL)
1210 priority = THREAD_PRIORITY_HIGHEST;
1212 * Scan lock list for this file looking for locks that would block us.
1214 /* Create temporary space for the all locks list. */
1215 node->i_all_lf = (lockf_t *) (void *) tp.w_get ();
1216 while ((block = lf_getblock(lock, node)))
1218 HANDLE obj = block->lf_obj;
1219 block->lf_obj = NULL;
1222 * Free the structure and return if nonblocking.
1224 if ((lock->lf_flags & F_WAIT) == 0)
1226 NtClose (obj);
1227 lock->lf_next = *clean;
1228 *clean = lock;
1229 return EAGAIN;
1232 * We are blocked. Since flock style locks cover
1233 * the whole file, there is no chance for deadlock.
1234 * For byte-range locks we must check for deadlock.
1236 * Deadlock detection is done by looking through the
1237 * wait channels to see if there are any cycles that
1238 * involve us. MAXDEPTH is set just to make sure we
1239 * do not go off into neverland.
1241 /* FIXME: We check the handle count of all the lock event objects
1242 this process holds. If it's > 1, another process is
1243 waiting for one of our locks. This method isn't overly
1244 intelligent. If it turns out to be too dumb, we might
1245 have to remove it or to find another method. */
1246 if (lock->lf_flags & F_POSIX)
1247 for (lockf_t *lk = node->i_lockf; lk; lk = lk->lf_next)
1248 if ((lk->lf_flags & F_POSIX) && get_obj_handle_count (lk->lf_obj) > 1)
1250 NtClose (obj);
1251 return EDEADLK;
1255 * For flock type locks, we must first remove
1256 * any shared locks that we hold before we sleep
1257 * waiting for an exclusive lock.
1259 if ((lock->lf_flags & F_FLOCK) && lock->lf_type == F_WRLCK)
1261 lock->lf_type = F_UNLCK;
1262 (void) lf_clearlock (lock, clean, fhdl);
1263 lock->lf_type = F_WRLCK;
1267 * Add our lock to the blocked list and sleep until we're free.
1268 * Remember who blocked us (for deadlock detection).
1270 /* Cygwin: No locked list. See deadlock recognition above. */
1272 node->UNLOCK ();
1274 /* Create list of objects to wait for. */
1275 HANDLE w4[4] = { obj, NULL, NULL, NULL };
1276 DWORD wait_count = 1;
1278 DWORD timeout;
1279 HANDLE proc = NULL;
1280 if (lock->lf_flags & F_POSIX)
1282 proc = OpenProcess (SYNCHRONIZE, FALSE, block->lf_wid);
1283 if (!proc)
1284 timeout = 0L;
1285 else
1287 w4[wait_count++] = proc;
1288 timeout = INFINITE;
1291 else
1292 timeout = 100L;
1294 DWORD WAIT_SIGNAL_ARRIVED = WAIT_OBJECT_0 + wait_count;
1295 wait_signal_arrived here (w4[wait_count++]);
1297 DWORD WAIT_THREAD_CANCELED = WAIT_TIMEOUT + 1;
1298 HANDLE cancel_event = pthread::get_cancel_event ();
1299 if (cancel_event)
1301 WAIT_THREAD_CANCELED = WAIT_OBJECT_0 + wait_count;
1302 w4[wait_count++] = cancel_event;
1305 /* Wait for the blocking object and, for POSIX locks, its holding process.
1306 Unfortunately, since BSD flock locks are not attached to a specific
1307 process, we can't recognize an abandoned lock by sync'ing with the
1308 creator process. We have to make sure the event object is in a
1309 signalled state, or that it has gone away. The latter we can only
1310 recognize by retrying to fetch the block list, so we must not wait
1311 infinitely. For POSIX locks, if the process has already exited,
1312 just check if a signal or a thread cancel request arrived. */
1313 SetThreadPriority (GetCurrentThread (), priority);
1314 DWORD ret = WaitForMultipleObjects (wait_count, w4, FALSE, timeout);
1315 SetThreadPriority (GetCurrentThread (), old_prio);
1316 if (proc)
1317 CloseHandle (proc);
1318 node->LOCK ();
1319 /* Never close lock object handle outside of node lock! */
1320 NtClose (obj);
1321 if (ret == WAIT_SIGNAL_ARRIVED)
1323 /* A signal came in. */
1324 lock->lf_next = *clean;
1325 *clean = lock;
1326 return EINTR;
1328 else if (ret == WAIT_THREAD_CANCELED)
1330 /* The thread has been sent a cancellation request. */
1331 lock->lf_next = *clean;
1332 *clean = lock;
1333 return ECANCELED;
1335 else
1336 /* The lock object has been set to signalled or ...
1337 for POSIX locks, the process holding the lock has exited, or ...
1338 just a timeout. Just retry. */
1339 continue;
1341 allow_others_to_sync ();
1343 * No blocks!! Add the lock. Note that we will
1344 * downgrade or upgrade any overlapping locks this
1345 * process already owns.
1347 * Handle any locks that overlap.
1349 prev = head;
1350 block = *head;
1351 needtolink = 1;
1352 for (;;)
1354 ovcase = lf_findoverlap (block, lock, SELF, &prev, &overlap);
1355 if (ovcase)
1356 block = overlap->lf_next;
1358 * Six cases:
1359 * 0) no overlap
1360 * 1) overlap == lock
1361 * 2) overlap contains lock
1362 * 3) lock contains overlap
1363 * 4) overlap starts before lock
1364 * 5) overlap ends after lock
1366 switch (ovcase)
1368 case 0: /* no overlap */
1369 if (needtolink)
1371 *prev = lock;
1372 lock->lf_next = overlap;
1373 lock->create_lock_obj ();
1375 break;
1377 case 1: /* overlap == lock */
1379 * If downgrading lock, others may be
1380 * able to acquire it.
1381 * Cygwin: Always wake lock.
1383 lf_wakelock (overlap, fhdl);
1384 overlap->lf_type = lock->lf_type;
1385 overlap->create_lock_obj ();
1386 lock->lf_next = *clean;
1387 *clean = lock;
1388 break;
1390 case 2: /* overlap contains lock */
1392 * Check for common starting point and different types.
1394 if (overlap->lf_type == lock->lf_type)
1396 lock->lf_next = *clean;
1397 *clean = lock;
1398 break;
1400 if (overlap->lf_start == lock->lf_start)
1402 *prev = lock;
1403 lock->lf_next = overlap;
1404 overlap->lf_start = lock->lf_end + 1;
1406 else
1407 lf_split (overlap, lock, clean);
1408 lf_wakelock (overlap, fhdl);
1409 overlap->create_lock_obj ();
1410 lock->create_lock_obj ();
1411 if (lock->lf_next && !lock->lf_next->lf_obj)
1412 lock->lf_next->create_lock_obj ();
1413 break;
1415 case 3: /* lock contains overlap */
1417 * If downgrading lock, others may be able to
1418 * acquire it, otherwise take the list.
1419 * Cygwin: Always wake old lock and create new lock.
1421 lf_wakelock (overlap, fhdl);
1423 * Add the new lock if necessary and delete the overlap.
1425 if (needtolink)
1427 *prev = lock;
1428 lock->lf_next = overlap->lf_next;
1429 prev = &lock->lf_next;
1430 lock->create_lock_obj ();
1431 needtolink = 0;
1433 else
1434 *prev = overlap->lf_next;
1435 overlap->lf_next = *clean;
1436 *clean = overlap;
1437 continue;
1439 case 4: /* overlap starts before lock */
1441 * Add lock after overlap on the list.
1443 lock->lf_next = overlap->lf_next;
1444 overlap->lf_next = lock;
1445 overlap->lf_end = lock->lf_start - 1;
1446 prev = &lock->lf_next;
1447 lf_wakelock (overlap, fhdl);
1448 overlap->create_lock_obj ();
1449 lock->create_lock_obj ();
1450 needtolink = 0;
1451 continue;
1453 case 5: /* overlap ends after lock */
1455 * Add the new lock before overlap.
1457 if (needtolink) {
1458 *prev = lock;
1459 lock->lf_next = overlap;
1461 overlap->lf_start = lock->lf_end + 1;
1462 lf_wakelock (overlap, fhdl);
1463 lock->create_lock_obj ();
1464 overlap->create_lock_obj ();
1465 break;
1467 break;
1469 return 0;
1473 * Remove a byte-range lock on an inode_t.
1475 * Generally, find the lock (or an overlap to that lock)
1476 * and remove it (or shrink it), then wakeup anyone we can.
1478 static int
1479 lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl)
1481 lockf_t **head = unlock->lf_head;
1482 lockf_t *lf = *head;
1483 lockf_t *overlap, **prev;
1484 int ovcase;
1486 if (lf == NOLOCKF)
1487 return 0;
1488 prev = head;
1489 while ((ovcase = lf_findoverlap (lf, unlock, SELF, &prev, &overlap)))
1492 * Wakeup the list of locks to be retried.
1494 lf_wakelock (overlap, fhdl);
1496 switch (ovcase)
1498 case 1: /* overlap == lock */
1499 *prev = overlap->lf_next;
1500 overlap->lf_next = *clean;
1501 *clean = overlap;
1502 break;
1504 case 2: /* overlap contains lock: split it */
1505 if (overlap->lf_start == unlock->lf_start)
1507 overlap->lf_start = unlock->lf_end + 1;
1508 overlap->create_lock_obj ();
1509 break;
1511 lf_split (overlap, unlock, clean);
1512 overlap->lf_next = unlock->lf_next;
1513 overlap->create_lock_obj ();
1514 if (overlap->lf_next && !overlap->lf_next->lf_obj)
1515 overlap->lf_next->create_lock_obj ();
1516 break;
1518 case 3: /* lock contains overlap */
1519 *prev = overlap->lf_next;
1520 lf = overlap->lf_next;
1521 overlap->lf_next = *clean;
1522 *clean = overlap;
1523 continue;
1525 case 4: /* overlap starts before lock */
1526 overlap->lf_end = unlock->lf_start - 1;
1527 prev = &overlap->lf_next;
1528 lf = overlap->lf_next;
1529 overlap->create_lock_obj ();
1530 continue;
1532 case 5: /* overlap ends after lock */
1533 overlap->lf_start = unlock->lf_end + 1;
1534 overlap->create_lock_obj ();
1535 break;
1537 break;
1539 return 0;
1543 * Check whether there is a blocking lock,
1544 * and if so return its process identifier.
1546 static int
1547 lf_getlock (lockf_t *lock, inode_t *node, struct flock *fl)
1549 lockf_t *block;
1550 tmp_pathbuf tp;
1552 /* Create temporary space for the all locks list. */
1553 node->i_all_lf = (lockf_t *) (void * ) tp.w_get ();
1554 if ((block = lf_getblock (lock, node)))
1556 if (block->lf_obj)
1557 block->close_lock_obj ();
1558 fl->l_type = block->lf_type;
1559 fl->l_whence = SEEK_SET;
1560 fl->l_start = block->lf_start;
1561 if (block->lf_end == -1)
1562 fl->l_len = 0;
1563 else
1564 fl->l_len = block->lf_end - block->lf_start + 1;
1565 if (block->lf_flags & F_POSIX)
1566 fl->l_pid = (pid_t) block->lf_id;
1567 else
1568 fl->l_pid = -1;
1570 else
1571 fl->l_type = F_UNLCK;
1572 return 0;
1576 * Walk the list of locks for an inode_t and
1577 * return the first blocking lock.
1579 static lockf_t *
1580 lf_getblock (lockf_t *lock, inode_t *node)
1582 lockf_t **prev, *overlap;
1583 lockf_t *lf = node->get_all_locks_list ();
1584 int ovcase;
1586 prev = lock->lf_head;
1587 while ((ovcase = lf_findoverlap (lf, lock, OTHERS, &prev, &overlap)))
1590 * We've found an overlap, see if it blocks us
1592 if ((lock->lf_type == F_WRLCK || overlap->lf_type == F_WRLCK))
1594 /* Open the event object for synchronization. */
1595 if (overlap->open_lock_obj ())
1597 /* Check if the event object is signalled. If so, the overlap
1598 doesn't actually exist anymore. There are just a few open
1599 handles left. */
1600 if (!IsEventSignalled (overlap->lf_obj))
1601 return overlap;
1602 overlap->close_lock_obj ();
1606 * Nope, point to the next one on the list and
1607 * see if it blocks us
1609 lf = overlap->lf_next;
1611 return NOLOCKF;
1615 * Walk the list of locks for an inode_t to
1616 * find an overlapping lock (if any).
1618 * NOTE: this returns only the FIRST overlapping lock. There
1619 * may be more than one.
1621 static int
1622 lf_findoverlap (lockf_t *lf, lockf_t *lock, int type, lockf_t ***prev,
1623 lockf_t **overlap)
1625 off_t start, end;
1627 *overlap = lf;
1628 if (lf == NOLOCKF)
1629 return 0;
1631 start = lock->lf_start;
1632 end = lock->lf_end;
1633 while (lf != NOLOCKF)
1635 if (((type & SELF) && lf->lf_id != lock->lf_id)
1636 || ((type & OTHERS) && lf->lf_id == lock->lf_id)
1637 /* As on Linux: POSIX locks and BSD flock locks don't interact. */
1638 || (lf->lf_flags & (F_POSIX | F_FLOCK))
1639 != (lock->lf_flags & (F_POSIX | F_FLOCK)))
1641 *prev = &lf->lf_next;
1642 *overlap = lf = lf->lf_next;
1643 continue;
1646 * OK, check for overlap
1648 * Six cases:
1649 * 0) no overlap
1650 * 1) overlap == lock
1651 * 2) overlap contains lock
1652 * 3) lock contains overlap
1653 * 4) overlap starts before lock
1654 * 5) overlap ends after lock
1656 if ((lf->lf_end != -1 && start > lf->lf_end) ||
1657 (end != -1 && lf->lf_start > end))
1659 /* Case 0 */
1660 if ((type & SELF) && end != -1 && lf->lf_start > end)
1661 return 0;
1662 *prev = &lf->lf_next;
1663 *overlap = lf = lf->lf_next;
1664 continue;
1666 if ((lf->lf_start == start) && (lf->lf_end == end))
1668 /* Case 1 */
1669 return 1;
1671 if ((lf->lf_start <= start) && (end != -1) &&
1672 ((lf->lf_end >= end) || (lf->lf_end == -1)))
1674 /* Case 2 */
1675 return 2;
1677 if (start <= lf->lf_start && (end == -1 ||
1678 (lf->lf_end != -1 && end >= lf->lf_end)))
1680 /* Case 3 */
1681 return 3;
1683 if ((lf->lf_start < start) &&
1684 ((lf->lf_end >= start) || (lf->lf_end == -1)))
1686 /* Case 4 */
1687 return 4;
1689 if ((lf->lf_start > start) && (end != -1) &&
1690 ((lf->lf_end > end) || (lf->lf_end == -1)))
1692 /* Case 5 */
1693 return 5;
1695 api_fatal ("lf_findoverlap: default\n");
1697 return 0;
1701 * Split a lock and a contained region into
1702 * two or three locks as necessary.
1704 static void
1705 lf_split (lockf_t *lock1, lockf_t *lock2, lockf_t **split)
1707 lockf_t *splitlock;
1710 * Check to see if spliting into only two pieces.
1712 if (lock1->lf_start == lock2->lf_start)
1714 lock1->lf_start = lock2->lf_end + 1;
1715 lock2->lf_next = lock1;
1716 return;
1718 if (lock1->lf_end == lock2->lf_end)
1720 lock1->lf_end = lock2->lf_start - 1;
1721 lock2->lf_next = lock1->lf_next;
1722 lock1->lf_next = lock2;
1723 return;
1726 * Make a new lock consisting of the last part of
1727 * the encompassing lock. We use the preallocated
1728 * splitlock so we don't have to block.
1730 splitlock = *split;
1731 assert (splitlock != NULL);
1732 *split = splitlock->lf_next;
1733 memcpy ((void *) splitlock, lock1, sizeof *splitlock);
1734 /* We have to unset the obj HANDLE here which has been copied by the
1735 above memcpy, so that the calling function recognizes the new object.
1736 See post-lf_split handling in lf_setlock and lf_clearlock. */
1737 splitlock->lf_obj = NULL;
1738 splitlock->lf_start = lock2->lf_end + 1;
1739 lock1->lf_end = lock2->lf_start - 1;
1741 * OK, now link it in
1743 splitlock->lf_next = lock1->lf_next;
1744 lock2->lf_next = splitlock;
1745 lock1->lf_next = lock2;
1749 * Wakeup a blocklist
1750 * Cygwin: Just signal the lock which gets removed. This unblocks
1751 * all threads waiting for this lock.
1753 static void
1754 lf_wakelock (lockf_t *listhead, HANDLE fhdl)
1756 listhead->del_lock_obj (fhdl, true);
1759 extern "C" int
1760 flock (int fd, int operation)
1762 int res = -1;
1763 int cmd;
1764 struct flock fl = { 0, SEEK_SET, 0, 0, 0 };
1766 __try
1768 cygheap_fdget cfd (fd);
1769 if (cfd < 0)
1770 __leave;
1772 cmd = (operation & LOCK_NB) ? F_SETLK : F_SETLKW;
1773 switch (operation & (~LOCK_NB))
1775 case LOCK_EX:
1776 fl.l_type = F_WRLCK;
1777 break;
1778 case LOCK_SH:
1779 fl.l_type = F_RDLCK;
1780 break;
1781 case LOCK_UN:
1782 fl.l_type = F_UNLCK;
1783 break;
1784 default:
1785 set_errno (EINVAL);
1786 __leave;
1788 if (!cfd->mandatory_locking ())
1789 fl.l_type |= F_FLOCK;
1790 res = cfd->mandatory_locking () ? cfd->mand_lock (cmd, &fl)
1791 : cfd->lock (cmd, &fl);
1792 if ((res == -1) && ((get_errno () == EAGAIN) || (get_errno () == EACCES)))
1793 set_errno (EWOULDBLOCK);
1795 __except (EFAULT) {}
1796 __endtry
1797 syscall_printf ("%R = flock(%d, %d)", res, fd, operation);
1798 return res;
1801 extern "C" int
1802 lockf (int filedes, int function, off_t size)
1804 int res = -1;
1805 int cmd;
1806 struct flock fl;
1808 pthread_testcancel ();
1810 __try
1812 cygheap_fdget cfd (filedes);
1813 if (cfd < 0)
1814 __leave;
1816 fl.l_start = 0;
1817 fl.l_len = size;
1818 fl.l_whence = SEEK_CUR;
1820 switch (function)
1822 case F_ULOCK:
1823 cmd = F_SETLK;
1824 fl.l_type = F_UNLCK;
1825 break;
1826 case F_LOCK:
1827 cmd = F_SETLKW;
1828 fl.l_type = F_WRLCK;
1829 break;
1830 case F_TLOCK:
1831 cmd = F_SETLK;
1832 fl.l_type = F_WRLCK;
1833 break;
1834 case F_TEST:
1835 fl.l_type = F_WRLCK;
1836 if (cfd->lock (F_GETLK, &fl) == -1)
1837 __leave;
1838 if (fl.l_type == F_UNLCK || fl.l_pid == getpid ())
1839 res = 0;
1840 else
1841 errno = EAGAIN;
1842 __leave;
1843 /* NOTREACHED */
1844 default:
1845 errno = EINVAL;
1846 __leave;
1847 /* NOTREACHED */
1849 res = cfd->mandatory_locking () ? cfd->mand_lock (cmd, &fl)
1850 : cfd->lock (cmd, &fl);
1852 __except (EFAULT) {}
1853 __endtry
1854 syscall_printf ("%R = lockf(%d, %d, %D)", res, filedes, function, size);
1855 return res;
1858 /* This is the fcntl lock implementation for mandatory locks using the
1859 Windows mandatory locking functions. For the UNIX-like advisory locking
1860 implementation see the fhandler_disk_file::lock method earlier in this
1861 file. */
1862 struct lock_parms {
1863 HANDLE h;
1864 PIO_STATUS_BLOCK pio;
1865 PLARGE_INTEGER poff;
1866 PLARGE_INTEGER plen;
1867 BOOL type;
1868 NTSTATUS status;
1871 static DWORD
1872 blocking_lock_thr (LPVOID param)
1874 struct lock_parms *lp = (struct lock_parms *) param;
1875 lp->status = NtLockFile (lp->h, NULL, NULL, NULL, lp->pio, lp->poff,
1876 lp->plen, 0, FALSE, lp->type);
1877 return 0;
1881 fhandler_base::mand_lock (int, struct flock *)
1883 set_errno (EINVAL);
1884 return -1;
1888 fhandler_disk_file::mand_lock (int a_op, struct flock *fl)
1890 NTSTATUS status;
1891 IO_STATUS_BLOCK io;
1892 FILE_POSITION_INFORMATION fpi;
1893 FILE_STANDARD_INFORMATION fsi;
1894 off_t startpos;
1895 LARGE_INTEGER offset;
1896 LARGE_INTEGER length;
1898 /* Calculate where to start from, then adjust this by fl->l_start. */
1899 switch (fl->l_whence)
1901 case SEEK_SET:
1902 startpos = 0;
1903 break;
1904 case SEEK_CUR:
1905 status = NtQueryInformationFile (get_handle (), &io, &fpi, sizeof fpi,
1906 FilePositionInformation);
1907 if (!NT_SUCCESS (status))
1909 __seterrno_from_nt_status (status);
1910 return -1;
1912 startpos = fpi.CurrentByteOffset.QuadPart;
1913 break;
1914 case SEEK_END:
1915 status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi,
1916 FileStandardInformation);
1917 if (!NT_SUCCESS (status))
1919 __seterrno_from_nt_status (status);
1920 return -1;
1922 startpos = fsi.EndOfFile.QuadPart;
1923 break;
1924 default:
1925 set_errno (EINVAL);
1926 return -1;
1928 /* Adjust start and length until they make sense. */
1929 offset.QuadPart = startpos + fl->l_start;
1930 if (fl->l_len < 0)
1932 offset.QuadPart -= fl->l_len;
1933 length.QuadPart = -fl->l_len;
1935 else
1936 length.QuadPart = fl->l_len;
1937 if (offset.QuadPart < 0)
1939 length.QuadPart -= -offset.QuadPart;
1940 if (length.QuadPart <= 0)
1942 set_errno (EINVAL);
1943 return -1;
1945 offset.QuadPart = 0;
1947 /* Special case if len == 0. For POSIX this means lock to the end of
1948 the entire file, even when file grows later. */
1949 if (length.QuadPart == 0)
1950 length.QuadPart = UINT64_MAX;
1951 /* Action! */
1952 if (fl->l_type == F_UNLCK)
1954 status = NtUnlockFile (get_handle (), &io, &offset, &length, 0);
1955 if (status == STATUS_RANGE_NOT_LOCKED) /* Not an error */
1956 status = STATUS_SUCCESS;
1958 else if (a_op == F_SETLKW)
1960 /* We open file handles synchronously. To allow asynchronous operation
1961 the file locking functions require a file handle opened in asynchronous
1962 mode. Since Windows locks are per-process/per-file object, we can't
1963 open another handle asynchrously and lock/unlock using that handle:
1964 The original file handle would not have placed the lock and would be
1965 restricted by the lock like any other file handle.
1966 So, what we do here is to start a thread which calls the potentially
1967 blocking NtLockFile call. Then we wait for thread completion in an
1968 interruptible fashion. */
1969 OBJECT_ATTRIBUTES attr;
1970 HANDLE evt;
1971 struct lock_parms lp = { get_handle (), &io, &offset, &length,
1972 fl->l_type == F_WRLCK, 0 };
1973 cygthread *thr = NULL;
1975 InitializeObjectAttributes (&attr, NULL, 0, NULL, NULL);
1976 status = NtCreateEvent (&evt, EVENT_ALL_ACCESS, &attr,
1977 NotificationEvent, FALSE);
1978 if (evt)
1979 thr = new cygthread (blocking_lock_thr, &lp, "blk_lock", evt);
1980 if (!thr)
1982 /* Thread creation failed. Fall back to blocking lock call. */
1983 if (evt)
1984 NtClose (evt);
1985 status = NtLockFile (get_handle (), NULL, NULL, NULL, &io, &offset,
1986 &length, 0, FALSE, fl->l_type == F_WRLCK);
1988 else
1990 /* F_SETLKW and lock cannot be established. Wait until the lock can
1991 be established, or a signal request arrived. We deliberately
1992 don't handle thread cancel requests here. */
1993 DWORD wait_res = cygwait (evt, INFINITE, cw_sig | cw_sig_eintr);
1994 NtClose (evt);
1995 switch (wait_res)
1997 case WAIT_OBJECT_0:
1998 /* Fetch completion status. */
1999 status = lp.status;
2000 thr->detach ();
2001 break;
2002 default:
2003 /* Signal arrived.
2004 If CancelSynchronousIo works we wait for the thread to exit.
2005 lp.status will be either STATUS_SUCCESS, or STATUS_CANCELLED.
2006 We only call NtUnlockFile in the first case.
2007 If CancelSynchronousIo fails we terminated the thread and
2008 call NtUnlockFile since lp.status was 0 to begin with. */
2009 if (CancelSynchronousIo (thr->thread_handle ()))
2010 thr->detach ();
2011 else
2012 thr->terminate_thread ();
2013 if (NT_SUCCESS (lp.status))
2014 NtUnlockFile (get_handle (), &io, &offset, &length, 0);
2015 /* Per SUSv4: If a signal is received while fcntl is waiting,
2016 fcntl shall be interrupted. Upon return from the signal
2017 handler, fcntl shall return -1 with errno set to EINTR,
2018 and the lock operation shall not be done. */
2019 _my_tls.call_signal_handler ();
2020 set_errno (EINTR);
2021 return -1;
2025 else
2027 status = NtLockFile (get_handle (), NULL, NULL, NULL, &io, &offset,
2028 &length, 0, TRUE, fl->l_type == F_WRLCK);
2029 if (a_op == F_GETLK)
2031 /* This is non-atomic, but there's no other way on Windows to detect
2032 if another lock is blocking our lock, other than trying to place
2033 the lock, and then having to unlock it again. */
2034 if (NT_SUCCESS (status))
2036 NtUnlockFile (get_handle (), &io, &offset, &length, 0);
2037 fl->l_type = F_UNLCK;
2039 else
2041 /* FAKE! FAKE! FAKE! */
2042 fl->l_type = F_WRLCK;
2043 fl->l_whence = SEEK_SET;
2044 fl->l_start = offset.QuadPart;
2045 fl->l_len = length.QuadPart;
2046 fl->l_pid = (pid_t) -1;
2048 status = STATUS_SUCCESS;
2051 if (!NT_SUCCESS (status))
2053 __seterrno_from_nt_status (status);
2054 return -1;
2056 return 0;