Index: coreutils-5.1.2/m4/xattr.m4 =================================================================== --- coreutils-5.1.2.orig/m4/xattr.m4 +++ coreutils-5.1.2/m4/xattr.m4 @@ -0,0 +1,38 @@ +# 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_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 +]) Index: coreutils-5.1.2/doc/coreutils.texi =================================================================== --- coreutils-5.1.2.orig/doc/coreutils.texi +++ coreutils-5.1.2/doc/coreutils.texi @@ -6137,6 +6137,18 @@ directory structure; i.e., @samp{ls -U} directory in a different order). Equivalent to @option{-dpPR}. +@itemx @w{@kbd{--attributes}=@var{regex}} +@opindex --attributes +Preserve extended attributes whose names match the specified regular +expression. The default behavior or @command{cp} if no +@option{--attributes} option is given is to preserve all extended +attributes except file permissions. If @var{regex} is ``@samp{-}'', 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 +@option{--preserve=mode} options. + @item -b @itemx @w{@kbd{--backup}[=@var{method}]} @opindex -b Index: coreutils-5.1.2/src/cp.c =================================================================== --- coreutils-5.1.2.orig/src/cp.c +++ coreutils-5.1.2/src/cp.c @@ -77,7 +77,8 @@ enum SPARSE_OPTION, STRIP_TRAILING_SLASHES_OPTION, TARGET_DIRECTORY_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. */ @@ -133,6 +134,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}, @@ -221,6 +223,13 @@ Mandatory arguments to long options are -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 (_("\ @@ -782,6 +791,8 @@ cp_option_init (struct cp_options *x) x->verbose = 0; 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 @@ -977,6 +988,13 @@ main (int argc, char **argv) x.require_preserve = 1; break; + case PRESERVE_XATTRS_OPTION: + if (strcmp (optarg, "-") == 0) + x.attr_pattern = NULL; + else + x.attr_pattern = optarg; + break; + case PARENTS_OPTION: flag_path = 1; break; Index: coreutils-5.1.2/src/mv.c =================================================================== --- coreutils-5.1.2.orig/src/mv.c +++ coreutils-5.1.2/src/mv.c @@ -137,6 +137,8 @@ cp_option_init (struct cp_options *x) x->xstat = lstat; x->dest_info = NULL; x->src_info = NULL; + + x->attr_pattern = ""; /* all extended attributes */ } /* If PATH is an existing directory, return nonzero, else 0. */ Index: coreutils-5.1.2/src/copy.c =================================================================== --- coreutils-5.1.2.orig/src/copy.c +++ coreutils-5.1.2/src/copy.c @@ -43,6 +43,13 @@ #include "xreadlink.h" #include "acl.h" +#if USE_XATTR +# include "regex.h" +# include +# include +# include +#endif + #define DO_CHOWN(Chown, File, New_uid, New_gid) \ (Chown (File, New_uid, New_gid) \ /* If non-root uses -p, it's ok if we can't preserve ownership. \ @@ -113,6 +120,104 @@ is_ancestor (const struct stat *sb, cons return 0; } +#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 (©_ctx->re_compiled, name, strlen (name), 0, + strlen (name), NULL) >= 0); +} +#endif /* USE_XATTR */ + +static int +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 0; + + if (copy_attr_ctx.re_pattern != x->attr_pattern) + { + struct re_pattern_buffer *c = ©_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, ©_attr_ctx.ctx); +#else /* USE_XATTR */ + return 0; +#endif /* USE_XATTR */ +} + /* Read the contents of the directory SRC_PATH_IN, and recursively copy the contents to DST_PATH_IN. NEW_DST is nonzero if DST_PATH_IN is a directory that was created previously in the @@ -1570,6 +1675,9 @@ copy_internal (const char *src_path, con } #endif + if (copy_extended_attributes (src_path, dst_path, x)) + delayed_fail = 1; + if (x->preserve_mode || x->move_mode) { if (copy_acl (src_path, dst_path, src_mode) && x->require_preserve) Index: coreutils-5.1.2/src/copy.h =================================================================== --- coreutils-5.1.2.orig/src/copy.h +++ coreutils-5.1.2/src/copy.h @@ -106,6 +106,10 @@ struct cp_options int preserve_mode; int 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 nonzero, attempt to preserve in the destination files any logical hard links between the source files. If used with cp's Index: coreutils-5.1.2/src/Makefile.am =================================================================== --- coreutils-5.1.2.orig/src/Makefile.am +++ coreutils-5.1.2/src/Makefile.am @@ -36,9 +36,9 @@ dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_ACL) shred_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) $(LIB_ACL) -cp_LDADD = $(LDADD) $(LIB_ACL) -mv_LDADD = $(LDADD) $(LIB_ACL) -ginstall_LDADD = $(LDADD) $(LIB_ACL) +cp_LDADD = $(LDADD) $(LIB_ACL) $(LIB_XATTR) +mv_LDADD = $(LDADD) $(LIB_ACL) $(LIB_XATTR) +ginstall_LDADD = $(LDADD) $(LIB_ACL) $(LIB_XATTR) ## If necessary, add -lm to resolve use of pow in lib/strtod.c. sort_LDADD = $(LDADD) $(POW_LIB) Index: coreutils-5.1.2/src/install.c =================================================================== --- coreutils-5.1.2.orig/src/install.c +++ coreutils-5.1.2/src/install.c @@ -167,6 +167,8 @@ cp_option_init (struct cp_options *x) x->xstat = stat; x->dest_info = NULL; x->src_info = NULL; + + x->attr_pattern = NULL; /* no extended attributes */ } int Index: coreutils-5.1.2/configure.ac =================================================================== --- coreutils-5.1.2.orig/configure.ac +++ coreutils-5.1.2/configure.ac @@ -227,6 +227,9 @@ fi # For src/kill.c. AC_CHECK_DECLS([strsignal, strtoimax, sys_siglist, _sys_siglist, __sys_siglist]) +# Extended attribute copying. +AC_FUNC_XATTR + jm_LIB_CHECK AM_GNU_GETTEXT([external], [need-ngettext])