* 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:
Corinna Vinschen 2013-06-02 10:22:14 +00:00
parent fa35814af1
commit a24ad2c346
9 changed files with 289 additions and 16 deletions

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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,

View File

@ -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.