Paul Eggert <[email protected]> writes:

> Since mv ordinarily acts like 'cp --preserve=all' when copying, presumably mv 
> should warn in this situation if cp warns.
>
> Also, if no mv options other than -i and -f are used, a diagnostic is
> needed to conform to the spirit of POSIX, as the POSIX spec says for
> this situation "If the duplication of the file characteristics fails
> for any reason, mv shall write a diagnostic message to standard error,
> but this failure shall not cause mv to modify its exit status."[1]
> Contrary to the original bug report POSIX does not require (and
> seemingly does not allow) the mv to be aborted if file characteristics
> are lost in the copy, but at least the user should be warned about the
> situation.

Thanks for the link. POSIX seems pretty clear here.

The attached patch should fix things. I was tempted to add another
option to "struct cp_options", but it was more unwieldy then just
setting "require_preserve_xattr" and special casing "move_mode" to not
change the exit status.

It would be nice to add a test but it seems strace can't inject
ENOTSUP. I'll see if I can think of an alternative.

Collin

>From 4cde26b6beb36e525eda936ffdcdf59d551c1f26 Mon Sep 17 00:00:00 2001
Message-ID: <4cde26b6beb36e525eda936ffdcdf59d551c1f26.1786854256.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Sat, 15 Aug 2026 21:09:23 -0700
Subject: [PATCH] mv: emit warnings when copying extended attributes fails with
 ENOTSUP

* src/copy.c (copy_reg, copy_interal): Don't change the exit status if
copying extended attributes fails and we are 'mv'.
* src/copy.h (struct cp_options): Update some commentary.
* src/mv.c (cp_option_init): Enable require_preserve_xattr in the
cp_options struct.
* doc/coreutils.texi (mv invocation): Mention that all errors are
emitted, but do not modify the exit status.
* NEWS: Mention the bug fix.
---
 NEWS               | 4 ++++
 doc/coreutils.texi | 3 ++-
 src/copy.c         | 4 ++--
 src/copy.h         | 3 +--
 src/mv.c           | 2 +-
 5 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/NEWS b/NEWS
index 5415d4d77..3edfbd502 100644
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,10 @@ GNU coreutils NEWS                                    -*- outline -*-
   'head' and 'tail' now quote names in file headers when needed.
   [This bug was present in "the beginning".]
 
+  'mv' now warns when copying extended attributes fails with ENOTSUP, e.g., when
+  moving files to a file system that does not support them.
+  [bug introduced in coreutils-7.3]
+
   'numfmt', 'printf', and 'seq' on Solaris, no longer output an extraneous e+00
   when using a large precision like "%.5119f".
   [This bug was present in "the beginning".]
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index e4d4db47f..90c2dfcd6 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -9981,7 +9981,8 @@ @node mv invocation
 @cindex extended attributes, xattr
 @command{mv} always tries to copy extended attributes (xattr), which may
 include SELinux context, ACLs or Capabilities.
-Upon failure all but @samp{Operation not supported} warnings are output.
+Upon failure all warnings are emitted, but do not modify the exit
+status.
 
 @cindex prompting, and @command{mv}
 If a destination file exists but is normally unwritable, standard input
diff --git a/src/copy.c b/src/copy.c
index a53fb8f8c..c1b72dfb4 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -1086,7 +1086,7 @@ copy_reg (char const *src_name, char const *dst_name,
   if (preserve_xattr)
     {
       if (!copy_attr (src_name, source_desc, dst_name, dest_desc, x)
-          && x->require_preserve_xattr)
+          && x->require_preserve_xattr && ! x->move_mode)
         return_val = false;
     }
 
@@ -2672,7 +2672,7 @@ skip:
 
   /* Set xattrs after ownership as changing owners will clear capabilities.  */
   if (x->preserve_xattr && ! copy_attr (src_name, -1, dst_name, -1, x)
-      && x->require_preserve_xattr)
+      && x->require_preserve_xattr && ! x->move_mode)
     return false;
 
   /* The operations beyond this point may dereference a symlink.  */
diff --git a/src/copy.h b/src/copy.h
index 294cffaaf..f2d10fefd 100644
--- a/src/copy.h
+++ b/src/copy.h
@@ -234,12 +234,11 @@ struct cp_options
      while with 'cp --preserve=all' or 'cp -a', it is "false". */
   bool require_preserve_xattr;
 
-  /* This allows us to output warnings in cases 2 and 4 below,
+  /* This allows us to output warnings in case 2 below,
      while being quiet for case 1 (when reduce_diagnostics is true).
        1. cp -a                       try to copy xattrs with no errors
        2. cp --preserve=all           copy xattrs with all but ENOTSUP warnings
        3. cp --preserve=xattr,context copy xattrs with all errors
-       4. mv                          copy xattrs with all but ENOTSUP warnings
    */
   bool reduce_diagnostics;
 
diff --git a/src/mv.c b/src/mv.c
index 3ba6f701e..7f0d4f8c3 100644
--- a/src/mv.c
+++ b/src/mv.c
@@ -145,7 +145,7 @@ cp_option_init (struct cp_options *x)
   x->require_preserve = false;  /* FIXME: maybe make this an option */
   x->require_preserve_context = false;
   x->preserve_xattr = true;
-  x->require_preserve_xattr = false;
+  x->require_preserve_xattr = true;
   x->recursive = true;
   x->sparse_mode = SPARSE_AUTO;  /* FIXME: maybe make this an option */
   x->symbolic_link = false;
-- 
2.55.0

Reply via email to