Kamil Dudka 79fe59
From 76df06ff8fa39ae0cb0d167b7f622139778dc7d7 Mon Sep 17 00:00:00 2001
Kamil Dudka 79fe59
From: Kamil Dudka <kdudka@redhat.com>
Kamil Dudka 79fe59
Date: Thu, 4 Jan 2018 09:42:10 +0100
Kamil Dudka 79fe59
Subject: [PATCH] mv -n: do not overwrite the destination
Kamil Dudka 79fe59
Kamil Dudka 79fe59
... if it is created by another process after mv has checked its
Kamil Dudka 79fe59
non-existence.
Kamil Dudka 79fe59
Kamil Dudka 79fe59
* src/copy.c (copy_internal): Use renameat2 (..., RENAME_NOREPLACE)
Kamil Dudka 79fe59
if called by mv -n.  If it fails with EEXIST in that case, pretend
Kamil Dudka 79fe59
successful rename as if the existing destination file was detected
Kamil Dudka 79fe59
by the preceding lstat call.
Kamil Dudka 79fe59
Kamil Dudka 79fe59
Fixes https://bugs.gnu.org/29961
Kamil Dudka 79fe59
---
Kamil Dudka 79fe59
 src/copy.c | 17 ++++++++++++++++-
Kamil Dudka 79fe59
 1 file changed, 16 insertions(+), 1 deletion(-)
Kamil Dudka 79fe59
Kamil Dudka 79fe59
diff --git a/src/copy.c b/src/copy.c
Kamil Dudka 79fe59
index 2a804945e..be4e357a8 100644
Kamil Dudka 79fe59
--- a/src/copy.c
Kamil Dudka 79fe59
+++ b/src/copy.c
Kamil Dudka 79fe59
@@ -53,6 +53,7 @@
Kamil Dudka 79fe59
 #include "ignore-value.h"
Kamil Dudka 79fe59
 #include "ioblksize.h"
Kamil Dudka 79fe59
 #include "quote.h"
Kamil Dudka 79fe59
+#include "renameat2.h"
Kamil Dudka 79fe59
 #include "root-uid.h"
Kamil Dudka 79fe59
 #include "same.h"
Kamil Dudka 79fe59
 #include "savedir.h"
Kamil Dudka 79fe59
@@ -2319,7 +2320,12 @@ copy_internal (char const *src_name, char const *dst_name,
Kamil Dudka 79fe59
 
Kamil Dudka 79fe59
   if (x->move_mode)
Kamil Dudka 79fe59
     {
Kamil Dudka 79fe59
-      if (rename (src_name, dst_name) == 0)
Kamil Dudka 79fe59
+      int flags = 0;
Kamil Dudka 79fe59
+      if (x->interactive == I_ALWAYS_NO)
Kamil Dudka 79fe59
+        /* do not replace DST_NAME if it was created since our last check */
Kamil Dudka 79fe59
+        flags = RENAME_NOREPLACE;
Kamil Dudka 79fe59
+
Kamil Dudka 79fe59
+      if (renameat2 (AT_FDCWD, src_name, AT_FDCWD, dst_name, flags) == 0)
Kamil Dudka 79fe59
         {
Kamil Dudka 79fe59
           if (x->verbose)
Kamil Dudka 79fe59
             {
Kamil Dudka 79fe59
@@ -2351,6 +2357,15 @@ copy_internal (char const *src_name, char const *dst_name,
Kamil Dudka 79fe59
           return true;
Kamil Dudka 79fe59
         }
Kamil Dudka 79fe59
 
Kamil Dudka 79fe59
+      if ((flags & RENAME_NOREPLACE) && (errno == EEXIST))
Kamil Dudka 79fe59
+        {
Kamil Dudka 79fe59
+          /* Pretend the rename succeeded, so the caller (mv)
Kamil Dudka 79fe59
+             doesn't end up removing the source file.  */
Kamil Dudka 79fe59
+          if (rename_succeeded)
Kamil Dudka 79fe59
+            *rename_succeeded = true;
Kamil Dudka 79fe59
+          return true;
Kamil Dudka 79fe59
+        }
Kamil Dudka 79fe59
+
Kamil Dudka 79fe59
       /* FIXME: someday, consider what to do when moving a directory into
Kamil Dudka 79fe59
          itself but when source and destination are on different devices.  */
Kamil Dudka 79fe59
 
Kamil Dudka 79fe59
-- 
Kamil Dudka 79fe59
2.13.6
Kamil Dudka 79fe59