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