Hello Jim,

after your agreement last week I am sending the patch for cp/mv xattr support.
Any feedback is wellcome...


Kamil
From 5c392c91880f78859189e45125ec1ff3e9992585 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <[EMAIL PROTECTED]>
Date: Mon, 10 Nov 2008 19:07:44 +0100
Subject: [PATCH] cp/mv: xattr support

* m4/xattr.m4: Check for libattr availability, new configure option
--disable-xattr.
* m4/prereq.m4: Require gl_FUNC_XATTR.
* src/Makefile.am: Link cp, mv and ginstall with libattr.
* src/copy.h: Add preserve_xattr to cp_options.
* src/copy.c (copy_attr_error): New function to handle errors during
xattr copying.
(copy_extended_attributes): New function to copy xattr.
(copy_reg, copy_internal): Call copy_extended_attributes function.
* src/cp.c (usage): Mention new --preserve=xattr option.
(decode_preserve_arg): Handle new --preserve=xattr option.
* src/mv.c: Always attempt to preserve xattr.
* src/install.c: Never attempt to preserve xattr.
* tests/cp/xattr: New test for xattr support in cp.
* tests/mv/xattr: New test for xattr support in mv.
* tests/Makefile.am: Add new tests to list.
* doc/coreutils.texi: Mention new --preserve=xattr option.
* NEWS: Mention the change.
---
 NEWS               |    2 +
 doc/coreutils.texi |    3 ++
 m4/prereq.m4       |    1 +
 m4/xattr.m4        |   45 +++++++++++++++++++++++++++++++++++
 src/Makefile.am    |    6 ++--
 src/copy.c         |   51 ++++++++++++++++++++++++++++++++++++++++
 src/copy.h         |    4 +++
 src/cp.c           |   15 +++++++++--
 src/install.c      |    1 +
 src/mv.c           |    1 +
 tests/Makefile.am  |    2 +
 tests/cp/xattr     |   59 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/mv/xattr     |   66 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 13 files changed, 250 insertions(+), 6 deletions(-)
 create mode 100644 m4/xattr.m4
 create mode 100755 tests/cp/xattr
 create mode 100755 tests/mv/xattr

diff --git a/NEWS b/NEWS
index cbea67c..b8992aa 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,8 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 ** New features
 
+  cp/mv: xattr support, new option --preserve=xattr in cp
+
   ls --color now highlights hard linked files, too
 
   stat -f recognizes the Lustre file system type
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 2d11388..18a8ffc 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -7372,6 +7372,9 @@ Preserve in the destination files
 any links between corresponding source files.
 @c Give examples illustrating how hard links are preserved.
 @c Also, show how soft links map to hard links with -L and -H.
[EMAIL PROTECTED] xattr
+Preserve extended (xattr) attributes if coreutils are compiled with xattr
+support.
 @itemx all
 Preserve all file attributes.
 Equivalent to specifying all of the above.
diff --git a/m4/prereq.m4 b/m4/prereq.m4
index e65682f..536070e 100644
--- a/m4/prereq.m4
+++ b/m4/prereq.m4
@@ -38,6 +38,7 @@ AC_DEFUN([gl_PREREQ],
   # handles that; see ../bootstrap.conf.
   AC_REQUIRE([gl_EUIDACCESS_STAT])
   AC_REQUIRE([gl_FD_REOPEN])
+  AC_REQUIRE([gl_FUNC_XATTR])
   AC_REQUIRE([gl_FUNC_XFTS])
   AC_REQUIRE([gl_MEMXFRM])
   AC_REQUIRE([gl_STRINTCMP])
diff --git a/m4/xattr.m4 b/m4/xattr.m4
new file mode 100644
index 0000000..7edc04e
--- /dev/null
+++ b/m4/xattr.m4
@@ -0,0 +1,45 @@
+# xattr.m4 - check for Extended Attributes (Linux)
+
+# Copyright (C) 2003 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+# Written by Andreas Gruenbacher.
+# Note: original macro name was AC_FUNC_XATTR
+
+AC_DEFUN([gl_FUNC_XATTR],
+[
+  AC_ARG_ENABLE(xattr,
+	[  --disable-xattr         turn off support for extended attributes],
+	use_xattr=$enableval, use_xattr=yes)
+
+  if test "$use_xattr" = "yes"; then
+    AC_CHECK_HEADERS(attr/error_context.h attr/libattr.h)
+    if test "$ac_cv_header_attr_libattr_h" = yes \
+       && test "$ac_cv_header_attr_error_context_h" = yes; then
+      use_xattr=1
+    else
+      use_xattr=0
+    fi
+    AC_DEFINE_UNQUOTED(USE_XATTR, $use_xattr,
+		       [Define if you want extended attribute support.])
+    xattr_saved_LIBS=$LIBS
+    AC_SEARCH_LIBS(attr_copy_file, attr,
+		   [test "$ac_cv_search_attr_copy_file" = "none required" || LIB_XATTR=$ac_cv_search_attr_copy_file])
+    AC_SUBST(LIB_XATTR)
+    AC_CHECK_FUNCS(attr_copy_file)
+    LIBS=$xattr_saved_LIBS
+  fi
+])
diff --git a/src/Makefile.am b/src/Makefile.am
index 097cc7a..aab67d1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -149,9 +149,9 @@ su_LDADD = $(LDADD) $(LIB_CRYPT)
 dir_LDADD += $(LIB_ACL)
 ls_LDADD += $(LIB_ACL)
 vdir_LDADD += $(LIB_ACL)
-cp_LDADD += $(LIB_ACL)
-mv_LDADD += $(LIB_ACL)
-ginstall_LDADD += $(LIB_ACL)
+cp_LDADD += $(LIB_ACL) $(LIB_XATTR)
+mv_LDADD += $(LIB_ACL) $(LIB_XATTR)
+ginstall_LDADD += $(LIB_ACL) $(LIB_XATTR)
 
 stat_LDADD = $(LDADD) $(LIB_SELINUX)
 
diff --git a/src/copy.c b/src/copy.c
index bc1b20e..4953d4a 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -54,6 +54,12 @@
 #include "areadlink.h"
 #include "yesno.h"
 
+#if USE_XATTR
+# include <stdarg.h>
+# include <attr/error_context.h>
+# include <attr/libattr.h>
+#endif
+
 #ifndef HAVE_FCHOWN
 # define HAVE_FCHOWN false
 # define fchown(fd, uid, gid) (-1)
@@ -123,6 +129,45 @@ is_ancestor (const struct stat *sb, const struct dir_list *ancestors)
   return false;
 }
 
+#if USE_XATTR
+static void
+copy_attr_error (struct error_context *ctx, const char *fmt, ...)
+{
+  int err = errno;
+  va_list ap;
+  int len;
+  char *buffer;
+
+  /* There is no error function that takes a va_list argument,
+     so we print the message in a buffer first.  */
+
+  va_start (ap, fmt);
+  len = vsnprintf (NULL, 0, fmt, ap);
+  if (len > 0)
+    {
+      buffer = xmalloc (len + 1);
+      vsnprintf (buffer, len + 1, fmt, ap);
+      error (0, err, "%s", buffer);
+      free (buffer);
+    }
+  va_end (ap);
+}
+
+static bool
+copy_extended_attributes (const char *src_path, const char *dst_path)
+{
+  return 0 == attr_copy_file (src_path, dst_path, attr_copy_check_permissions,
+			      copy_attr_error);
+}
+#else /* USE_XATTR */
+
+static bool
+copy_extended_attributes (const char *src_path, const char *dst_path)
+{
+  return true;
+}
+#endif /* USE_XATTR */
+
 /* Read the contents of the directory SRC_NAME_IN, and recursively
    copy the contents to DST_NAME_IN.  NEW_DST is true if
    DST_NAME_IN is a directory that was created previously in the
@@ -681,6 +726,9 @@ copy_reg (char const *src_name, char const *dst_name,
 
   set_author (dst_name, dest_desc, src_sb);
 
+  if (x->preserve_xattr && ! copy_extended_attributes (src_name, dst_name))
+    return_val = false;
+
   if (x->preserve_mode || x->move_mode)
     {
       if (copy_acl (src_name, source_desc, dst_name, dest_desc, src_mode) != 0
@@ -1979,6 +2027,9 @@ copy_internal (char const *src_name, char const *dst_name,
 
   set_author (dst_name, -1, &src_sb);
 
+  if (x->preserve_xattr && ! copy_extended_attributes (src_name, dst_name))
+    delayed_ok = false;
+
   if (x->preserve_mode || x->move_mode)
     {
       if (copy_acl (src_name, -1, dst_name, -1, src_mode) != 0
diff --git a/src/copy.h b/src/copy.h
index 12b7c2d..bc2ca41 100644
--- a/src/copy.h
+++ b/src/copy.h
@@ -173,6 +173,10 @@ struct cp_options
      fail if it is unable to do so.  */
   bool require_preserve_context;
 
+  /* If true, attempt to preserve extended attributes using libattr.
+     Ignored if coreutils are compiled without xattr support. */
+  bool preserve_xattr;
+
   /* If true, copy directories recursively and copy special files
      as themselves rather than copying their contents. */
   bool recursive;
diff --git a/src/cp.c b/src/cp.c
index 95eba0c..9b081d4 100644
--- a/src/cp.c
+++ b/src/cp.c
@@ -197,7 +197,8 @@ Mandatory arguments to long options are mandatory for short options too.\n\
   -p                           same as --preserve=mode,ownership,timestamps\n\
       --preserve[=ATTR_LIST]   preserve the specified attributes (default:\n\
                                  mode,ownership,timestamps), if possible\n\
-                                 additional attributes: context, links, all\n\
+                                 additional attributes: context, links, xattr,\n\
+                                 all\n\
 "), stdout);
       fputs (_("\
       --no-preserve=ATTR_LIST  don't preserve the specified attributes\n\
@@ -774,6 +775,7 @@ cp_option_init (struct cp_options *x)
   x->preserve_timestamps = false;
   x->preserve_security_context = false;
   x->require_preserve_context = false;
+  x->preserve_xattr = false;
 
   x->require_preserve = false;
   x->recursive = false;
@@ -810,18 +812,20 @@ decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off)
       PRESERVE_OWNERSHIP,
       PRESERVE_LINK,
       PRESERVE_CONTEXT,
+      PRESERVE_XATTR,
       PRESERVE_ALL
     };
   static enum File_attribute const preserve_vals[] =
     {
       PRESERVE_MODE, PRESERVE_TIMESTAMPS,
-      PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_CONTEXT, PRESERVE_ALL
+      PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_CONTEXT, PRESERVE_XATTR,
+      PRESERVE_ALL
     };
   /* Valid arguments to the `--preserve' option. */
   static char const* const preserve_args[] =
     {
       "mode", "timestamps",
-      "ownership", "links", "context", "all", NULL
+      "ownership", "links", "context", "xattr", "all", NULL
     };
   ARGMATCH_VERIFY (preserve_args, preserve_vals);
 
@@ -862,6 +866,10 @@ decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off)
 	  x->require_preserve_context = on_off;
 	  break;
 
+	case PRESERVE_XATTR:
+	  x->preserve_xattr = on_off;
+	  break;
+
 	case PRESERVE_ALL:
 	  x->preserve_mode = on_off;
 	  x->preserve_timestamps = on_off;
@@ -869,6 +877,7 @@ decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off)
 	  x->preserve_links = on_off;
 	  if (selinux_enabled)
 	    x->preserve_security_context = on_off;
+	  x->preserve_xattr = on_off;
 	  break;
 
 	default:
diff --git a/src/install.c b/src/install.c
index a7c3b3d..5a67597 100644
--- a/src/install.c
+++ b/src/install.c
@@ -200,6 +200,7 @@ cp_option_init (struct cp_options *x)
   x->open_dangling_dest_symlink = false;
   x->update = false;
   x->preserve_security_context = false;
+  x->preserve_xattr = false;
   x->verbose = false;
   x->dest_info = NULL;
   x->src_info = NULL;
diff --git a/src/mv.c b/src/mv.c
index fc255f3..bbe863e 100644
--- a/src/mv.c
+++ b/src/mv.c
@@ -139,6 +139,7 @@ cp_option_init (struct cp_options *x)
   x->preserve_security_context = selinux_enabled;
   x->require_preserve = false;  /* FIXME: maybe make this an option */
   x->require_preserve_context = false;
+  x->preserve_xattr = true;
   x->recursive = true;
   x->sparse_mode = SPARSE_AUTO;  /* FIXME: maybe make this an option */
   x->symbolic_link = false;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0dabb56..0211886 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -280,6 +280,7 @@ TESTS =						\
   cp/src-base-dot				\
   cp/symlink-slash				\
   cp/thru-dangling				\
+  cp/xattr					\
   dd/misc					\
   dd/not-rewound				\
   dd/skip-seek					\
@@ -389,6 +390,7 @@ TESTS =						\
   mv/to-symlink					\
   mv/trailing-slash				\
   mv/update					\
+  mv/xattr					\
   readlink/can-e				\
   readlink/can-f				\
   readlink/can-m				\
diff --git a/tests/cp/xattr b/tests/cp/xattr
new file mode 100755
index 0000000..d0b07b0
--- /dev/null
+++ b/tests/cp/xattr
@@ -0,0 +1,59 @@
+#!/bin/sh
+# Ensure that cp --preserve=xattr works properly.
+
+# Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+  set -x
+  cp --version
+fi
+
+. $srcdir/test-lib.sh
+
+# Skip this test if cp was built without xattr support:
+grep '^#define USE_XATTR 1' $CONFIG_HEADER > /dev/null ||
+  skip_test_ "coreutils built without xattr support"
+
+# testing xattr name-value pair
+xattr_name="user.foo"
+xattr_value="bar"
+xattr_pair="$xattr_name=\"$xattr_value\""
+
+# create new file and check its xattrs
+touch a || framework_failure
+getfattr -d a > out_a || skip_test_ "failed to get xattr of file"
+fgrep "$xattr_pair" out_a > /dev/null && framework_failure
+
+# try to set user xattr on file
+setfattr -n "$xattr_name" -v "$xattr_value" a > out_a \
+  || skip_test_ "failed to set xattr of file"
+getfattr -d a > out_a || skip_test_ "failed to get xattr of file"
+fgrep "$xattr_pair" out_a > /dev/null \
+  || skip_test_ "failed to set xattr of file"
+
+fail=0
+
+# cp should not preserve xattr by default
+cp a b || fail=1
+getfattr -d b > out_b || skip_test_ "failed to get xattr of file"
+fgrep "$xattr_pair" out_b > /dev/null && fail=1
+
+# test if --preserve=xattr option works
+cp --preserve=xattr a b || fail=1
+getfattr -d b > out_b || skip_test_ "failed to get xattr of file"
+fgrep "$xattr_pair" out_b > /dev/null || fail=1
+
+Exit $fail
diff --git a/tests/mv/xattr b/tests/mv/xattr
new file mode 100755
index 0000000..c0eb608
--- /dev/null
+++ b/tests/mv/xattr
@@ -0,0 +1,66 @@
+#!/bin/sh
+# Check if mv always preserve extended attributes.
+
+# Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+  set -x
+  mv --version
+fi
+
+# this code was taken from test mv/backup-is-src
+. $srcdir/test-lib.sh
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/other-fs-tmpdir"
+b_other="$other_partition_tmpdir/b"
+rm -f $b_other || framework_failure
+
+# Skip this test if mv was built without xattr support:
+grep '^#define USE_XATTR 1' $CONFIG_HEADER > /dev/null ||
+  skip_test_ "coreutils built without xattr support"
+
+# testing xattr name-value pair
+xattr_name="user.foo"
+xattr_value="bar"
+xattr_pair="$xattr_name=\"$xattr_value\""
+
+# create new file and check its xattrs
+touch a || framework_failure
+getfattr -d a > out_a || skip_test_ "failed to get xattr of file"
+fgrep "$xattr_pair" out_a > /dev/null && framework_failure
+
+# try to set user xattr on file
+setfattr -n "$xattr_name" -v "$xattr_value" a > out_a \
+  || skip_test_ "failed to set xattr of file"
+getfattr -d a > out_a || skip_test_ "failed to get xattr of file"
+fgrep "$xattr_pair" out_a > /dev/null \
+  || skip_test_ "failed to set xattr of file"
+
+fail=0
+
+# mv should preserve xattr when not copying content
+# (implicit and probably expected behavior)
+mv a b || fail=1
+getfattr -d b > out_b || skip_test_ "failed to get xattr of file"
+fgrep "$xattr_pair" out_b > /dev/null || fail=1
+
+# mv should even preserve xattr when copying content from one partition
+# to another
+mv b $b_other || fail=1
+getfattr -d $b_other > out_b || skip_test_ "failed to get xattr of file"
+fgrep "$xattr_pair" out_b > /dev/null || fail=1
+
+Exit $fail
-- 
1.5.4.1

_______________________________________________
Bug-coreutils mailing list
Bug-coreutils@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-coreutils

Reply via email to