]> git.eshelyaron.com Git - emacs.git/commitdiff
Port recent rename changes to RHEL 7 + NFS
authorPaul Eggert <eggert@cs.ucla.edu>
Thu, 3 Aug 2017 23:18:45 +0000 (16:18 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Thu, 3 Aug 2017 23:19:21 +0000 (16:19 -0700)
Problem reported by Ted Zlatanov in:
http://lists.gnu.org/archive/html/emacs-devel/2017-08/msg00082.html
* src/fileio.c (Frename_file): On RHEL 7 + NFS, renameat2 can fail
with errno == EINVAL when it is not supported.  So treat that case
like errno == ENOSYS.  Also, when ok_if_already_exists is neither
nil nor an integer, just call plain rename; this avoids an extra
syscall to renameat2 when the latter fails with errno == EINVAL or
ENOSYS or ENOENT.

src/fileio.c

index 0264c9fa1d810e538cfbcb189a49c6242781d339..db760d9b22d06a4264a2aed1b65ff14ea942bab1 100644 (file)
@@ -2344,23 +2344,38 @@ This is what happens in interactive use with M-x.  */)
   encoded_file = ENCODE_FILE (file);
   encoded_newname = ENCODE_FILE (newname);
 
-  if (renameat_noreplace (AT_FDCWD, SSDATA (encoded_file),
-                         AT_FDCWD, SSDATA (encoded_newname))
-      == 0)
-    return Qnil;
-  int rename_errno = errno;
+  /* If the filesystem is case-insensitive and the file names are
+     identical but for the case, don't worry whether the destination
+     already exists: the caller simply wants to change the letter-case
+     of the file name.  */
+  bool plain_rename
+    = ((!NILP (ok_if_already_exists) && !INTEGERP (ok_if_already_exists))
+       || (file_name_case_insensitive_p (SSDATA (encoded_file))
+          && ! NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname)))));
+
+  int rename_errno;
+  if (!plain_rename)
+    {
+      if (renameat_noreplace (AT_FDCWD, SSDATA (encoded_file),
+                             AT_FDCWD, SSDATA (encoded_newname))
+         == 0)
+       return Qnil;
+
+      rename_errno = errno;
+      switch (rename_errno)
+       {
+       case EEXIST: case EINVAL: case ENOSYS:
+         barf_or_query_if_file_exists (newname, rename_errno == EEXIST,
+                                       "rename to it",
+                                       INTEGERP (ok_if_already_exists),
+                                       false);
+         plain_rename = true;
+         break;
+       }
+    }
 
-  if (rename_errno == EEXIST || rename_errno == ENOSYS)
+  if (plain_rename)
     {
-      /* If the filesystem is case-insensitive and the file names are
-        identical but for the case, don't ask for confirmation: they
-        simply want to change the letter-case of the file name.  */
-      if ((NILP (ok_if_already_exists) || INTEGERP (ok_if_already_exists))
-         && (! file_name_case_insensitive_p (SSDATA (encoded_file))
-             || NILP (Fstring_equal (Fdowncase (file), Fdowncase (newname)))))
-       barf_or_query_if_file_exists (newname, rename_errno == EEXIST,
-                                     "rename to it",
-                                     INTEGERP (ok_if_already_exists), false);
       if (rename (SSDATA (encoded_file), SSDATA (encoded_newname)) == 0)
        return Qnil;
       rename_errno = errno;