Hello,

it has been proposed a few times ago to add support for xattr to coreutils 
cp/mv. There was proposed a patch written by Andreas Grünbacher and later 
reminded by Mike Frysinger (CC):

http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00253.html
http://lists.gnu.org/archive/html/bug-coreutils/2008-04/msg00190.html

What is the current state of this patch?

I am attaching the current xattr patch from Gentoo Linux (rediffed against git 
HEAD) which works for me. If I solved the issues listed in the threads above, 
would you accept this patch?

Note it also fixes rhbz #202823, #454072.


Kamil
From 18a8185efddb9135eea1b8d698fd913450ea98d3 Mon Sep 17 00:00:00 2001
From: Kamil Dudka <[EMAIL PROTECTED]>
Date: Mon, 20 Oct 2008 14:18:18 +0200
Subject: [PATCH] cp/mv: xattr support

---
 configure.ac       |    3 +
 doc/coreutils.texi |   12 ++++++
 m4/xattr.m4        |   44 ++++++++++++++++++++
 src/Makefile.am    |    6 +-
 src/copy.c         |  111 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/copy.h         |    4 ++
 src/cp.c           |   20 +++++++++-
 src/install.c      |    2 +
 src/mv.c           |    2 +
 9 files changed, 200 insertions(+), 4 deletions(-)
 create mode 100644 m4/xattr.m4

diff --git a/configure.ac b/configure.ac
index 549c7ee..4828d6f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -334,6 +334,9 @@ CONFIG_STATUS_DEPENDENCIES='$(top_srcdir)/src/Makefile.am'
 AC_SUBST([CONFIG_STATUS_DEPENDENCIES])
 ############################################################################
 
+# Extended attribute copying.
+AC_FUNC_XATTR
+
 AM_GNU_GETTEXT([external], [need-formatstring-macros])
 AM_GNU_GETTEXT_VERSION([0.15])
 
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 6459870..f927a7a 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -6945,6 +6945,18 @@ These options change how file names themselves are printed.
 
 @table @samp
 
[EMAIL PROTECTED] @[EMAIL PROTECTED]@var{regex}}
[EMAIL PROTECTED] --attributes
+Preserve extended attributes whose names match the specified regular
+expression.  The default behavior or @command{cp} if no
[EMAIL PROTECTED] option is given is to preserve all extended
+attributes except file permissions.  If @var{regex} is [EMAIL PROTECTED]'', no
+extended attributes are preserved.
+
+This option does not affect the preservation of file permissions.
+File permission preservation is controlled by the @option{-p} or
[EMAIL PROTECTED] options.
+
 @item -b
 @itemx --escape
 @itemx --quoting-style=escape
diff --git a/m4/xattr.m4 b/m4/xattr.m4
new file mode 100644
index 0000000..d749d56
--- /dev/null
+++ b/m4/xattr.m4
@@ -0,0 +1,44 @@
+# 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.
+
+AC_DEFUN([AC_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..3d91e9d 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -54,6 +54,13 @@
 #include "areadlink.h"
 #include "yesno.h"
 
+#if USE_XATTR
+# include "regex.h"
+# 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 +130,104 @@ 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 const char *
+copy_attr_quote (struct error_context *ctx, const char *str)
+{
+  return xstrdup (quote (str));
+}
+
+static void
+copy_attr_free (struct error_context *ctx, const char *str)
+{
+  free ((void *) str);
+}
+
+struct copy_attr_context
+  {
+    struct error_context ctx;
+    const char *re_pattern;
+    struct re_pattern_buffer re_compiled;
+  } copy_attr_ctx = {
+    { copy_attr_error,
+      copy_attr_quote,
+      copy_attr_free }
+  };
+
+static int
+copy_attr_filter (const char *name, struct error_context *ctx)
+{
+  struct copy_attr_context *copy_ctx = (struct copy_attr_context *) ctx;
+
+  return (attr_copy_check_permissions (name, ctx)
+	  && copy_ctx->re_pattern != NULL
+	  && re_search (&copy_ctx->re_compiled, name, strlen (name), 0,
+			strlen (name), NULL) >= 0);
+}
+#endif  /* USE_XATTR */
+
+static bool
+copy_extended_attributes (const char *src_path, const char *dst_path,
+			  const struct cp_options *x)
+{
+#if USE_XATTR
+  if (x->attr_pattern == NULL)
+    return true;
+
+  if (copy_attr_ctx.re_pattern != x->attr_pattern)
+    {
+      struct re_pattern_buffer *c = &copy_attr_ctx.re_compiled;
+      size_t len = strlen (x->attr_pattern);
+      const char *err;
+
+      free (c->fastmap);
+      free (c->buffer);
+
+      copy_attr_ctx.re_pattern = x->attr_pattern;
+      c->allocated = 2 * len;
+      c->buffer = xmalloc (c->allocated);
+      c->fastmap = xmalloc (256);
+      c->translate = 0;
+      err = re_compile_pattern (x->attr_pattern, len, c);
+      if (err)
+	{
+	  free (c->fastmap);
+	  free (c->buffer);
+	  copy_attr_ctx.re_pattern = NULL;
+	  error (EXIT_FAILURE, 0, _("%s: invalid regular expression: %s"),
+	  	 x->attr_pattern, err);
+	}
+    }
+  return attr_copy_file (src_path, dst_path,
+			 copy_attr_filter, &copy_attr_ctx.ctx) == 0;
+#else  /* USE_XATTR */
+  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 +786,9 @@ copy_reg (char const *src_name, char const *dst_name,
 
   set_author (dst_name, dest_desc, src_sb);
 
+  if (! copy_extended_attributes (src_name, dst_name, x))
+    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 +2087,9 @@ copy_internal (char const *src_name, char const *dst_name,
 
   set_author (dst_name, -1, &src_sb);
 
+  if (! copy_extended_attributes (src_name, dst_name, x))
+    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 86a8161..6b0add3 100644
--- a/src/copy.h
+++ b/src/copy.h
@@ -141,6 +141,10 @@ struct cp_options
   bool preserve_mode;
   bool preserve_timestamps;
 
+  /* Regular expression pattern that specifies which extended attributes to
+     copy.  NULL stands for copying no extended attributes.  */
+  const char *attr_pattern;
+
   /* Enabled for mv, and for cp by the --preserve=links option.
      If true, attempt to preserve in the destination files any
      logical hard links between the source files.  If used with cp's
diff --git a/src/cp.c b/src/cp.c
index 95eba0c..94f0fb2 100644
--- a/src/cp.c
+++ b/src/cp.c
@@ -79,7 +79,8 @@ enum
   REPLY_OPTION,
   SPARSE_OPTION,
   STRIP_TRAILING_SLASHES_OPTION,
-  UNLINK_DEST_BEFORE_OPENING
+  UNLINK_DEST_BEFORE_OPENING,
+  PRESERVE_XATTRS_OPTION
 };
 
 /* Initial number of entries in each hash table entry's table of inodes.  */
@@ -136,6 +137,7 @@ static struct option const long_opts[] =
   {"parents", no_argument, NULL, PARENTS_OPTION},
   {"path", no_argument, NULL, PARENTS_OPTION},   /* Deprecated.  */
   {"preserve", optional_argument, NULL, PRESERVE_ATTRIBUTES_OPTION},
+  {"attributes", required_argument, NULL, PRESERVE_XATTRS_OPTION},
   {"recursive", no_argument, NULL, 'R'},
   {"remove-destination", no_argument, NULL, UNLINK_DEST_BEFORE_OPENING},
   {"reply", required_argument, NULL, REPLY_OPTION}, /* Deprecated 2005-07-03,
@@ -226,6 +228,13 @@ Mandatory arguments to long options are mandatory for short options too.\n\
   -v, --verbose                explain what is being done\n\
   -x, --one-file-system        stay on this file system\n\
 "), stdout);
+      fputs(_("\n\
+      --attributes=regex       preserve extended attributes whose name\n\
+                               matches the specified regular expression\n\
+                               (defaults to preserving all extended\n\
+                                attributes except file permissions;\n\
+                                regex=`-' preserves no extended attributes).\n\
+"), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
       fputs (_("\
@@ -796,6 +805,8 @@ cp_option_init (struct cp_options *x)
 
   x->dest_info = NULL;
   x->src_info = NULL;
+
+  x->attr_pattern = "";  /* all extended attributes */
 }
 
 /* Given a string, ARG, containing a comma-separated list of arguments
@@ -992,6 +1003,13 @@ main (int argc, char **argv)
 	  x.require_preserve = true;
 	  break;
 
+	case PRESERVE_XATTRS_OPTION:
+	  if (strcmp (optarg, "-") == 0)
+	    x.attr_pattern = NULL;
+	  else
+	    x.attr_pattern = optarg;
+	  break;
+
 	case PARENTS_OPTION:
 	  parents_option = true;
 	  break;
diff --git a/src/install.c b/src/install.c
index a7c3b3d..0bc5987 100644
--- a/src/install.c
+++ b/src/install.c
@@ -203,6 +203,8 @@ cp_option_init (struct cp_options *x)
   x->verbose = false;
   x->dest_info = NULL;
   x->src_info = NULL;
+
+  x->attr_pattern = NULL;  /* no extended attributes */
 }
 
 #ifdef ENABLE_MATCHPATHCON
diff --git a/src/mv.c b/src/mv.c
index fc255f3..3f42f78 100644
--- a/src/mv.c
+++ b/src/mv.c
@@ -151,6 +151,8 @@ cp_option_init (struct cp_options *x)
   x->verbose = false;
   x->dest_info = NULL;
   x->src_info = NULL;
+
+  x->attr_pattern = "";  /* all extended attributes */
 }
 
 /* FILE is the last operand of this command.  Return true if FILE is a
-- 
1.5.4.1

_______________________________________________
Bug-coreutils mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/bug-coreutils

Reply via email to