On Thu, Aug 01, 2019 at 03:58:51PM -0700, Paul Eggert wrote:
> Thanks, that's better, but we're still missing some opportunities for 
> improvement.
> 
> >     mv: cannot move 'A' to 'B/A': Target directory not empty
> 
> This should be "Destination" not "Target". 
[...] 
> You meant "mv" not "rm".
[...]
> > +static char*
> Space before "*".
[...]
> > +strerror_target (int e)
> Change name to "strerror_dest"
[...] 
> This function should return NULL instead of aborting when the errno value is
> inapplicable. That way, its callers need not hardcode which errno values it
> handles.

Thanks for the review and suggestions - attached an updated patch.

> Come to think of it, the same improvement should be made to ln, cp, install
> and shred. Basically, to any program that uses 'rename' or 'link' or similar
> syscalls, and which reports an error if the syscall fails.

OK, I will work on that next.

-assaf
>From 8dc6158a6fde668e55312b5fb69384f438b7e55a Mon Sep 17 00:00:00 2001
From: Assaf Gordon <assafgor...@gmail.com>
Date: Mon, 29 Jul 2019 00:23:20 -0600
Subject: [PATCH] mv: improve error messages when destination directory is at
 fault

Suggested by Alex Mantel <alexmante...@gmail.com> in
https://bugs.gnu.org/36831 .

    $ mkdir A B B/A
    $ touch A/bar B/A/foo

Before:

    $ mv A B
    mv: cannot move 'A' to 'B/A': Directory not empty

After:

    $ mv A B
    mv: cannot move 'A' to 'B/A': Destination directory not empty

The following errors are handled:
EDQUOT, EEXIST, ENOTEMPTY, EISDIR, ENOSPC, ETXTBSY.

* src/copy.c (copy_internal): Print custom messages for errors
that explicitly fault the destination directory.
(strerror_dest): New function, return custom, translatable error
messages for errors relating to 'destination' component.
* tests/mv/dir2dir.sh: Adjust expected error message.
* NEWS: Mention change.
---
 NEWS                |  6 +++++
 src/copy.c          | 53 ++++++++++++++++++++++++++++++++++++++++++---
 tests/mv/dir2dir.sh |  8 ++++---
 3 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/NEWS b/NEWS
index fd0543351..3d80665ae 100644
--- a/NEWS
+++ b/NEWS
@@ -44,6 +44,12 @@ GNU coreutils NEWS                                    -*- 
outline -*-
   stat(1) also supports a new --cached= option to control cache
   coherency of file system attributes, useful on network file systems.
 
+** Improvements
+
+  mv now prints clearer error messages when a failure relates to the
+  destination directory (e.g., "Destination directory is not empty" instead
+  of "Directory not empty").
+
 
 * Noteworthy changes in release 8.31 (2019-03-10) [stable]
 
diff --git a/src/copy.c b/src/copy.c
index 65cf65895..602c8307b 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -1867,6 +1867,44 @@ source_is_dst_backup (char const *srcbase, struct stat 
const *src_st,
   return dst_back_status == 0 && SAME_INODE (*src_st, dst_back_sb);
 }
 
+/* Return custom error messages replacing the default libc's
+   messages. These messages explicity fault the destination component
+   in the error.
+
+   Return NULL if E (errno value) is not handled (and by implication
+   should use the system's default text for the error message).  */
+static char *
+strerror_dest (int e)
+{
+  /* TRANSLATORS: These strings should mimick libc's standard
+     error messages (from strerror(3)), but explicitly mention
+     the fault is with the destination directory. */
+  switch (errno)
+    {
+    case EDQUOT:
+      return _("Disk quota exceeded on destination device");
+    case EEXIST:
+    case ENOTEMPTY:
+      return _("Destination directory not empty");
+    case EISDIR:
+      return _("Tried to overwrite a directory with a file");
+    case ENOSPC:
+      return _("No space left on destination device");
+    case ETXTBSY:
+      /* NOTE: The error is "Text file busy" - but "text" in that context
+         refers to "text segment" of an executable file (as opposed to
+         "data segment" and "BSS segment").
+
+         This error message is meant for users, and 'text file' can be easily
+         confused with an actual text file (i.e., one containing only ASCII
+         characters. Thus, say 'executable' instead of 'text'.*/
+      return _("Destination executable file is busy");
+    default:
+      return NULL;
+    }
+}
+
+
 /* Copy the file SRC_NAME to the file DST_NAME.  The files may be of
    any type.  NEW_DST should be true if the file DST_NAME cannot
    exist because its parent directory was just created; NEW_DST should
@@ -2477,9 +2515,18 @@ copy_internal (char const *src_name, char const 
*dst_name,
              If the permissions on the directory containing the source or
              destination file are made too restrictive, the rename will
              fail.  Etc.  */
-          error (0, rename_errno,
-                 _("cannot move %s to %s"),
-                 quoteaf_n (0, src_name), quoteaf_n (1, dst_name));
+
+          const char *custom_err_msg = strerror_dest (rename_errno);
+          if (custom_err_msg)
+            error (0, 0,
+                   _("cannot move %s to %s: %s"),
+                   quoteaf_n (0, src_name), quoteaf_n (1, dst_name),
+                   custom_err_msg) ;
+          else
+            error (0, rename_errno,
+                   _("cannot move %s to %s"),
+                   quoteaf_n (0, src_name), quoteaf_n (1, dst_name));
+
           forget_created (src_sb.st_ino, src_sb.st_dev);
           return false;
         }
diff --git a/tests/mv/dir2dir.sh b/tests/mv/dir2dir.sh
index 6455386b9..869f624a3 100755
--- a/tests/mv/dir2dir.sh
+++ b/tests/mv/dir2dir.sh
@@ -30,11 +30,13 @@ touch a/t/f || framework_failure_
 mv b/t a 2> out && fail=1
 
 # Accept any of these: EEXIST, ENOTEMPTY, EBUSY.
-sed             's/: File exists/: Directory not empty/'<out>o1;mv o1 out
-sed 's/: Device or resource busy/: Directory not empty/'<out>o1;mv o1 out
+sed             's/: File exists/: Destination directory not empty/'<out>o1
+mv o1 out
+sed 's/: Device or resource busy/: Destination directory not empty/'<out>o1
+mv o1 out
 
 cat <<\EOF > exp || framework_failure_
-mv: cannot move 'b/t' to 'a/t': Directory not empty
+mv: cannot move 'b/t' to 'a/t': Destination directory not empty
 EOF
 
 compare exp out || fail=1
-- 
2.20.1

Reply via email to