bug#13601: mv should not silently lose file extended attributes

Collin Funk <[email protected]>
Newsgroups gmane.comp.gnu.core-utils.bugs
Message-ID <[email protected]>
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
0001-mv-emit-warnings-when-copying-extended-attributes-fa.patch (text/x-patch, 4.1 KB)
From 4cde26b6beb36e525eda936ffdcdf59d551c1f26 Mon Sep 17 00:00:00 2001
Message-ID: <4cde26b6beb36e525eda936ffdcdf59d551c1f26.1786854256.git.collin.funk1@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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.