emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master ddc1ff5: Port recent rename changes to RHEL 7 + NFS


From: Paul Eggert
Subject: [Emacs-diffs] master ddc1ff5: Port recent rename changes to RHEL 7 + NFS
Date: Thu, 3 Aug 2017 19:19:27 -0400 (EDT)

branch: master
commit ddc1ff58dec92a782b233d97a254fc41c1c887eb
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>

    Port recent rename changes to RHEL 7 + NFS
    
    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 | 45 ++++++++++++++++++++++++++++++---------------
 1 file changed, 30 insertions(+), 15 deletions(-)

diff --git a/src/fileio.c b/src/fileio.c
index 0264c9f..db760d9 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -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;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]