OSDN Git Service

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