* autoload.cc (CancelSynchronousIo): Define.
* fcntl.cc (fcntl64): Drop handling of locking commands. * fhandler.h (class fhandler_disk_file): Add mandatory_locking. (fhandler_disk_file::fcntl): Declare. (fhandler_disk_file::mand_lock): Declare. * fhandler_disk_file.cc (fhandler_disk_file::fhandler_disk_file): Initialize mandatory_locking. (fhandler_disk_file::fcntl): New method. Handle F_LCK_MANDATORY and locking commands. (fhandler_disk_file::dup): Duplicate mandatory_locking. Fix a bug when duplicating prw_handle failed. (fhandler_disk_file::fixup_after_fork): Reset mandatory_locking. * flock.cc (fhandler_disk_file::lock): Add comment. (struct lock_parms): New struct to pass parameters to blocking_lock_thr thread function. (blocking_lock_thr): New thread function. (fhandler_disk_file::mand_lock): New methof implementing mandatory locking with Windows semantics. * ntdll.h (NtLockFile): Declare. (NtUnlockFile): Declare. * include/fcntl.h: Fix a comment. (F_LCK_MANDATORY): Define. Add lengthy comment to explain.
This commit is contained in:
parent
fa35814af1
commit
a24ad2c346
|
@ -1,3 +1,28 @@
|
|||
2013-06-02 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* autoload.cc (CancelSynchronousIo): Define.
|
||||
* fcntl.cc (fcntl64): Drop handling of locking commands.
|
||||
* fhandler.h (class fhandler_disk_file): Add mandatory_locking.
|
||||
(fhandler_disk_file::fcntl): Declare.
|
||||
(fhandler_disk_file::mand_lock): Declare.
|
||||
* fhandler_disk_file.cc (fhandler_disk_file::fhandler_disk_file):
|
||||
Initialize mandatory_locking.
|
||||
(fhandler_disk_file::fcntl): New method. Handle F_LCK_MANDATORY and
|
||||
locking commands.
|
||||
(fhandler_disk_file::dup): Duplicate mandatory_locking. Fix a bug
|
||||
when duplicating prw_handle failed.
|
||||
(fhandler_disk_file::fixup_after_fork): Reset mandatory_locking.
|
||||
* flock.cc (fhandler_disk_file::lock): Add comment.
|
||||
(struct lock_parms): New struct to pass parameters to blocking_lock_thr
|
||||
thread function.
|
||||
(blocking_lock_thr): New thread function.
|
||||
(fhandler_disk_file::mand_lock): New methof implementing mandatory
|
||||
locking with Windows semantics.
|
||||
* ntdll.h (NtLockFile): Declare.
|
||||
(NtUnlockFile): Declare.
|
||||
* include/fcntl.h: Fix a comment.
|
||||
(F_LCK_MANDATORY): Define. Add lengthy comment to explain.
|
||||
|
||||
2013-06-02 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* exceptions.cc (exception::handle): Resurrect accidentally lost
|
||||
|
|
|
@ -574,6 +574,7 @@ LoadDLLfunc (GetIpForwardTable, 12, iphlpapi)
|
|||
LoadDLLfunc (GetNetworkParams, 8, iphlpapi)
|
||||
LoadDLLfunc (GetUdpTable, 12, iphlpapi)
|
||||
|
||||
LoadDLLfuncEx (CancelSynchronousIo, 4, kernel32, 1)
|
||||
LoadDLLfunc (CreateSymbolicLinkW, 12, kernel32)
|
||||
LoadDLLfuncEx (GetNamedPipeClientProcessId, 8, kernel32, 1)
|
||||
LoadDLLfunc (LocaleNameToLCID, 8, kernel32)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* fcntl.cc: fcntl syscall
|
||||
|
||||
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2008, 2009,
|
||||
2010, 2011, 2012 Red Hat, Inc.
|
||||
2010, 2011, 2012, 2013 Red Hat, Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
|
@ -70,15 +70,6 @@ fcntl64 (int fd, int cmd, ...)
|
|||
res = -1;
|
||||
}
|
||||
break;
|
||||
case F_GETLK:
|
||||
case F_SETLK:
|
||||
case F_SETLKW:
|
||||
{
|
||||
struct flock *fl = (struct flock *) arg;
|
||||
fl->l_type &= F_RDLCK | F_WRLCK | F_UNLCK;
|
||||
res = cfd->lock (cmd, fl);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
res = cfd->fcntl (cmd, arg);
|
||||
break;
|
||||
|
|
|
@ -963,6 +963,7 @@ class fhandler_dev_tape: public fhandler_dev_raw
|
|||
class fhandler_disk_file: public fhandler_base
|
||||
{
|
||||
HANDLE prw_handle;
|
||||
bool mandatory_locking;
|
||||
int __reg3 readdir_helper (DIR *, dirent *, DWORD, DWORD, PUNICODE_STRING fname);
|
||||
|
||||
int prw_open (bool);
|
||||
|
@ -973,9 +974,11 @@ class fhandler_disk_file: public fhandler_base
|
|||
|
||||
int open (int flags, mode_t mode);
|
||||
int close ();
|
||||
int fcntl (int cmd, intptr_t);
|
||||
int dup (fhandler_base *child, int);
|
||||
void fixup_after_fork (HANDLE parent);
|
||||
int lock (int, struct flock *);
|
||||
int mand_lock (int, struct flock *);
|
||||
bool isdevice () const { return false; }
|
||||
int __reg2 fstat (struct stat *buf);
|
||||
int __reg1 fchmod (mode_t mode);
|
||||
|
|
|
@ -1379,12 +1379,12 @@ fhandler_base::utimens_fs (const struct timespec *tvp)
|
|||
}
|
||||
|
||||
fhandler_disk_file::fhandler_disk_file () :
|
||||
fhandler_base (), prw_handle (NULL)
|
||||
fhandler_base (), prw_handle (NULL), mandatory_locking (false)
|
||||
{
|
||||
}
|
||||
|
||||
fhandler_disk_file::fhandler_disk_file (path_conv &pc) :
|
||||
fhandler_base (), prw_handle (NULL)
|
||||
fhandler_base (), prw_handle (NULL), mandatory_locking (false)
|
||||
{
|
||||
set_name (pc);
|
||||
}
|
||||
|
@ -1407,6 +1407,33 @@ fhandler_disk_file::close ()
|
|||
return fhandler_base::close ();
|
||||
}
|
||||
|
||||
int
|
||||
fhandler_disk_file::fcntl (int cmd, intptr_t arg)
|
||||
{
|
||||
int res;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case F_LCK_MANDATORY:
|
||||
mandatory_locking = !!arg;
|
||||
res = 0;
|
||||
break;
|
||||
case F_GETLK:
|
||||
case F_SETLK:
|
||||
case F_SETLKW:
|
||||
{
|
||||
struct flock *fl = (struct flock *) arg;
|
||||
fl->l_type &= F_RDLCK | F_WRLCK | F_UNLCK;
|
||||
res = mandatory_locking ? mand_lock (cmd, fl) : lock (cmd, fl);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
res = fhandler_base::fcntl (cmd, arg);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
fhandler_disk_file::dup (fhandler_base *child, int flags)
|
||||
{
|
||||
|
@ -1417,7 +1444,8 @@ fhandler_disk_file::dup (fhandler_base *child, int flags)
|
|||
&& !DuplicateHandle (GetCurrentProcess (), prw_handle,
|
||||
GetCurrentProcess (), &fhc->prw_handle,
|
||||
0, TRUE, DUPLICATE_SAME_ACCESS))
|
||||
prw_handle = NULL;
|
||||
fhc->prw_handle = NULL;
|
||||
fhc->mandatory_locking = mandatory_locking;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1425,6 +1453,7 @@ void
|
|||
fhandler_disk_file::fixup_after_fork (HANDLE parent)
|
||||
{
|
||||
prw_handle = NULL;
|
||||
mandatory_locking = false;
|
||||
fhandler_base::fixup_after_fork (parent);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* flock.cc. NT specific implementation of advisory file locking.
|
||||
|
||||
Copyright 2003, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc.
|
||||
Copyright 2003, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
|
@ -915,6 +915,9 @@ static int lf_setlock (lockf_t *, inode_t *, lockf_t **, HANDLE);
|
|||
static void lf_split (lockf_t *, lockf_t *, lockf_t **);
|
||||
static void lf_wakelock (lockf_t *, HANDLE);
|
||||
|
||||
/* This is the fcntl advisory lock implementation. For the implementation
|
||||
of mandatory locks using the Windows mandatory locking functions, see the
|
||||
fhandler_disk_file::mand_lock method at the end of this file. */
|
||||
int
|
||||
fhandler_disk_file::lock (int a_op, struct flock *fl)
|
||||
{
|
||||
|
@ -1805,3 +1808,199 @@ done:
|
|||
syscall_printf ("%R = lockf(%d, %d, %D)", res, filedes, function, size);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* This is the fcntl lock implementation for mandatory locks using the
|
||||
Windows mandatory locking functions. For the UNIX-like advisory locking
|
||||
implementation see the fhandler_disk_file::lock method earlier in this
|
||||
file. */
|
||||
struct lock_parms {
|
||||
HANDLE h;
|
||||
PIO_STATUS_BLOCK pio;
|
||||
PLARGE_INTEGER poff;
|
||||
PLARGE_INTEGER plen;
|
||||
BOOL type;
|
||||
NTSTATUS status;
|
||||
};
|
||||
|
||||
static DWORD WINAPI
|
||||
blocking_lock_thr (LPVOID param)
|
||||
{
|
||||
struct lock_parms *lp = (struct lock_parms *) param;
|
||||
lp->status = NtLockFile (lp->h, NULL, NULL, NULL, lp->pio, lp->poff,
|
||||
lp->plen, 0, FALSE, lp->type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fhandler_disk_file::mand_lock (int a_op, struct flock *fl)
|
||||
{
|
||||
NTSTATUS status;
|
||||
IO_STATUS_BLOCK io;
|
||||
FILE_POSITION_INFORMATION fpi;
|
||||
FILE_STANDARD_INFORMATION fsi;
|
||||
off_t startpos;
|
||||
LARGE_INTEGER offset;
|
||||
LARGE_INTEGER length;
|
||||
|
||||
/* Calculate where to start from, then adjust this by fl->l_start. */
|
||||
switch (fl->l_whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
startpos = 0;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
status = NtQueryInformationFile (get_handle (), &io, &fpi, sizeof fpi,
|
||||
FilePositionInformation);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
__seterrno_from_nt_status (status);
|
||||
return -1;
|
||||
}
|
||||
startpos = fpi.CurrentByteOffset.QuadPart;
|
||||
break;
|
||||
case SEEK_END:
|
||||
status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi,
|
||||
FileStandardInformation);
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
__seterrno_from_nt_status (status);
|
||||
return -1;
|
||||
}
|
||||
startpos = fsi.EndOfFile.QuadPart;
|
||||
break;
|
||||
default:
|
||||
set_errno (EINVAL);
|
||||
return -1;
|
||||
}
|
||||
/* Adjust start and length until they make sense. */
|
||||
offset.QuadPart = startpos + fl->l_start;
|
||||
if (fl->l_len < 0)
|
||||
{
|
||||
offset.QuadPart -= fl->l_len;
|
||||
length.QuadPart = -fl->l_len;
|
||||
}
|
||||
else
|
||||
length.QuadPart = fl->l_len;
|
||||
if (offset.QuadPart < 0)
|
||||
{
|
||||
length.QuadPart -= -offset.QuadPart;
|
||||
if (length.QuadPart <= 0)
|
||||
{
|
||||
set_errno (EINVAL);
|
||||
return -1;
|
||||
}
|
||||
offset.QuadPart = 0;
|
||||
}
|
||||
/* Special case if len == 0. For POSIX this means lock to the end of
|
||||
the entire file, even when file grows later. */
|
||||
if (length.QuadPart == 0)
|
||||
length.QuadPart = UINT64_MAX;
|
||||
/* Action! */
|
||||
if (fl->l_type == F_UNLCK)
|
||||
{
|
||||
status = NtUnlockFile (get_handle (), &io, &offset, &length, 0);
|
||||
if (status == STATUS_RANGE_NOT_LOCKED) /* Not an error */
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
else if (a_op == F_SETLKW)
|
||||
{
|
||||
/* We open file handles synchronously. To allow asynchronous operation
|
||||
the file locking functions require a file handle opened in asynchronous
|
||||
mode. Since Windows locks are per-process/per-file object, we can't
|
||||
open another handle asynchrously and lock/unlock using that handle:
|
||||
The original file handle would not have placed the lock and would be
|
||||
restricted by the lock like any other file handle.
|
||||
So, what we do here is to start a thread which calls the potentially
|
||||
blocking NtLockFile call. Then we wait for thread completion in an
|
||||
interruptible fashion. */
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
HANDLE evt;
|
||||
struct lock_parms lp = { get_handle (), &io, &offset, &length,
|
||||
fl->l_type == F_WRLCK, 0 };
|
||||
cygthread *thr = NULL;
|
||||
|
||||
InitializeObjectAttributes (&attr, NULL, 0, NULL, NULL);
|
||||
status = NtCreateEvent (&evt, EVENT_ALL_ACCESS, &attr,
|
||||
NotificationEvent, FALSE);
|
||||
if (evt)
|
||||
thr = new cygthread (blocking_lock_thr, &lp, "blk_lock", evt);
|
||||
if (!thr)
|
||||
{
|
||||
/* Thread creation failed. Fall back to blocking lock call. */
|
||||
if (evt)
|
||||
NtClose (evt);
|
||||
status = NtLockFile (get_handle (), NULL, NULL, NULL, &io, &offset,
|
||||
&length, 0, FALSE, fl->l_type == F_WRLCK);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* F_SETLKW and lock cannot be established. Wait until the lock can
|
||||
be established, or a signal request arrived. We deliberately
|
||||
don't handle thread cancel requests here. */
|
||||
DWORD wait_res = cygwait (evt, INFINITE, cw_sig | cw_sig_eintr);
|
||||
NtClose (evt);
|
||||
switch (wait_res)
|
||||
{
|
||||
case WAIT_OBJECT_0:
|
||||
/* Fetch completion status. */
|
||||
status = lp.status;
|
||||
thr->detach ();
|
||||
break;
|
||||
default:
|
||||
/* Signal arrived. */
|
||||
/* Starting with Vista, CancelSynchronousIo works, and we wait
|
||||
for the thread to exit. lp.status will be either
|
||||
STATUS_SUCCESS, or STATUS_CANCELLED. We only call
|
||||
NtUnlockFile in the first case.
|
||||
Prior to Vista, CancelSynchronousIo doesn't exist, so we
|
||||
terminated the thread and always call NtUnlockFile since
|
||||
lp.status was 0 to begin with. */
|
||||
if (CancelSynchronousIo (thr->thread_handle ()))
|
||||
thr->detach ();
|
||||
else
|
||||
thr->terminate_thread ();
|
||||
if (NT_SUCCESS (lp.status))
|
||||
NtUnlockFile (get_handle (), &io, &offset, &length, 0);
|
||||
/* Per SUSv4: If a signal is received while fcntl is waiting,
|
||||
fcntl shall be interrupted. Upon return from the signal
|
||||
handler, fcntl shall return -1 with errno set to EINTR,
|
||||
and the lock operation shall not be done. */
|
||||
_my_tls.call_signal_handler ();
|
||||
set_errno (EINTR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = NtLockFile (get_handle (), NULL, NULL, NULL, &io, &offset,
|
||||
&length, 0, TRUE, fl->l_type == F_WRLCK);
|
||||
if (a_op == F_GETLK)
|
||||
{
|
||||
/* This is non-atomic, but there's no other way on Windows to detect
|
||||
if another lock is blocking our lock, other than trying to place
|
||||
the lock, and then having to unlock it again. */
|
||||
if (NT_SUCCESS (status))
|
||||
{
|
||||
NtUnlockFile (get_handle (), &io, &offset, &length, 0);
|
||||
fl->l_type = F_UNLCK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FAKE! FAKE! FAKE! */
|
||||
fl->l_type = F_WRLCK;
|
||||
fl->l_whence = SEEK_SET;
|
||||
fl->l_start = offset.QuadPart;
|
||||
fl->l_len = length.QuadPart;
|
||||
fl->l_pid = (pid_t) -1;
|
||||
}
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
if (!NT_SUCCESS (status))
|
||||
{
|
||||
__seterrno_from_nt_status (status);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* fcntl.h
|
||||
|
||||
Copyright 1996, 1998, 2000, 2001, 2005, 2006, 2009, 2010 Red Hat, Inc.
|
||||
Copyright 1996, 1998, 2000, 2001, 2005, 2006, 2009, 2010, 2013 Red Hat, Inc.
|
||||
|
||||
This file is part of Cygwin.
|
||||
|
||||
|
@ -14,12 +14,29 @@ details. */
|
|||
#include <sys/fcntl.h>
|
||||
#define O_NDELAY _FNDELAY
|
||||
|
||||
/* sys/fcntl defines values up to 0x40000 (O_NOINHERIT). */
|
||||
/* sys/_default_fcntl.h defines values up to 0x40000 (O_NOINHERIT). */
|
||||
#define _FDIRECT 0x80000
|
||||
#define _FNOFOLLOW 0x100000
|
||||
#define _FDIRECTORY 0x200000
|
||||
#define _FEXECSRCH 0x400000
|
||||
|
||||
/* F_LCK_MANDATORY: Request mandatory locks for this file descriptor.
|
||||
|
||||
Cygwin extension to fcntl file locking mechanism. By default, fcntl file
|
||||
locks are advisory locks. This works nicely as long as only Cygwin
|
||||
processes interact. If you have the requirement to interact with native
|
||||
Windows applications which use Windows mandatory file locking, your have
|
||||
to use mandatory locking as well. The command
|
||||
|
||||
fcntl (fd, F_LCK_MANDATORY, 1)
|
||||
|
||||
switches subsequent F_GETLK, F_SETLK, F_SETLKW calls to mandatory locking
|
||||
for this file descriptor and subsequently duplicated ones WITHIN THE SAME
|
||||
PROCESS. Note that mandatory locks are NOT inherited by child processes,
|
||||
nor do they survive an execve call. This fully corresponds to Windows
|
||||
mandatory locking semantics. */
|
||||
#define F_LCK_MANDATORY 0x99
|
||||
|
||||
/* POSIX-1.2008 requires this flag and allows to set it to 0 if its
|
||||
functionality is not required. */
|
||||
#define O_TTY_INIT 0
|
||||
|
|
|
@ -1224,6 +1224,9 @@ extern "C"
|
|||
PVOID, ULONG);
|
||||
NTSTATUS NTAPI NtFlushBuffersFile (HANDLE, PIO_STATUS_BLOCK);
|
||||
NTSTATUS NTAPI NtLoadKey (POBJECT_ATTRIBUTES, POBJECT_ATTRIBUTES);
|
||||
NTSTATUS NTAPI NtLockFile (HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID,
|
||||
PIO_STATUS_BLOCK, PLARGE_INTEGER, PLARGE_INTEGER,
|
||||
ULONG, BOOLEAN, BOOLEAN);
|
||||
NTSTATUS NTAPI NtLockVirtualMemory (HANDLE, PVOID *, PSIZE_T, ULONG);
|
||||
NTSTATUS NTAPI NtMapViewOfSection (HANDLE, HANDLE, PVOID *, ULONG_PTR, SIZE_T,
|
||||
PLARGE_INTEGER, PSIZE_T, SECTION_INHERIT,
|
||||
|
@ -1308,6 +1311,8 @@ extern "C"
|
|||
NTSTATUS NTAPI NtSetTimerResolution (ULONG, BOOLEAN, PULONG);
|
||||
NTSTATUS NTAPI NtSetValueKey (HANDLE, PUNICODE_STRING, ULONG, ULONG, PVOID,
|
||||
ULONG);
|
||||
NTSTATUS NTAPI NtUnlockFile (HANDLE, PIO_STATUS_BLOCK, PLARGE_INTEGER,
|
||||
PLARGE_INTEGER, ULONG);
|
||||
NTSTATUS NTAPI NtUnlockVirtualMemory (HANDLE, PVOID *, PSIZE_T, ULONG);
|
||||
NTSTATUS NTAPI NtUnmapViewOfSection (HANDLE, PVOID);
|
||||
NTSTATUS NTAPI NtWriteFile (HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID,
|
||||
|
|
|
@ -10,6 +10,9 @@ What's new:
|
|||
|
||||
- Add support for the AFS filesystem.
|
||||
|
||||
- Preliminary support for mandatory locking via fcntl, using Windows
|
||||
locking semantics. New F_LCK_MANDATORY fcntl command.
|
||||
|
||||
- New APIs: __b64_ntop, __b64_pton, arc4random, arc4random_addrandom,
|
||||
arc4random_buf, arc4random_stir, arc4random_uniform.
|
||||
|
||||
|
|
Loading…
Reference in New Issue