]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/flock.cc
powf: Fixed another precision bug in powf() (FreeBSD)
[newlib-cygwin.git] / winsup / cygwin / flock.cc
CommitLineData
a998dd70 1/* flock.cc. NT specific implementation of advisory file locking.
f3a1e23e 2
f3a1e23e
CV
3 This file is part of Cygwin.
4
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. */
8
a998dd70
CV
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
025c1fac
CF
14 purposes.
15
a998dd70
CV
16 So, the following copyright applies to most of the code in the lf_XXX
17 functions.
18
19 * Copyright (c) 1982, 1986, 1989, 1993
20 * The Regents of the University of California. All rights reserved.
21 *
22 * This code is derived from software contributed to Berkeley by
23 * Scooter Morris at Genentech Inc.
24 *
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.
36 *
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.
48 *
49 * @(#)ufs_lockf.c 8.3 (Berkeley) 1/6/94
025c1fac 50*/
a998dd70
CV
51
52/*
53 * The flock() function is based upon source taken from the Red Hat
54 * implementation used in their imap-2002d SRPM.
55 *
56 * $RH: flock.c,v 1.2 2000/08/23 17:07:00 nalin Exp $
57 */
58
fabfb1a1 59/* The lockf function is based upon FreeBSD sources with the following
a998dd70 60 * copyright.
8c0b8bc3
CV
61 */
62/*
a998dd70
CV
63 * Copyright (c) 1997 The NetBSD Foundation, Inc.
64 * All rights reserved.
65 *
66 * This code is derived from software contributed to The NetBSD Foundation
67 * by Klaus Klein.
68 *
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.
a998dd70
CV
77 *
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.
8c0b8bc3 89 */
a998dd70 90
e2a39e2e 91#include "winsup.h"
a998dd70 92#include <assert.h>
f3a1e23e 93#include <sys/file.h>
f3a1e23e 94#include <unistd.h>
a998dd70
CV
95#include <stdlib.h>
96#include "cygerrno.h"
a998dd70 97#include "security.h"
db5ae618 98#include "shared_info.h"
a998dd70
CV
99#include "path.h"
100#include "fhandler.h"
101#include "dtable.h"
102#include "cygheap.h"
a998dd70
CV
103#include "pinfo.h"
104#include "sigproc.h"
105#include "cygtls.h"
30bbc55e 106#include "tls_pbuf.h"
f4ec8743 107#include "miscfuncs.h"
a998dd70
CV
108#include "ntdll.h"
109#include <sys/queue.h>
110#include <wchar.h>
111
a998dd70
CV
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 */
115
116#ifndef OFF_MAX
117#define OFF_MAX LLONG_MAX
118#endif
119
120static NO_COPY muto lockf_guard;
121
122#define INODE_LIST_LOCK() (lockf_guard.init ("lockf_guard")->acquire ())
123#define INODE_LIST_UNLOCK() (lockf_guard.release ())
124
dbf576fd
CV
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 */
129
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 */
a998dd70 133
db5ae618
CV
134#define FLOCK_INODE_DIR_ACCESS (DIRECTORY_QUERY \
135 | DIRECTORY_TRAVERSE \
136 | DIRECTORY_CREATE_OBJECT \
137 | READ_CONTROL)
138
db5ae618
CV
139#define FLOCK_EVENT_ACCESS (EVENT_QUERY_STATE \
140 | SYNCHRONIZE \
141 | READ_CONTROL)
142
a998dd70 143/* This function takes the own process security descriptor DACL and adds
b9e2579c
CV
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. */
a998dd70
CV
147static void
148allow_others_to_sync ()
149{
150 static NO_COPY bool done;
151
152 if (done)
153 return;
154
155 NTSTATUS status;
156 PACL dacl;
157 LPVOID ace;
158 ULONG len;
159
30bbc55e
CV
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. */
4e8f539f 164#define MAX_PROCESS_SD_SIZE 3072
ca7f6a04 165 PISECURITY_DESCRIPTOR sd = (PISECURITY_DESCRIPTOR) alloca (MAX_PROCESS_SD_SIZE);
f16706de
CV
166 status = NtQuerySecurityObject (NtCurrentProcess (),
167 DACL_SECURITY_INFORMATION, sd,
4e8f539f 168 MAX_PROCESS_SD_SIZE, &len);
a998dd70
CV
169 if (!NT_SUCCESS (status))
170 {
61522196 171 debug_printf ("NtQuerySecurityObject: %y", status);
a998dd70
CV
172 return;
173 }
30bbc55e 174 /* Create a valid dacl pointer and set its size to be as big as
a998dd70
CV
175 there's room in the temporary buffer. Note that the descriptor
176 is in self-relative format. */
b4ad7197
CV
177 BOOLEAN present, defaulted;
178 RtlGetDaclSecurityDescriptor (sd, &present, &dacl, &defaulted);
56bed670 179 if (!present) /* If so, dacl has undefined value. */
b4ad7197
CV
180 {
181 dacl = (PACL) (sd + 1);
182 RtlCreateAcl (dacl, MAX_PROCESS_SD_SIZE - sizeof *sd, ACL_REVISION);
183 }
56bed670
CV
184 else if (dacl == NULL) /* Everyone has all access anyway */
185 {
186 done = true;
187 return;
188 }
b4ad7197
CV
189 else
190 {
191 dacl->AclSize = MAX_PROCESS_SD_SIZE - ((PBYTE) dacl - (PBYTE) sd);
192 }
a998dd70 193 /* Allow everyone to SYNCHRONIZE with this process. */
5735d5f6
CV
194 status = RtlAddAccessAllowedAce (dacl, ACL_REVISION, SYNCHRONIZE,
195 well_known_world_sid);
196 if (!NT_SUCCESS (status))
a998dd70 197 {
61522196 198 debug_printf ("RtlAddAccessAllowedAce: %y", status);
a998dd70
CV
199 return;
200 }
201 /* Set the size of the DACL correctly. */
1754539e
CV
202 status = RtlFirstFreeAce (dacl, &ace);
203 if (!NT_SUCCESS (status))
a998dd70 204 {
61522196 205 debug_printf ("RtlFirstFreeAce: %y", status);
a998dd70
CV
206 return;
207 }
208 dacl->AclSize = (char *) ace - (char *) dacl;
209 /* Write the DACL back. */
f16706de 210 status = NtSetSecurityObject (NtCurrentProcess (), DACL_SECURITY_INFORMATION, sd);
a998dd70
CV
211 if (!NT_SUCCESS (status))
212 {
61522196 213 debug_printf ("NtSetSecurityObject: %y", status);
a998dd70
CV
214 return;
215 }
216 done = true;
217}
218
f4ec8743
CV
219/* Helper struct to construct a local OBJECT_ATTRIBUTES on the stack. */
220struct lockfattr_t
221{
222 OBJECT_ATTRIBUTES attr;
223 UNICODE_STRING uname;
224 WCHAR name[LOCK_OBJ_NAME_LEN + 1];
225};
226
a998dd70
CV
227/* Per lock class. */
228class lockf_t
229{
230 public:
dbf576fd
CV
231 uint16_t lf_flags; /* Semantics: F_POSIX, F_FLOCK, F_WAIT */
232 uint16_t lf_type; /* Lock type: F_RDLCK, F_WRLCK */
61522196
CV
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
636c94d8 236 file table entry for BSD flock locks. */
f4ec8743 237 DWORD lf_wid; /* Win PID of the resource holding the lock */
2e560a09
CV
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. */
a998dd70
CV
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 */
f4ec8743 245 HANDLE lf_obj; /* Handle to the lock event object. */
a998dd70
CV
246
247 lockf_t ()
248 : lf_flags (0), lf_type (0), lf_start (0), lf_end (0), lf_id (0),
2e560a09 249 lf_wid (0), lf_ver (0), lf_head (NULL), lf_inode (NULL),
636c94d8 250 lf_next (NULL), lf_obj (NULL)
a998dd70 251 {}
2e560a09 252 lockf_t (class inode_t *node, class lockf_t **head,
61522196 253 short flags, short type, off_t start, off_t end,
2e560a09 254 long long id, DWORD wid, uint16_t ver)
a998dd70 255 : lf_flags (flags), lf_type (type), lf_start (start), lf_end (end),
2e560a09 256 lf_id (id), lf_wid (wid), lf_ver (ver), lf_head (head), lf_inode (node),
a998dd70
CV
257 lf_next (NULL), lf_obj (NULL)
258 {}
259 ~lockf_t ();
260
dbf576fd
CV
261 bool from_obj_name (class inode_t *node, class lockf_t **head,
262 const wchar_t *name);
263
31390e4c
CV
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. */
a998dd70 268 void *operator new (size_t size)
31390e4c
CV
269 { return cmalloc (HEAP_FHANDLER, sizeof (lockf_t)); }
270 /* Never call on node->i_all_lf! */
a998dd70
CV
271 void operator delete (void *p)
272 { cfree (p); }
273
f4ec8743 274 POBJECT_ATTRIBUTES create_lock_obj_attr (lockfattr_t *attr,
44e0f5a7 275 ULONG flags, void *sd_buf);
f4ec8743 276
a998dd70 277 void create_lock_obj ();
636c94d8 278 bool open_lock_obj ();
f4ec8743 279 void close_lock_obj () { NtClose (lf_obj); lf_obj = NULL; }
636c94d8 280 void del_lock_obj (HANDLE fhdl, bool signal = false);
a998dd70
CV
281};
282
283/* Per inode_t class */
284class inode_t
285{
286 friend class lockf_t;
287
288 public:
2e560a09
CV
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. */
a998dd70 292
61522196
CV
293 dev_t i_dev; /* Device ID */
294 ino_t i_ino; /* inode number */
a998dd70 295
636c94d8 296 private:
2e560a09
CV
297 HANDLE i_dir;
298 HANDLE i_mtx;
299 uint32_t i_cnt; /* # of threads referencing this instance. */
300
a998dd70 301 public:
61522196 302 inode_t (dev_t dev, ino_t ino);
a998dd70
CV
303 ~inode_t ();
304
305 void *operator new (size_t size)
31390e4c 306 { return cmalloc (HEAP_FHANDLER, sizeof (inode_t)); }
a998dd70
CV
307 void operator delete (void *p)
308 { cfree (p); }
309
61522196 310 static inode_t *get (dev_t dev, ino_t ino,
dbf576fd 311 bool create_if_missing, bool lock);
a998dd70
CV
312
313 void LOCK () { WaitForSingleObject (i_mtx, INFINITE); }
314 void UNLOCK () { ReleaseMutex (i_mtx); }
315
dbf576fd
CV
316 void use () { ++i_cnt; }
317 void unuse () { if (i_cnt > 0) --i_cnt; }
318 bool inuse () { return i_cnt > 0; }
2e560a09
CV
319 void notused () { i_cnt = 0; }
320
52a5f8cc 321 void unlock_and_remove_if_unused ();
a74869c0 322
31390e4c 323 lockf_t *get_all_locks_list ();
a998dd70 324
636c94d8 325 bool del_my_locks (long long id, HANDLE fhdl);
a998dd70
CV
326};
327
636c94d8 328inode_t::~inode_t ()
a998dd70 329{
636c94d8
CV
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);
a998dd70
CV
335}
336
2e560a09 337void
52a5f8cc 338inode_t::unlock_and_remove_if_unused ()
2e560a09
CV
339{
340 UNLOCK ();
341 INODE_LIST_LOCK ();
342 unuse ();
343 if (i_lockf == NULL && !inuse ())
344 {
345 LIST_REMOVE (this, i_next);
346 delete this;
347 }
348 INODE_LIST_UNLOCK ();
349}
350
636c94d8
CV
351bool
352inode_t::del_my_locks (long long id, HANDLE fhdl)
a998dd70 353{
636c94d8
CV
354 lockf_t *lock, *n_lock;
355 lockf_t **prev = &i_lockf;
636c94d8
CV
356 for (lock = *prev; lock && (n_lock = lock->lf_next, 1); lock = n_lock)
357 {
358 if (lock->lf_flags & F_POSIX)
359 {
360 /* Delete all POSIX locks. */
361 *prev = n_lock;
3c53eaeb
CV
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 ();
636c94d8
CV
368 delete lock;
369 }
370 else if (id && lock->lf_id == id)
371 {
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)
380 {
381 *prev = n_lock;
382 lock->del_lock_obj (fhdl);
383 delete lock;
384 }
385 }
386 else
387 prev = &lock->lf_next;
388 }
389 return i_lockf == NULL;
390}
a998dd70 391
636c94d8
CV
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. */
396void
4a77aea0 397fhandler_base::del_my_locks (del_lock_called_from from)
636c94d8 398{
dbf576fd 399 inode_t *node = inode_t::get (get_dev (), get_ino (), false, true);
636c94d8
CV
400 if (node)
401 {
4a77aea0
CV
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. */
2e560a09
CV
411 node->del_my_locks (from == after_fork ? 0 : get_unique_id (),
412 from == after_exec ? NULL : get_handle ());
52a5f8cc 413 node->unlock_and_remove_if_unused ();
636c94d8 414 }
a998dd70
CV
415}
416
417/* Called in an execed child. The exec'ed process must allow SYNCHRONIZE
418 access to everyone if at least one inode exists.
636c94d8
CV
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. */
a998dd70 423void
127cfd4f 424fixup_lockf_after_exec (bool exec)
a998dd70 425{
636c94d8 426 inode_t *node, *next_node;
a998dd70
CV
427
428 INODE_LIST_LOCK ();
429 if (LIST_FIRST (&cygheap->inode_list))
430 allow_others_to_sync ();
636c94d8 431 LIST_FOREACH_SAFE (node, &cygheap->inode_list, i_next, next_node)
a998dd70 432 {
2e560a09 433 node->notused ();
636c94d8
CV
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
95ff6fc6 439 && ++cnt >= 1)
636c94d8
CV
440 break;
441 if (cnt == 0)
a998dd70 442 {
636c94d8
CV
443 LIST_REMOVE (node, i_next);
444 delete node;
445 }
446 else
447 {
448 node->LOCK ();
127cfd4f
CV
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)
636c94d8
CV
452 if (lock->lf_flags & F_POSIX)
453 {
127cfd4f
CV
454 if (exec)
455 {
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 ();
462 }
463 else
464 {
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;
471 }
636c94d8
CV
472 }
473 node->UNLOCK ();
a998dd70 474 }
a998dd70 475 }
a998dd70
CV
476 INODE_LIST_UNLOCK ();
477}
478
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. */
482inode_t *
61522196 483inode_t::get (dev_t dev, ino_t ino, bool create_if_missing, bool lock)
a998dd70
CV
484{
485 inode_t *node;
486
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;
636c94d8 491 if (!node && create_if_missing)
a998dd70
CV
492 {
493 node = new inode_t (dev, ino);
31390e4c
CV
494 if (node)
495 LIST_INSERT_HEAD (&cygheap->inode_list, node, i_next);
a998dd70 496 }
636c94d8 497 if (node)
2e560a09 498 node->use ();
a998dd70 499 INODE_LIST_UNLOCK ();
dbf576fd 500 if (node && lock)
2e560a09 501 node->LOCK ();
a998dd70
CV
502 return node;
503}
504
61522196 505inode_t::inode_t (dev_t dev, ino_t ino)
2e560a09 506: i_lockf (NULL), i_all_lf (NULL), i_dev (dev), i_ino (ino), i_cnt (0L)
a998dd70
CV
507{
508 HANDLE parent_dir;
db5ae618 509 WCHAR name[48];
a998dd70
CV
510 UNICODE_STRING uname;
511 OBJECT_ATTRIBUTES attr;
512 NTSTATUS status;
513
db5ae618 514 parent_dir = get_shared_parent_dir ();
a998dd70
CV
515 /* Create a subdir which is named after the device and inode_t numbers
516 of the given file, in hex notation. */
dbf576fd 517 int len = __small_swprintf (name, LOCK_DIR_NAME_FMT, dev, ino);
a998dd70 518 RtlInitCountedUnicodeString (&uname, name, len * sizeof (WCHAR));
5cb524ee
CV
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);
a998dd70 522 if (!NT_SUCCESS (status))
61522196 523 api_fatal ("NtCreateDirectoryObject(inode): %y", status);
a998dd70
CV
524 /* Create a mutex object in the file specific dir, which is used for
525 access synchronization on the dir and its objects. */
8deb4118 526 InitializeObjectAttributes (&attr, &ro_u_mtx, OBJ_INHERIT | OBJ_OPENIF, i_dir,
abbde487
CV
527 everyone_sd (CYG_MUTANT_ACCESS));
528 status = NtCreateMutant (&i_mtx, CYG_MUTANT_ACCESS, &attr, FALSE);
a998dd70 529 if (!NT_SUCCESS (status))
61522196 530 api_fatal ("NtCreateMutant(inode): %y", status);
a998dd70
CV
531}
532
a998dd70
CV
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. */
31390e4c
CV
536
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)))
540
dbf576fd
CV
541bool
542lockf_t::from_obj_name (inode_t *node, lockf_t **head, const wchar_t *name)
543{
544 wchar_t *endptr;
545
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;
61522196 555 lf_start = (off_t) wcstoull (endptr + 1, &endptr, 16);
dbf576fd
CV
556 if (lf_start < 0 || !endptr || *endptr != L'-')
557 return false;
61522196 558 lf_end = (off_t) wcstoull (endptr + 1, &endptr, 16);
dbf576fd
CV
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'-'
8451a289 565 || ((lf_flags & F_POSIX) && (lf_id < 1 || lf_id > UINT32_MAX)))
dbf576fd
CV
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;
578}
579
31390e4c 580lockf_t *
a998dd70
CV
581inode_t::get_all_locks_list ()
582{
2f05de4d 583 tmp_pathbuf tp;
a998dd70
CV
584 ULONG context;
585 NTSTATUS status;
2f05de4d
CV
586 BOOLEAN restart = TRUE;
587 bool last_run = false;
dbf576fd 588 lockf_t newlock, *lock = i_all_lf;
a998dd70 589
2f05de4d
CV
590 PDIRECTORY_BASIC_INFORMATION dbi_buf = (PDIRECTORY_BASIC_INFORMATION)
591 tp.w_get ();
592 while (!last_run)
a998dd70 593 {
2f05de4d
CV
594 status = NtQueryDirectoryObject (i_dir, dbi_buf, 65536, FALSE, restart,
595 &context, NULL);
596 if (!NT_SUCCESS (status))
025c1fac 597 {
2f05de4d 598 debug_printf ("NtQueryDirectoryObject, status %y", status);
31390e4c
CV
599 break;
600 }
2f05de4d
CV
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++)
607 {
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)
614 {
615 system_printf ("Warning, can't handle more than %d locks per file.",
616 MAX_LOCKF_CNT);
617 break;
618 }
619 if (lock > i_all_lf)
620 lock[-1].lf_next = lock;
621 new (lock++) lockf_t (newlock);
622 }
a998dd70 623 }
31390e4c
CV
624 /* If no lock has been found, return NULL. */
625 if (lock == i_all_lf)
626 return NULL;
627 return i_all_lf;
a998dd70
CV
628}
629
f4ec8743
CV
630/* Create the lock object name. The name is constructed from the lock
631 properties which identify it uniquely, all values in hex. */
632POBJECT_ATTRIBUTES
44e0f5a7 633lockf_t::create_lock_obj_attr (lockfattr_t *attr, ULONG flags, void *sd_buf)
f4ec8743 634{
dbf576fd 635 __small_swprintf (attr->name, LOCK_OBJ_NAME_FMT,
f4ec8743 636 lf_flags & (F_POSIX | F_FLOCK), lf_type, lf_start, lf_end,
2e560a09 637 lf_id, lf_wid, lf_ver);
f4ec8743
CV
638 RtlInitCountedUnicodeString (&attr->uname, attr->name,
639 LOCK_OBJ_NAME_LEN * sizeof (WCHAR));
640 InitializeObjectAttributes (&attr->attr, &attr->uname, flags, lf_inode->i_dir,
44e0f5a7 641 _everyone_sd (sd_buf, FLOCK_EVENT_ACCESS));
f4ec8743
CV
642 return &attr->attr;
643}
644
b28edc7b 645DWORD
dbf576fd
CV
646create_lock_in_parent (PVOID param)
647{
648 HANDLE lf_obj;
649 ULONG size;
650 OBJECT_NAME_INFORMATION *ntfn;
651 NTSTATUS status;
652 wchar_t *lockname, *inodename, *endptr;
61522196
CV
653 dev_t dev;
654 ino_t ino;
dbf576fd
CV
655 inode_t *node;
656 lockf_t newlock, *lock;
657 int cnt;
658
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. */
687 {
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;
693 }
694 /* If not, close handle and return. */
695 if (!cnt)
696 {
697 NtClose (lf_obj);
698 return 0;
699 }
df386dda
CV
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;
dbf576fd
CV
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;
717
718err:
719 system_printf ("Adding <%S> lock failed", &ntfn->Name);
720 NtClose (lf_obj);
721 return 1;
722}
723
b28edc7b 724DWORD
dbf576fd
CV
725delete_lock_in_parent (PVOID param)
726{
59ce2890 727 inode_t *node, *next_node;
dbf576fd
CV
728 lockf_t *lock, **prev;
729
730 /* Scan list of all inodes, and reap stale BSD lock if lf_id matches.
731 Remove inode if empty. */
732 INODE_LIST_LOCK ();
59ce2890 733 LIST_FOREACH_SAFE (node, &cygheap->inode_list, i_next, next_node)
dbf576fd
CV
734 if (!node->inuse ())
735 {
736 for (prev = &node->i_lockf, lock = *prev; lock; lock = *prev)
737 {
738 if ((lock->lf_flags & F_FLOCK) && IsEventSignalled (lock->lf_obj))
739 {
740 *prev = lock->lf_next;
741 delete lock;
742 }
743 else
744 prev = &lock->lf_next;
745 }
746 if (node->i_lockf == NULL)
747 {
748 LIST_REMOVE (node, i_next);
749 delete node;
750 }
751 }
752 INODE_LIST_UNLOCK ();
753 return 0;
754}
755
a998dd70 756/* Create the lock event object in the file's subdir in the NT global
f4ec8743 757 namespace. */
a998dd70
CV
758void
759lockf_t::create_lock_obj ()
760{
f4ec8743 761 lockfattr_t attr;
a998dd70 762 NTSTATUS status;
914620a7 763 PSECURITY_DESCRIPTOR sd_buf = alloca (SD_MIN_SIZE);
44e0f5a7 764 POBJECT_ATTRIBUTES lock_obj_attr;
a998dd70 765
f4ec8743
CV
766 do
767 {
914620a7 768 lock_obj_attr = create_lock_obj_attr (&attr, OBJ_INHERIT, sd_buf);
44e0f5a7 769 status = NtCreateEvent (&lf_obj, CYG_EVENT_ACCESS, lock_obj_attr,
f4ec8743
CV
770 NotificationEvent, FALSE);
771 if (!NT_SUCCESS (status))
772 {
2e560a09 773 if (status != STATUS_OBJECT_NAME_COLLISION)
61522196 774 api_fatal ("NtCreateEvent(lock): %y", status);
2e560a09
CV
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. */
f4ec8743
CV
782 if (open_lock_obj ())
783 {
784 if (!IsEventSignalled (lf_obj))
61522196 785 api_fatal ("NtCreateEvent(lock): %y", status);
f4ec8743 786 close_lock_obj ();
2e560a09
CV
787 /* Increment the lf_ver field until we have no collision. */
788 ++lf_ver;
f4ec8743
CV
789 }
790 }
791 }
792 while (!NT_SUCCESS (status));
dbf576fd
CV
793 /* For BSD locks, notify the parent process. */
794 if (lf_flags & F_FLOCK)
795 {
796 HANDLE parent_proc, parent_thread, parent_lf_obj;
797
798 pinfo p (myself->ppid);
799 if (!p) /* No access or not a Cygwin parent. */
d2ef2331 800 return;
dbf576fd
CV
801
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)
810 {
811 debug_printf ("OpenProcess (%u): %E", p->dwProcessId);
812 return;
813 }
814 if (!DuplicateHandle (GetCurrentProcess (), lf_obj, parent_proc,
df386dda 815 &parent_lf_obj, TRUE, FALSE, DUPLICATE_SAME_ACCESS))
dbf576fd
CV
816 debug_printf ("DuplicateHandle (lf_obj): %E");
817 else
818 {
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)
825 {
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);
831 }
832 else
833 {
834 /* Must wait to avoid race conditions. */
835 WaitForSingleObject (parent_thread, INFINITE);
836 CloseHandle (parent_thread);
837 }
838 }
839 CloseHandle (parent_proc);
840 }
a998dd70
CV
841}
842
843/* Open a lock event object for SYNCHRONIZE access (to wait for it). */
636c94d8
CV
844bool
845lockf_t::open_lock_obj ()
a998dd70 846{
f4ec8743 847 lockfattr_t attr;
a998dd70 848 NTSTATUS status;
a998dd70 849
f4ec8743 850 status = NtOpenEvent (&lf_obj, FLOCK_EVENT_ACCESS,
44e0f5a7 851 create_lock_obj_attr (&attr, 0, alloca (SD_MIN_SIZE)));
a998dd70 852 if (!NT_SUCCESS (status))
c46d7be9
CV
853 {
854 SetLastError (RtlNtStatusToDosError (status));
636c94d8 855 lf_obj = NULL; /* Paranoia... */
a998dd70 856 }
636c94d8 857 return lf_obj != NULL;
a998dd70
CV
858}
859
f4ec8743
CV
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. */
a998dd70 863void
636c94d8 864lockf_t::del_lock_obj (HANDLE fhdl, bool signal)
a998dd70
CV
865{
866 if (lf_obj)
867 {
636c94d8
CV
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))
dbf576fd 877 {
df386dda
CV
878 NTSTATUS status = NtSetEvent (lf_obj, NULL);
879 if (!NT_SUCCESS (status))
880 system_printf ("NtSetEvent, %y", status);
dbf576fd
CV
881 /* For BSD locks, notify the parent process. */
882 if (lf_flags & F_FLOCK)
883 {
884 HANDLE parent_proc, parent_thread;
885
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)))
893 {
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)
900 {
901 /* Must wait to avoid race conditions. */
902 WaitForSingleObject (parent_thread, INFINITE);
903 CloseHandle (parent_thread);
904 }
905 CloseHandle (parent_proc);
906 }
907 }
908 }
f4ec8743 909 close_lock_obj ();
a998dd70
CV
910 }
911}
912
913lockf_t::~lockf_t ()
914{
636c94d8 915 del_lock_obj (NULL);
a998dd70
CV
916}
917
918/*
919 * This variable controls the maximum number of processes that will
920 * be checked in doing deadlock detection.
921 */
636c94d8 922#ifndef __CYGWIN__
a998dd70
CV
923#define MAXDEPTH 50
924static int maxlockdepth = MAXDEPTH;
925#endif
926
927#define NOLOCKF (struct lockf_t *)0
928#define SELF 0x1
929#define OTHERS 0x2
636c94d8 930static int lf_clearlock (lockf_t *, lockf_t **, HANDLE);
a998dd70 931static int lf_findoverlap (lockf_t *, lockf_t *, int, lockf_t ***, lockf_t **);
31390e4c 932static lockf_t *lf_getblock (lockf_t *, inode_t *node);
61522196 933static int lf_getlock (lockf_t *, inode_t *, struct flock *);
636c94d8 934static int lf_setlock (lockf_t *, inode_t *, lockf_t **, HANDLE);
a998dd70 935static void lf_split (lockf_t *, lockf_t *, lockf_t **);
636c94d8 936static void lf_wakelock (lockf_t *, HANDLE);
a998dd70 937
a24ad2c3
CV
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. */
edd73646 941int
95ff6fc6 942fhandler_base::lock (int a_op, struct flock *fl)
a998dd70 943{
61522196 944 off_t start, end, oadd;
a998dd70 945 int error = 0;
a998dd70
CV
946
947 short a_flags = fl->l_type & (F_POSIX | F_FLOCK);
948 short type = fl->l_type & (F_RDLCK | F_WRLCK | F_UNLCK);
025c1fac 949
7a1dc2a9
CV
950 if (!a_flags)
951 a_flags = F_POSIX; /* default */
952
953 /* FIXME: For BSD flock(2) we need a valid, per file table entry OS handle.
df680fb6
CV
954 Therefore we can't allow using flock(2) on nohandle devices. */
955 if ((a_flags & F_FLOCK) && nohandle ())
95ff6fc6
CV
956 {
957 set_errno (EINVAL);
7a1dc2a9
CV
958 debug_printf ("BSD locking on nohandle and old-style console devices "
959 "not supported");
95ff6fc6
CV
960 return -1;
961 }
962
a998dd70
CV
963 if (a_op == F_SETLKW)
964 {
965 a_op = F_SETLK;
966 a_flags |= F_WAIT;
967 }
968 if (a_op == F_SETLK)
969 switch (type)
970 {
971 case F_UNLCK:
972 a_op = F_UNLCK;
973 break;
974 case F_RDLCK:
fc69f1ae
CV
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. */
95ff6fc6
CV
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))
a998dd70 985 {
85a53bd5 986 debug_printf ("request F_RDLCK on O_WRONLY file: EBADF");
a998dd70
CV
987 set_errno (EBADF);
988 return -1;
989 }
990 break;
991 case F_WRLCK:
fc69f1ae 992 /* See above comment. */
95ff6fc6
CV
993 if ((a_flags & F_POSIX)
994 && ((get_flags () & O_ACCMODE) == O_RDONLY))
a998dd70 995 {
85a53bd5 996 debug_printf ("request F_WRLCK on O_RDONLY file: EBADF");
a998dd70
CV
997 set_errno (EBADF);
998 return -1;
999 }
1000 break;
1001 default:
025c1fac 1002 set_errno (EINVAL);
a998dd70
CV
1003 return -1;
1004 }
1005
a998dd70
CV
1006 /*
1007 * Convert the flock structure into a start and end.
1008 */
1009 switch (fl->l_whence)
1010 {
1011 case SEEK_SET:
1012 start = fl->l_start;
1013 break;
1014
1015 case SEEK_CUR:
1016 if ((start = lseek (0, SEEK_CUR)) == ILLEGAL_SEEK)
95ff6fc6 1017 start = 0;
a998dd70
CV
1018 break;
1019
1020 case SEEK_END:
95ff6fc6 1021 if (get_device () != FH_FS)
d2ef2331 1022 start = 0;
95ff6fc6
CV
1023 else
1024 {
1025 NTSTATUS status;
1026 IO_STATUS_BLOCK io;
1027 FILE_STANDARD_INFORMATION fsi;
636c94d8 1028
95ff6fc6
CV
1029 status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi,
1030 FileStandardInformation);
1031 if (!NT_SUCCESS (status))
1032 {
1033 __seterrno_from_nt_status (status);
1034 return -1;
1035 }
1036 if (fl->l_start > 0 && fsi.EndOfFile.QuadPart > OFF_MAX - fl->l_start)
1037 {
1038 set_errno (EOVERFLOW);
1039 return -1;
1040 }
1041 start = fsi.EndOfFile.QuadPart + fl->l_start;
1042 }
a998dd70
CV
1043 break;
1044
1045 default:
1046 return (EINVAL);
1047 }
1048 if (start < 0)
1049 {
1050 set_errno (EINVAL);
1051 return -1;
1052 }
1053 if (fl->l_len < 0)
1054 {
1055 if (start == 0)
1056 {
1057 set_errno (EINVAL);
1058 return -1;
1059 }
1060 end = start - 1;
1061 start += fl->l_len;
1062 if (start < 0)
1063 {
1064 set_errno (EINVAL);
1065 return -1;
1066 }
1067 }
1068 else if (fl->l_len == 0)
1069 end = -1;
1070 else
1071 {
1072 oadd = fl->l_len - 1;
1073 if (oadd > OFF_MAX - start)
1074 {
1075 set_errno (EOVERFLOW);
1076 return -1;
1077 }
1078 end = start + oadd;
1079 }
1080
f4ec8743
CV
1081restart: /* Entry point after a restartable signal came in. */
1082
dbf576fd 1083 inode_t *node = inode_t::get (get_dev (), get_ino (), true, true);
a998dd70
CV
1084 if (!node)
1085 {
636c94d8
CV
1086 set_errno (ENOLCK);
1087 return -1;
a998dd70 1088 }
636c94d8 1089
fabfb1a1
CV
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. */
a998dd70
CV
1092 cygheap->fdtab.unlock ();
1093
1094 lockf_t **head = &node->i_lockf;
1095
9fa63f7a 1096#if 0
a998dd70
CV
1097 /*
1098 * Avoid the common case of unlocking when inode_t has no locks.
9fa63f7a
CV
1099 *
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.
a998dd70
CV
1103 */
1104 if (*head == NULL)
1105 {
1106 if (a_op != F_SETLK)
1107 {
636c94d8 1108 node->UNLOCK ();
a998dd70
CV
1109 fl->l_type = F_UNLCK;
1110 return 0;
1111 }
1112 }
9fa63f7a 1113#endif
a998dd70
CV
1114 /*
1115 * Allocate a spare structure in case we have to split.
1116 */
1117 lockf_t *clean = NULL;
1118 if (a_op == F_SETLK || a_op == F_UNLCK)
31390e4c
CV
1119 {
1120 clean = new lockf_t ();
1121 if (!clean)
025c1fac 1122 {
52a5f8cc 1123 node->unlock_and_remove_if_unused ();
31390e4c
CV
1124 set_errno (ENOLCK);
1125 return -1;
1126 }
1127 }
a998dd70
CV
1128 /*
1129 * Create the lockf_t structure
1130 */
1131 lockf_t *lock = new lockf_t (node, head, a_flags, type, start, end,
636c94d8
CV
1132 (a_flags & F_FLOCK) ? get_unique_id ()
1133 : getpid (),
2e560a09 1134 myself->dwProcessId, 0);
31390e4c
CV
1135 if (!lock)
1136 {
52a5f8cc 1137 node->unlock_and_remove_if_unused ();
31390e4c
CV
1138 set_errno (ENOLCK);
1139 return -1;
1140 }
a998dd70 1141
a998dd70
CV
1142 switch (a_op)
1143 {
1144 case F_SETLK:
636c94d8 1145 error = lf_setlock (lock, node, &clean, get_handle ());
a998dd70
CV
1146 break;
1147
1148 case F_UNLCK:
636c94d8 1149 error = lf_clearlock (lock, &clean, get_handle ());
a998dd70 1150 lock->lf_next = clean;
025c1fac 1151 clean = lock;
a998dd70 1152 break;
025c1fac 1153
a998dd70
CV
1154 case F_GETLK:
1155 error = lf_getlock (lock, node, fl);
1156 lock->lf_next = clean;
1157 clean = lock;
1158 break;
1159
1160 default:
1161 lock->lf_next = clean;
1162 clean = lock;
1163 error = EINVAL;
1164 break;
1165 }
1166 for (lock = clean; lock != NULL; )
1167 {
f4ec8743 1168 lockf_t *n = lock->lf_next;
636c94d8 1169 lock->del_lock_obj (get_handle (), a_op == F_UNLCK);
a998dd70
CV
1170 delete lock;
1171 lock = n;
1172 }
52a5f8cc 1173 node->unlock_and_remove_if_unused ();
f4ec8743 1174 switch (error)
a998dd70 1175 {
f4ec8743
CV
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;
a998dd70 1188 }
f4ec8743
CV
1189 set_errno (error);
1190 return -1;
a998dd70
CV
1191}
1192
1193/*
1194 * Set a byte-range lock.
1195 */
1196static int
636c94d8 1197lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl)
025c1fac 1198{
a998dd70
CV
1199 lockf_t *block;
1200 lockf_t **head = lock->lf_head;
1201 lockf_t **prev, *overlap;
1202 int ovcase, priority, old_prio, needtolink;
30bbc55e 1203 tmp_pathbuf tp;
a998dd70
CV
1204
1205 /*
1206 * Set the priority
1207 */
1208 priority = old_prio = GetThreadPriority (GetCurrentThread ());
1209 if (lock->lf_type == F_WRLCK && priority <= THREAD_PRIORITY_ABOVE_NORMAL)
1210 priority = THREAD_PRIORITY_HIGHEST;
1211 /*
1212 * Scan lock list for this file looking for locks that would block us.
1213 */
31390e4c 1214 /* Create temporary space for the all locks list. */
30bbc55e 1215 node->i_all_lf = (lockf_t *) (void *) tp.w_get ();
a998dd70
CV
1216 while ((block = lf_getblock(lock, node)))
1217 {
636c94d8
CV
1218 HANDLE obj = block->lf_obj;
1219 block->lf_obj = NULL;
1220
a998dd70
CV
1221 /*
1222 * Free the structure and return if nonblocking.
1223 */
1224 if ((lock->lf_flags & F_WAIT) == 0)
1225 {
2e560a09 1226 NtClose (obj);
a998dd70
CV
1227 lock->lf_next = *clean;
1228 *clean = lock;
1229 return EAGAIN;
1230 }
1231 /*
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.
1235 *
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.
1240 */
1241 /* FIXME: We check the handle count of all the lock event objects
025c1fac 1242 this process holds. If it's > 1, another process is
a998dd70
CV
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. */
2e560a09
CV
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)
1249 {
636c94d8 1250 NtClose (obj);
2e560a09
CV
1251 return EDEADLK;
1252 }
a998dd70
CV
1253
1254 /*
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.
1258 */
1259 if ((lock->lf_flags & F_FLOCK) && lock->lf_type == F_WRLCK)
1260 {
1261 lock->lf_type = F_UNLCK;
636c94d8 1262 (void) lf_clearlock (lock, clean, fhdl);
a998dd70
CV
1263 lock->lf_type = F_WRLCK;
1264 }
1265
1266 /*
1267 * Add our lock to the blocked list and sleep until we're free.
1268 * Remember who blocked us (for deadlock detection).
1269 */
636c94d8 1270 /* Cygwin: No locked list. See deadlock recognition above. */
a998dd70 1271
2e560a09 1272 node->UNLOCK ();
1804be04 1273
2e560a09
CV
1274 /* Create list of objects to wait for. */
1275 HANDLE w4[4] = { obj, NULL, NULL, NULL };
1276 DWORD wait_count = 1;
1804be04 1277
5eb802f8 1278 DWORD timeout;
2e560a09 1279 HANDLE proc = NULL;
636c94d8 1280 if (lock->lf_flags & F_POSIX)
025c1fac 1281 {
2e560a09 1282 proc = OpenProcess (SYNCHRONIZE, FALSE, block->lf_wid);
636c94d8 1283 if (!proc)
5eb802f8 1284 timeout = 0L;
2e560a09 1285 else
5eb802f8
CV
1286 {
1287 w4[wait_count++] = proc;
1288 timeout = INFINITE;
1289 }
636c94d8 1290 }
5eb802f8
CV
1291 else
1292 timeout = 100L;
1293
2e560a09 1294 DWORD WAIT_SIGNAL_ARRIVED = WAIT_OBJECT_0 + wait_count;
c43e9340 1295 wait_signal_arrived here (w4[wait_count++]);
1804be04 1296
2e560a09
CV
1297 DWORD WAIT_THREAD_CANCELED = WAIT_TIMEOUT + 1;
1298 HANDLE cancel_event = pthread::get_cancel_event ();
1299 if (cancel_event)
1300 {
1301 WAIT_THREAD_CANCELED = WAIT_OBJECT_0 + wait_count;
1302 w4[wait_count++] = cancel_event;
b9e2579c 1303 }
2e560a09
CV
1304
1305 /* Wait for the blocking object and, for POSIX locks, its holding process.
1b23b30b 1306 Unfortunately, since BSD flock locks are not attached to a specific
2e560a09
CV
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
5eb802f8
CV
1311 infinitely. For POSIX locks, if the process has already exited,
1312 just check if a signal or a thread cancel request arrived. */
2e560a09 1313 SetThreadPriority (GetCurrentThread (), priority);
5eb802f8 1314 DWORD ret = WaitForMultipleObjects (wait_count, w4, FALSE, timeout);
636c94d8 1315 SetThreadPriority (GetCurrentThread (), old_prio);
2e560a09
CV
1316 if (proc)
1317 CloseHandle (proc);
1318 node->LOCK ();
a8c8f19a
CV
1319 /* Never close lock object handle outside of node lock! */
1320 NtClose (obj);
f4ec8743 1321 if (ret == WAIT_SIGNAL_ARRIVED)
a998dd70 1322 {
a998dd70 1323 /* A signal came in. */
f4ec8743
CV
1324 lock->lf_next = *clean;
1325 *clean = lock;
1326 return EINTR;
1804be04
CV
1327 }
1328 else if (ret == WAIT_THREAD_CANCELED)
1329 {
1330 /* The thread has been sent a cancellation request. */
f4ec8743
CV
1331 lock->lf_next = *clean;
1332 *clean = lock;
1333 return ECANCELED;
1804be04
CV
1334 }
1335 else
f4ec8743
CV
1336 /* The lock object has been set to signalled or ...
1337 for POSIX locks, the process holding the lock has exited, or ...
2e560a09 1338 just a timeout. Just retry. */
f4ec8743 1339 continue;
a998dd70 1340 }
a998dd70
CV
1341 allow_others_to_sync ();
1342 /*
1343 * No blocks!! Add the lock. Note that we will
1344 * downgrade or upgrade any overlapping locks this
1345 * process already owns.
1346 *
1347 * Handle any locks that overlap.
1348 */
1349 prev = head;
1350 block = *head;
1351 needtolink = 1;
1352 for (;;)
1353 {
1354 ovcase = lf_findoverlap (block, lock, SELF, &prev, &overlap);
1355 if (ovcase)
1356 block = overlap->lf_next;
1357 /*
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
1365 */
1366 switch (ovcase)
1367 {
025c1fac 1368 case 0: /* no overlap */
a998dd70
CV
1369 if (needtolink)
1370 {
1371 *prev = lock;
1372 lock->lf_next = overlap;
1373 lock->create_lock_obj ();
025c1fac
CF
1374 }
1375 break;
a998dd70 1376
025c1fac 1377 case 1: /* overlap == lock */
a998dd70
CV
1378 /*
1379 * If downgrading lock, others may be
1380 * able to acquire it.
1381 * Cygwin: Always wake lock.
1382 */
636c94d8 1383 lf_wakelock (overlap, fhdl);
a998dd70
CV
1384 overlap->lf_type = lock->lf_type;
1385 overlap->create_lock_obj ();
1386 lock->lf_next = *clean;
1387 *clean = lock;
1388 break;
1389
025c1fac 1390 case 2: /* overlap contains lock */
a998dd70
CV
1391 /*
1392 * Check for common starting point and different types.
1393 */
1394 if (overlap->lf_type == lock->lf_type)
1395 {
1396 lock->lf_next = *clean;
1397 *clean = lock;
1398 break;
1399 }
1400 if (overlap->lf_start == lock->lf_start)
1401 {
1402 *prev = lock;
1403 lock->lf_next = overlap;
1404 overlap->lf_start = lock->lf_end + 1;
1405 }
1406 else
1407 lf_split (overlap, lock, clean);
636c94d8 1408 lf_wakelock (overlap, fhdl);
a998dd70
CV
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;
1414
025c1fac 1415 case 3: /* lock contains overlap */
a998dd70
CV
1416 /*
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.
1420 */
636c94d8 1421 lf_wakelock (overlap, fhdl);
a998dd70
CV
1422 /*
1423 * Add the new lock if necessary and delete the overlap.
1424 */
1425 if (needtolink)
1426 {
1427 *prev = lock;
1428 lock->lf_next = overlap->lf_next;
1429 prev = &lock->lf_next;
1430 lock->create_lock_obj ();
1431 needtolink = 0;
1432 }
1433 else
1434 *prev = overlap->lf_next;
1435 overlap->lf_next = *clean;
1436 *clean = overlap;
1437 continue;
1438
025c1fac 1439 case 4: /* overlap starts before lock */
a998dd70
CV
1440 /*
1441 * Add lock after overlap on the list.
1442 */
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;
636c94d8 1447 lf_wakelock (overlap, fhdl);
a998dd70
CV
1448 overlap->create_lock_obj ();
1449 lock->create_lock_obj ();
1450 needtolink = 0;
1451 continue;
1452
025c1fac 1453 case 5: /* overlap ends after lock */
a998dd70
CV
1454 /*
1455 * Add the new lock before overlap.
1456 */
1457 if (needtolink) {
1458 *prev = lock;
1459 lock->lf_next = overlap;
1460 }
1461 overlap->lf_start = lock->lf_end + 1;
636c94d8 1462 lf_wakelock (overlap, fhdl);
a998dd70
CV
1463 lock->create_lock_obj ();
1464 overlap->create_lock_obj ();
1465 break;
1466 }
1467 break;
1468 }
1469 return 0;
1470}
1471
1472/*
1473 * Remove a byte-range lock on an inode_t.
1474 *
1475 * Generally, find the lock (or an overlap to that lock)
1476 * and remove it (or shrink it), then wakeup anyone we can.
1477 */
1478static int
636c94d8 1479lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl)
a998dd70
CV
1480{
1481 lockf_t **head = unlock->lf_head;
1482 lockf_t *lf = *head;
1483 lockf_t *overlap, **prev;
1484 int ovcase;
1485
1486 if (lf == NOLOCKF)
1487 return 0;
1488 prev = head;
1489 while ((ovcase = lf_findoverlap (lf, unlock, SELF, &prev, &overlap)))
1490 {
1491 /*
1492 * Wakeup the list of locks to be retried.
1493 */
636c94d8 1494 lf_wakelock (overlap, fhdl);
a998dd70
CV
1495
1496 switch (ovcase)
1497 {
025c1fac 1498 case 1: /* overlap == lock */
a998dd70
CV
1499 *prev = overlap->lf_next;
1500 overlap->lf_next = *clean;
1501 *clean = overlap;
1502 break;
1503
025c1fac 1504 case 2: /* overlap contains lock: split it */
a998dd70
CV
1505 if (overlap->lf_start == unlock->lf_start)
1506 {
1507 overlap->lf_start = unlock->lf_end + 1;
1508 overlap->create_lock_obj ();
1509 break;
1510 }
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;
1517
025c1fac 1518 case 3: /* lock contains overlap */
a998dd70
CV
1519 *prev = overlap->lf_next;
1520 lf = overlap->lf_next;
1521 overlap->lf_next = *clean;
1522 *clean = overlap;
1523 continue;
1524
025c1fac
CF
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;
a998dd70 1529 overlap->create_lock_obj ();
025c1fac 1530 continue;
a998dd70 1531
025c1fac
CF
1532 case 5: /* overlap ends after lock */
1533 overlap->lf_start = unlock->lf_end + 1;
a998dd70 1534 overlap->create_lock_obj ();
025c1fac 1535 break;
a998dd70
CV
1536 }
1537 break;
1538 }
1539 return 0;
1540}
1541
1542/*
1543 * Check whether there is a blocking lock,
1544 * and if so return its process identifier.
1545 */
1546static int
61522196 1547lf_getlock (lockf_t *lock, inode_t *node, struct flock *fl)
a998dd70
CV
1548{
1549 lockf_t *block;
30bbc55e 1550 tmp_pathbuf tp;
a998dd70 1551
31390e4c 1552 /* Create temporary space for the all locks list. */
30bbc55e 1553 node->i_all_lf = (lockf_t *) (void * ) tp.w_get ();
a998dd70
CV
1554 if ((block = lf_getblock (lock, node)))
1555 {
636c94d8 1556 if (block->lf_obj)
f4ec8743 1557 block->close_lock_obj ();
a998dd70
CV
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)
636c94d8 1566 fl->l_pid = (pid_t) block->lf_id;
a998dd70
CV
1567 else
1568 fl->l_pid = -1;
1569 }
1570 else
1571 fl->l_type = F_UNLCK;
a998dd70
CV
1572 return 0;
1573}
1574
1575/*
1576 * Walk the list of locks for an inode_t and
1577 * return the first blocking lock.
1578 */
1579static lockf_t *
1580lf_getblock (lockf_t *lock, inode_t *node)
025c1fac 1581{
31390e4c
CV
1582 lockf_t **prev, *overlap;
1583 lockf_t *lf = node->get_all_locks_list ();
a998dd70
CV
1584 int ovcase;
1585
1586 prev = lock->lf_head;
1587 while ((ovcase = lf_findoverlap (lf, lock, OTHERS, &prev, &overlap)))
1588 {
1589 /*
1590 * We've found an overlap, see if it blocks us
1591 */
1592 if ((lock->lf_type == F_WRLCK || overlap->lf_type == F_WRLCK))
636c94d8
CV
1593 {
1594 /* Open the event object for synchronization. */
f4ec8743
CV
1595 if (overlap->open_lock_obj ())
1596 {
5eb802f8
CV
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. */
f4ec8743
CV
1600 if (!IsEventSignalled (overlap->lf_obj))
1601 return overlap;
1602 overlap->close_lock_obj ();
1603 }
636c94d8 1604 }
a998dd70
CV
1605 /*
1606 * Nope, point to the next one on the list and
1607 * see if it blocks us
1608 */
1609 lf = overlap->lf_next;
1610 }
1611 return NOLOCKF;
1612}
1613
1614/*
1615 * Walk the list of locks for an inode_t to
1616 * find an overlapping lock (if any).
1617 *
1618 * NOTE: this returns only the FIRST overlapping lock. There
1619 * may be more than one.
025c1fac 1620 */
a998dd70
CV
1621static int
1622lf_findoverlap (lockf_t *lf, lockf_t *lock, int type, lockf_t ***prev,
1623 lockf_t **overlap)
1624{
61522196 1625 off_t start, end;
a998dd70
CV
1626
1627 *overlap = lf;
1628 if (lf == NOLOCKF)
1629 return 0;
1630
1631 start = lock->lf_start;
1632 end = lock->lf_end;
1633 while (lf != NOLOCKF)
1634 {
a74869c0
CV
1635 if (((type & SELF) && lf->lf_id != lock->lf_id)
1636 || ((type & OTHERS) && lf->lf_id == lock->lf_id)
636c94d8 1637 /* As on Linux: POSIX locks and BSD flock locks don't interact. */
072030c3
CV
1638 || (lf->lf_flags & (F_POSIX | F_FLOCK))
1639 != (lock->lf_flags & (F_POSIX | F_FLOCK)))
a998dd70
CV
1640 {
1641 *prev = &lf->lf_next;
1642 *overlap = lf = lf->lf_next;
1643 continue;
025c1fac 1644 }
a998dd70
CV
1645 /*
1646 * OK, check for overlap
1647 *
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
1655 */
1656 if ((lf->lf_end != -1 && start > lf->lf_end) ||
1657 (end != -1 && lf->lf_start > end))
1658 {
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;
025c1fac 1665 }
a998dd70
CV
1666 if ((lf->lf_start == start) && (lf->lf_end == end))
1667 {
1668 /* Case 1 */
1669 return 1;
1670 }
1671 if ((lf->lf_start <= start) && (end != -1) &&
1672 ((lf->lf_end >= end) || (lf->lf_end == -1)))
1673 {
1674 /* Case 2 */
1675 return 2;
1676 }
1677 if (start <= lf->lf_start && (end == -1 ||
1678 (lf->lf_end != -1 && end >= lf->lf_end)))
1679 {
1680 /* Case 3 */
1681 return 3;
1682 }
1683 if ((lf->lf_start < start) &&
1684 ((lf->lf_end >= start) || (lf->lf_end == -1)))
1685 {
1686 /* Case 4 */
1687 return 4;
1688 }
1689 if ((lf->lf_start > start) && (end != -1) &&
1690 ((lf->lf_end > end) || (lf->lf_end == -1)))
1691 {
1692 /* Case 5 */
1693 return 5;
1694 }
1695 api_fatal ("lf_findoverlap: default\n");
1696 }
1697 return 0;
1698}
1699
1700/*
1701 * Split a lock and a contained region into
1702 * two or three locks as necessary.
1703 */
1704static void
1705lf_split (lockf_t *lock1, lockf_t *lock2, lockf_t **split)
1706{
1707 lockf_t *splitlock;
1708
025c1fac 1709 /*
a998dd70
CV
1710 * Check to see if spliting into only two pieces.
1711 */
1712 if (lock1->lf_start == lock2->lf_start)
1713 {
1714 lock1->lf_start = lock2->lf_end + 1;
1715 lock2->lf_next = lock1;
1716 return;
1717 }
1718 if (lock1->lf_end == lock2->lf_end)
1719 {
1720 lock1->lf_end = lock2->lf_start - 1;
1721 lock2->lf_next = lock1->lf_next;
1722 lock1->lf_next = lock2;
1723 return;
1724 }
1725 /*
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.
1729 */
1730 splitlock = *split;
1731 assert (splitlock != NULL);
1732 *split = splitlock->lf_next;
f0cf44dc 1733 memcpy ((void *) splitlock, lock1, sizeof *splitlock);
a998dd70
CV
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;
1740 /*
1741 * OK, now link it in
1742 */
1743 splitlock->lf_next = lock1->lf_next;
1744 lock2->lf_next = splitlock;
1745 lock1->lf_next = lock2;
1746}
1747
1748/*
1749 * Wakeup a blocklist
1750 * Cygwin: Just signal the lock which gets removed. This unblocks
1751 * all threads waiting for this lock.
1752 */
1753static void
636c94d8 1754lf_wakelock (lockf_t *listhead, HANDLE fhdl)
a998dd70 1755{
636c94d8 1756 listhead->del_lock_obj (fhdl, true);
a998dd70 1757}
f3a1e23e 1758
fabfb1a1 1759extern "C" int
f3a1e23e
CV
1760flock (int fd, int operation)
1761{
fabfb1a1
CV
1762 int res = -1;
1763 int cmd;
61522196 1764 struct flock fl = { 0, SEEK_SET, 0, 0, 0 };
fabfb1a1 1765
3f3bd101 1766 __try
f3a1e23e 1767 {
41299df0 1768 cygheap_fdget cfd (fd);
3f3bd101
CV
1769 if (cfd < 0)
1770 __leave;
1771
1772 cmd = (operation & LOCK_NB) ? F_SETLK : F_SETLKW;
1773 switch (operation & (~LOCK_NB))
1774 {
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;
1787 }
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);
f3a1e23e 1794 }
3f3bd101
CV
1795 __except (EFAULT) {}
1796 __endtry
b9aa8149 1797 syscall_printf ("%R = flock(%d, %d)", res, fd, operation);
fabfb1a1 1798 return res;
f3a1e23e
CV
1799}
1800
a998dd70 1801extern "C" int
61522196 1802lockf (int filedes, int function, off_t size)
f3a1e23e 1803{
fabfb1a1 1804 int res = -1;
a998dd70 1805 int cmd;
61522196 1806 struct flock fl;
fabfb1a1 1807
1804be04
CV
1808 pthread_testcancel ();
1809
3f3bd101
CV
1810 __try
1811 {
41299df0 1812 cygheap_fdget cfd (filedes);
3f3bd101
CV
1813 if (cfd < 0)
1814 __leave;
a998dd70 1815
3f3bd101
CV
1816 fl.l_start = 0;
1817 fl.l_len = size;
1818 fl.l_whence = SEEK_CUR;
a998dd70 1819
3f3bd101
CV
1820 switch (function)
1821 {
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 */
1848 }
1849 res = cfd->mandatory_locking () ? cfd->mand_lock (cmd, &fl)
1850 : cfd->lock (cmd, &fl);
a998dd70 1851 }
3f3bd101
CV
1852 __except (EFAULT) {}
1853 __endtry
b9aa8149 1854 syscall_printf ("%R = lockf(%d, %d, %D)", res, filedes, function, size);
fabfb1a1 1855 return res;
f3a1e23e 1856}
a24ad2c3
CV
1857
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. */
1862struct lock_parms {
1863 HANDLE h;
1864 PIO_STATUS_BLOCK pio;
1865 PLARGE_INTEGER poff;
1866 PLARGE_INTEGER plen;
1867 BOOL type;
1868 NTSTATUS status;
1869};
1870
b28edc7b 1871static DWORD
a24ad2c3
CV
1872blocking_lock_thr (LPVOID param)
1873{
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;
1878}
1879
edd73646
CV
1880int
1881fhandler_base::mand_lock (int, struct flock *)
1882{
1883 set_errno (EINVAL);
1884 return -1;
1885}
1886
a24ad2c3
CV
1887int
1888fhandler_disk_file::mand_lock (int a_op, struct flock *fl)
1889{
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;
1897
1898 /* Calculate where to start from, then adjust this by fl->l_start. */
1899 switch (fl->l_whence)
1900 {
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))
1908 {
1909 __seterrno_from_nt_status (status);
1910 return -1;
1911 }
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))
1918 {
1919 __seterrno_from_nt_status (status);
1920 return -1;
1921 }
1922 startpos = fsi.EndOfFile.QuadPart;
1923 break;
1924 default:
1925 set_errno (EINVAL);
1926 return -1;
1927 }
1928 /* Adjust start and length until they make sense. */
1929 offset.QuadPart = startpos + fl->l_start;
1930 if (fl->l_len < 0)
1931 {
1932 offset.QuadPart -= fl->l_len;
1933 length.QuadPart = -fl->l_len;
1934 }
1935 else
1936 length.QuadPart = fl->l_len;
1937 if (offset.QuadPart < 0)
1938 {
1939 length.QuadPart -= -offset.QuadPart;
1940 if (length.QuadPart <= 0)
1941 {
1942 set_errno (EINVAL);
1943 return -1;
1944 }
1945 offset.QuadPart = 0;
1946 }
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)
1953 {
1954 status = NtUnlockFile (get_handle (), &io, &offset, &length, 0);
1955 if (status == STATUS_RANGE_NOT_LOCKED) /* Not an error */
1956 status = STATUS_SUCCESS;
1957 }
1958 else if (a_op == F_SETLKW)
1959 {
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;
1974
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)
1981 {
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);
1987 }
1988 else
1989 {
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)
1996 {
1997 case WAIT_OBJECT_0:
1998 /* Fetch completion status. */
1999 status = lp.status;
2000 thr->detach ();
2001 break;
2002 default:
450b2dc8
CV
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. */
a24ad2c3
CV
2009 if (CancelSynchronousIo (thr->thread_handle ()))
2010 thr->detach ();
2011 else
d2ef2331 2012 thr->terminate_thread ();
a24ad2c3
CV
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;
2022 }
2023 }
2024 }
2025 else
2026 {
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)
2030 {
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))
2035 {
2036 NtUnlockFile (get_handle (), &io, &offset, &length, 0);
2037 fl->l_type = F_UNLCK;
2038 }
2039 else
2040 {
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;
2047 }
2048 status = STATUS_SUCCESS;
2049 }
2050 }
2051 if (!NT_SUCCESS (status))
2052 {
2053 __seterrno_from_nt_status (status);
2054 return -1;
2055 }
2056 return 0;
2057}
This page took 0.631884 seconds and 6 git commands to generate.