Subject: Re: bug#27986: 26.0.50; 'rename-file' can rename files without confirmation

From: Paul Eggert <[email-masked]>
Date: Mon, 14 Aug 2017 16:03:13 -0700

Philipp Stephani wrote:

> there's no way to special-case
> casing changes while keeping atomicity intact. So I'd rather have Emacs
> react conservatively and skip the casing check entirely.

Yes, that makes sense, at least for macOS.

> Note that the manpage says:
> 
> RENAME_EXCL   On file systems that support it (see getattrlist(2)
> VOL_CAP_INT_RENAME_EXCL), it will cause EEXIST to be returned if the
> destination already exists.
> 
> I interpret this such that if the filesystem doesn't support RENAME_EXCL
> the rename will succeed even if the destination exists.

I interpret it to mean that if the filesystem doesn't support RENAME_EXCL, the 
rename will fail with errno == EINVAL or ENOSYS.  At least, that's how it works 
under GNU/Linux. If it behaved the way you suggest, there'd be no good way to 
emulate RENAME_EXCL on filesystems lacking it, which would surely not be Apple's 
intent.

Please check this, though. I installed the patch on 'master' to help you do that.

Now that renameat_noreplace works on DOS_NT, would it make sense to apply the 
attached further patch as well? If we can get renameat_noreplace to work on 
Cygwin the we could simplify the fileio.c code even further.

> Since we probably won't be able to solve all issues across operating
> systems and filesystems, probably we should have at least a warning in the
> documentation that rename-file attempts to be race-free and atomic, but
> only on a best-effort basis.

True. I'd like to get the directory issue fixed before worrying about this, 
though. (That way I don't have to document the security holes in the current 
implementation. :-) I'll follow up separately about that.
From c929fb0ed882f15e492caff9f6610c87a57bca9a Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Mon, 14 Aug 2017 15:59:37 -0700
Subject: [PATCH] Improve rename-file behavior on DOS_NT

See Bug#27986.
* src/fileio.c (Frename_file): Do not worry about file name case
sensitivity if DOS_NT, since renameat_noreplace should work in
that case.
---
 src/fileio.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/fileio.c b/src/fileio.c
index 9f6de5b6ca..f5000352ab 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2254,12 +2254,13 @@ This is what happens in interactive use with M-x.  */)
 
   file = Fexpand_file_name (file, Qnil);
 
-  /* If the filesystem is case-insensitive and the file names are
-     identical but for case, treat it as a change-case request, and do
-     not worry whether NEWNAME exists or whether it is a directory, as
-     it is already another name for FILE.  */
+  /* If renameat_noreplace does not work and the filesystem is
+     case-insensitive and the file names are identical but for case,
+     treat it as a change-case request, and do not worry whether
+     NEWNAME exists or whether it is a directory, as it is already
+     another name for FILE.  */
   bool case_only_rename = false;
-#if defined CYGWIN || defined DOS_NT
+#ifdef CYGWIN
   if (!NILP (Ffile_name_case_insensitive_p (file)))
     {
       newname = Fexpand_file_name (newname, Qnil);
-- 
2.13.5