From: Paul Eggert Date: Thu, 3 Aug 2017 23:18:45 +0000 (-0700) Subject: Port recent rename changes to RHEL 7 + NFS X-Git-Tag: emacs-26.0.90~517^2~34 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=ddc1ff58dec92a782b233d97a254fc41c1c887eb;p=emacs.git 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. --- diff --git a/src/fileio.c b/src/fileio.c index 0264c9fa1d8..db760d9b22d 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;