* 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>
+
+ * 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
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)
/* 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.
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;
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);
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);
}
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);
}
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)
{
&& !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;
}
fhandler_disk_file::fixup_after_fork (HANDLE parent)
{
prw_handle = NULL;
+ mandatory_locking = false;
fhandler_base::fixup_after_fork (parent);
}
/* 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.
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)
{
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;
+}
/* 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.
#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
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,
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,
- 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.