On 4/19/22 16:05, Steve Ward wrote:
When doing mv or cp with --backup=simple, if an existing file in
DIRECTORY has the same name as SOURCE, the files appear to be swapped
instead of an in-place backup of the original file in DIRECTORY being
made.

Thanks for the bug report. That's new to coreutils 9.1, and is a big enough fail that it suggests we'll need a 9.2 sooner rather than later. I introduced the bug when fixing an earlier bug (sorry).

I installed the attached Gnulib patch, which should fix the bug in Coreutils, with the attached two Coreutils patches to update to the latest Gnulib, and to add a test case for the bug.
From 7347caeb9d902d3fca2c11f69a55a3e578d93bfe Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Wed, 20 Apr 2022 19:34:57 -0700
Subject: [PATCH] backupfile: fix bug when renaming simple backups

* lib/backupfile.c (backupfile_internal): Fix bug when RENAME
and when doing simple backups.  Problem reported by Steve Ward in:
https://bugs.gnu.org/55029
---
 ChangeLog        | 5 +++++
 lib/backupfile.c | 7 +++----
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 4b39a6a443..cd16bbe0cd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2022-04-20  Paul Eggert  <egg...@cs.ucla.edu>
 
+	backupfile: fix bug when renaming simple backups
+	* lib/backupfile.c (backupfile_internal): Fix bug when RENAME
+	and when doing simple backups.  Problem reported by Steve Ward in:
+	https://bugs.gnu.org/55029
+
 	gettime-res: more-robust sampling
 	* lib/gettime-res.c (gettime_res): If adjacent timestamps are
 	identical search for a differing timestamp.  Also, stop collecting
diff --git a/lib/backupfile.c b/lib/backupfile.c
index 1e9290a187..d9f465a3e0 100644
--- a/lib/backupfile.c
+++ b/lib/backupfile.c
@@ -332,7 +332,7 @@ backupfile_internal (int dir_fd, char const *file,
     return s;
 
   DIR *dirp = NULL;
-  int sdir = AT_FDCWD;
+  int sdir = dir_fd;
   idx_t base_max = 0;
   while (true)
     {
@@ -371,10 +371,9 @@ backupfile_internal (int dir_fd, char const *file,
       if (! rename)
         break;
 
-      int olddirfd = sdir < 0 ? dir_fd : sdir;
-      idx_t offset = sdir < 0 ? 0 : base_offset;
+      idx_t offset = backup_type == simple_backups ? 0 : base_offset;
       unsigned flags = backup_type == simple_backups ? 0 : RENAME_NOREPLACE;
-      if (renameatu (olddirfd, file + offset, sdir, s + offset, flags) == 0)
+      if (renameatu (sdir, file + offset, sdir, s + offset, flags) == 0)
         break;
       int e = errno;
       if (! (e == EEXIST && extended))
-- 
2.35.1

From d1be566b18b9df34a22d61c9aa92bde00a4a6f0e Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Wed, 20 Apr 2022 19:36:44 -0700
Subject: [PATCH 1/2] build: update gnulib submodule to latest

---
 gnulib | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gnulib b/gnulib
index 58c597d13..7347caeb9 160000
--- a/gnulib
+++ b/gnulib
@@ -1 +1 @@
-Subproject commit 58c597d13bc57dce3e97ea97856573f2d68ccb8c
+Subproject commit 7347caeb9d902d3fca2c11f69a55a3e578d93bfe
-- 
2.35.1

From 56b314b384192ab75c23c281968a38ac2cb31617 Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Wed, 20 Apr 2022 19:44:56 -0700
Subject: [PATCH 2/2] mv: test Bug#55029

* tests/mv/backup-dir.sh: New test for Bug#55029,
reported by Steve Ward.
---
 NEWS                   | 5 +++++
 tests/mv/backup-dir.sh | 6 ++++++
 2 files changed, 11 insertions(+)

diff --git a/NEWS b/NEWS
index 7bedb0617..26eb52ca0 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,11 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 * Noteworthy changes in release ?.? (????-??-??) [?]
 
+** Bug fixes
+
+  'mv --backup=simple f d/' no longer mistakenly backs up d/f to f~.
+  [bug introduced in coreutils-9.1]
+
 
 * Noteworthy changes in release 9.1 (2022-04-15) [stable]
 
diff --git a/tests/mv/backup-dir.sh b/tests/mv/backup-dir.sh
index 84c51afc8..2f708b5b6 100755
--- a/tests/mv/backup-dir.sh
+++ b/tests/mv/backup-dir.sh
@@ -36,4 +36,10 @@ mkdir C D E || framework_failure_
 mv -T --backup=numbered C E/ || fail=1
 mv -T --backup=numbered D E/ || fail=1
 
+# Bug#55029
+mkdir F && echo 1 >1 && echo 2 >2 && cp 1 F/X && cp 2 X || framework_failure_
+mv --backup=simple X F/ || fail=1
+compare 1 F/X~ || fail=1
+compare 2 F/X || fail=1
+
 Exit $fail
-- 
2.35.1

Reply via email to