[Toybox] [PATCH] Fix mv with trailing slash in source.

Denys Nykula nykula at ukr.net
Sat Jun 22 05:37:18 PDT 2019


Leaving the Makepost address because somebody abused my email provider
and got Mozilla and GitHub really unhappy.
---
>From 91c5ba7d250188afa5b40631b15bc3a778691288 Mon Sep 17 00:00:00 2001
From: Denys Nykula <nykula at ukr.net>
Date: Sat, 22 Jun 2019 14:57:59 +0300
Subject: [PATCH] Fix mv with trailing slash in source.

Press tab, have bash complete dir name with a slash, notice musl
rename() dislikes that. Replace trailing slash in the cp loop with a
null character, if the command name is mv. Add the slash back if an
error occurs.
---
 tests/mv.test   | 20 ++++++++++++++++++++
 toys/posix/cp.c |  8 +++++++-
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/tests/mv.test b/tests/mv.test
index f1f4a4f9..ed8922ac 100755
--- a/tests/mv.test
+++ b/tests/mv.test
@@ -96,6 +96,26 @@ testing "dir to existing dir" \
   "yes\n" "" ""
 rm -rf dir*
 
+# Trailing slash was once throwing: bad 'dir1/dir2/': Resource busy
+mkdir -p dir1/dir2
+testing "dir1/dir2 to ." \
+  "mv dir1/dir2 . && [ ! -e dir1/dir2 -a -d dir2 ] && echo yes" \
+  "yes\n" "" ""
+rm -rf dir*
+mkdir -p dir1/dir2
+testing "dir1/dir2/ to ." \
+  "mv dir1/dir2/ . && [ ! -e dir1/dir2 -a -d dir2 ] && echo yes" \
+  "yes\n" "" ""
+rm -rf dir*
+mkdir -p dir1/dir2
+testing "dir1/dir2/ to ./" \
+  "mv dir1/dir2/ ./ && [ ! -e dir1/dir2 -a -d dir2 ] && echo yes" \
+  "yes\n" "" ""
+rm -rf dir*
+testing "not/exists/ to ./" \
+  "mv not/exists/ ./ 2>&1 | grep -o not/exists/" \
+  "not/exists/\n" "" ""
+
 touch file1 file2
 chmod 400 file1 file2
 testing "force over unwritable" \
diff --git a/toys/posix/cp.c b/toys/posix/cp.c
index 681af025..9989ed14 100644
--- a/toys/posix/cp.c
+++ b/toys/posix/cp.c
@@ -403,9 +403,14 @@ void cp_main(void)
 
   // Loop through sources
   for (i=0; i<toys.optc; i++) {
-    char *src = toys.optargs[i];
+    char *src = toys.optargs[i], *trail = src;
     int rc = 1;
 
+    if (CFG_MV && toys.which->name[0] == 'm') {
+      while (*++trail);
+      if (*--trail == '/') *trail = 0;
+    }
+
     if (destdir) {
       char *s = (toys.optflags&FLAG_D) ? getdirname(src) : getbasename(src);
 
@@ -442,6 +447,7 @@ void cp_main(void)
         if (exists && no_clobber) rc = 0;
       }
       if (rc) rc = rename(src, TT.destname);
+      if (errno && !*trail) *trail = '/';
     }
 
     // Copy if we didn't mv, skipping nonexistent sources


More information about the Toybox mailing list