]> sourceware.org Git - newlib-cygwin.git/commitdiff
cygwin: Implement renameat2
authorKen Brown <kbrown@cornell.edu>
Thu, 17 Aug 2017 13:12:15 +0000 (09:12 -0400)
committerCorinna Vinschen <corinna@vinschen.de>
Sat, 19 Aug 2017 16:06:49 +0000 (18:06 +0200)
Define the RENAME_NOREPLACE flag in <cygwin/fs.h> as defined on Linux
in <linux/fs.h>.  The other RENAME_* flags defined on Linux are not
supported.

newlib/libc/include/stdio.h
winsup/cygwin/common.din
winsup/cygwin/include/cygwin/fs.h
winsup/cygwin/include/cygwin/version.h
winsup/cygwin/syscalls.cc

index 5d8cb10920b33e45248e713c5eb390f918cf477d..331a1cf0724923ec828d4278d758484fc1a3b1f3 100644 (file)
@@ -384,6 +384,9 @@ int _EXFUN(vdprintf, (int, const char *__restrict, __VALIST)
 #endif
 #if __ATFILE_VISIBLE
 int    _EXFUN(renameat, (int, const char *, int, const char *));
+# ifdef __CYGWIN__
+int    _EXFUN(renameat2, (int, const char *, int, const char *, unsigned int));
+# endif
 #endif
 
 /*
index 8da432b8a94a971da87db1095d26be2b5616a2be..ca6ff3cf93b9b257e23b9b22a998380eba932f68 100644 (file)
@@ -1168,6 +1168,7 @@ remquof NOSIGFE
 remquol NOSIGFE
 rename SIGFE
 renameat SIGFE
+renameat2 SIGFE
 res_close = __res_close SIGFE
 res_init = __res_init SIGFE
 res_mkquery = __res_mkquery SIGFE
index f606ffc3911390d58d56e4a1f1c5b6dc081fe3ac..48b0cca45c1ed4e01f134df5f63cf657d7624b18 100644 (file)
@@ -19,4 +19,10 @@ details. */
 #define BLKPBSZGET   0x0000127b
 #define BLKGETSIZE64 0x00041268
 
+/* Flags for renameat2, from /usr/include/linux/fs.h.  For now we
+   support only RENAME_NOREPLACE. */
+#define RENAME_NOREPLACE (1 << 0)
+/* #define RENAME_EXCHANGE  (1 << 1) */
+/* #define RENAME_WHITEOUT  (1 << 2) */
+
 #endif
index efd4ac017f4d4203bb8d8ef799c34c00e00482ec..7686a686526c4821737f84096f929a172a4be42d 100644 (file)
@@ -481,12 +481,13 @@ details. */
   314: Export explicit_bzero.
   315: Export pthread_mutex_timedlock.
   316: Export pthread_rwlock_timedrdlock, pthread_rwlock_timedwrlock.
+  317: Export renameat2.
 
   Note that we forgot to bump the api for ualarm, strtoll, strtoull,
   sigaltstack, sethostname. */
 
 #define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 316
+#define CYGWIN_VERSION_API_MINOR 317
 
 /* There is also a compatibity version number associated with the shared memory
    regions.  It is incremented when incompatible changes are made to the shared
index 885931632ba38b1259930e1d0121d2be21d644e3..61872fe58a3d83372d27b66645ec8871f630daff 100644 (file)
@@ -60,6 +60,7 @@ details. */
 #include "tls_pbuf.h"
 #include "sync.h"
 #include "child_info.h"
+#include <cygwin/fs.h>  /* needed for RENAME_NOREPLACE */
 
 #undef _close
 #undef _lseek
@@ -2048,14 +2049,19 @@ nt_path_has_executable_suffix (PUNICODE_STRING upath)
   return false;
 }
 
-extern "C" int
-rename (const char *oldpath, const char *newpath)
+/* If newpath names an existing file and the RENAME_NOREPLACE flag is
+   specified, fail with EEXIST.  Exception: Don't fail if the purpose
+   of the rename is just to change the case of oldpath on a
+   case-insensitive file system. */
+static int
+rename2 (const char *oldpath, const char *newpath, unsigned int flags)
 {
   tmp_pathbuf tp;
   int res = -1;
   path_conv oldpc, newpc, new2pc, *dstpc, *removepc = NULL;
   bool old_dir_requested = false, new_dir_requested = false;
   bool old_explicit_suffix = false, new_explicit_suffix = false;
+  bool noreplace = flags & RENAME_NOREPLACE;
   size_t olen, nlen;
   bool equal_path;
   NTSTATUS status = STATUS_SUCCESS;
@@ -2068,6 +2074,12 @@ rename (const char *oldpath, const char *newpath)
 
   __try
     {
+      if (flags & ~RENAME_NOREPLACE)
+       /* RENAME_NOREPLACE is the only flag currently supported. */
+       {
+         set_errno (EINVAL);
+         __leave;
+       }
       if (!*oldpath || !*newpath)
        {
          /* Reject rename("","x"), rename("x","").  */
@@ -2337,6 +2349,13 @@ rename (const char *oldpath, const char *newpath)
          __leave;
        }
 
+      /* Should we replace an existing file? */
+      if ((removepc || dstpc->exists ()) && noreplace)
+       {
+         set_errno (EEXIST);
+         __leave;
+       }
+
       /* Opening the file must be part of the transaction.  It's not sufficient
         to call only NtSetInformationFile under the transaction.  Therefore we
         have to start the transaction here, if necessary. */
@@ -2491,11 +2510,15 @@ rename (const char *oldpath, const char *newpath)
          __leave;
        }
       pfri = (PFILE_RENAME_INFORMATION) tp.w_get ();
-      pfri->ReplaceIfExists = TRUE;
+      pfri->ReplaceIfExists = !noreplace;
       pfri->RootDirectory = NULL;
       pfri->FileNameLength = dstpc->get_nt_native_path ()->Length;
       memcpy (&pfri->FileName,  dstpc->get_nt_native_path ()->Buffer,
              pfri->FileNameLength);
+      /* If dstpc points to an existing file and RENAME_NOREPLACE has
+        been specified, then we should get NT error
+        STATUS_OBJECT_NAME_COLLISION ==> Win32 error
+        ERROR_ALREADY_EXISTS ==> Cygwin error EEXIST. */
       status = NtSetInformationFile (fh, &io, pfri,
                                     sizeof *pfri + pfri->FileNameLength,
                                     FileRenameInformation);
@@ -2578,6 +2601,12 @@ rename (const char *oldpath, const char *newpath)
   return res;
 }
 
+extern "C" int
+rename (const char *oldpath, const char *newpath)
+{
+  return rename2 (oldpath, newpath, 0);
+}
+
 extern "C" int
 system (const char *cmdstring)
 {
@@ -4719,8 +4748,8 @@ readlinkat (int dirfd, const char *__restrict pathname, char *__restrict buf,
 }
 
 extern "C" int
-renameat (int olddirfd, const char *oldpathname,
-         int newdirfd, const char *newpathname)
+renameat2 (int olddirfd, const char *oldpathname,
+          int newdirfd, const char *newpathname, unsigned int flags)
 {
   tmp_pathbuf tp;
   __try
@@ -4731,13 +4760,20 @@ renameat (int olddirfd, const char *oldpathname,
       char *newpath = tp.c_get ();
       if (gen_full_path_at (newpath, newdirfd, newpathname))
        __leave;
-      return rename (oldpath, newpath);
+      return rename2 (oldpath, newpath, flags);
     }
   __except (EFAULT) {}
   __endtry
   return -1;
 }
 
+extern "C" int
+renameat (int olddirfd, const char *oldpathname,
+         int newdirfd, const char *newpathname)
+{
+  return renameat2 (olddirfd, oldpathname, newdirfd, newpathname, 0);
+}
+
 extern "C" int
 scandirat (int dirfd, const char *pathname, struct dirent ***namelist,
           int (*select) (const struct dirent *),
This page took 0.0449 seconds and 5 git commands to generate.