]> sourceware.org Git - newlib-cygwin.git/commitdiff
* autoload.cc (CancelSynchronousIo): Define.
authorCorinna Vinschen <corinna@vinschen.de>
Sun, 2 Jun 2013 10:22:14 +0000 (10:22 +0000)
committerCorinna Vinschen <corinna@vinschen.de>
Sun, 2 Jun 2013 10:22:14 +0000 (10:22 +0000)
* 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.

winsup/cygwin/ChangeLog
winsup/cygwin/autoload.cc
winsup/cygwin/fcntl.cc
winsup/cygwin/fhandler.h
winsup/cygwin/fhandler_disk_file.cc
winsup/cygwin/flock.cc
winsup/cygwin/include/fcntl.h
winsup/cygwin/ntdll.h
winsup/cygwin/release/1.7.19

index 3d18cd50bcaa8ec88aa452cd5da67404641dba27..b54060ab283b6034a170f14b4e5c5416107e9e44 100644 (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
index f545826c1ac9ccd6090c19e13155205f5fdc5194..75771a2b6dbe3d25330e3ae189d9c31995df8c25 100644 (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)
index f2c2acc2526880dbdbafd5da904a228816997fb0..ea9a71a5ee07b7ba22a0efd6856fac15624c83a7 100644 (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;
index e76f67e1fe5071e389a2759e7deb513257632920..76e0ea768944c574af337f5f5877ad733105ae94 100644 (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);
index 80ebfce487205c93ee447a6745624bdaeab8d0a3..1b76a34884a68a9257bec345223996fe8de26b46 100644 (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);
 }
 
index 1e875113de049d873b7c94a811c7c78ebc04197d..f7d19398b67f3cecc7165e8fc9d04bfe826f851b 100644 (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;
+}
index 9c3ddf9262737b8a0f71df3d5086d100a7bf861d..fe8a1fc42f8bc77481055559ef1dfa9e4c57ab5d 100644 (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
index 4d302ffe72de1c0a49b106904662ada5d1e1bfd4..2582bf25febb126d98c000451a81e5e736fd1973 100644 (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,
index 93240415347e003a2367348255b474845817e5a0..7cae9ad989e42cb0a60d234704631c32ee6159c6 100644 (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.
 
This page took 0.05302 seconds and 5 git commands to generate.