From 0889381cbfdbb4895e6b8693d14c0f5c77bc85bc Mon Sep 17 00:00:00 2001 From: Kamil Dudka Date: Fri, 23 Jan 2009 12:17:53 +0100 Subject: cp/mv: add xattr support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch was originally written by Andreas Grünbacher, nowadays available at http://www.suse.de/~agruen/coreutils/5.91/coreutils-xattr.diff * bootstrap.conf: Add gnulib module verror. * po/POTFILES.in: Add lib/verror.c. * 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 and require_preserve_xattr to cp_options. * src/copy.c (copy_attr_error): New function to handle errors during xattr copying. (copy_attr_quote): New function to quote file name in error messages printed by libattr. (copy_attr_free): Empty function requested by libattr to free quoted string. (copy_attr_by_fd): New fd-oriented function to copy xattr. (copy_attr_by_name): New name-oriented 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/misc/xattr: New test for xattr support in cp, mv and install. * tests/Makefile.am: Add the new test to list. * doc/coreutils.texi: Mention xattr support, new --preserve=xattr option. * NEWS: Mention the change. --- src/Makefile.am | 6 ++--- src/copy.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/copy.h | 13 +++++++++ src/cp.c | 23 +++++++++++++--- src/install.c | 1 + src/mv.c | 1 + 6 files changed, 121 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 555700bad..907b9e799 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -152,9 +152,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 c9c79a1b1..85d1fea13 100644 --- a/src/copy.c +++ b/src/copy.c @@ -1,5 +1,5 @@ /* copy.c -- core functions for copying files and directories - Copyright (C) 89, 90, 91, 1995-2008 Free Software Foundation, Inc. + Copyright (C) 89, 90, 91, 1995-2009 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 @@ -54,6 +54,13 @@ #include "areadlink.h" #include "yesno.h" +#if USE_XATTR +# include +# include +# include +# include "verror.h" +#endif + #ifndef HAVE_FCHOWN # define HAVE_FCHOWN false # define fchown(fd, uid, gid) (-1) @@ -123,6 +130,72 @@ 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 ATTRIBUTE_UNUSED, + char const *fmt, ...) +{ + int err = errno; + va_list ap; + + /* use verror module to print error message */ + va_start (ap, fmt); + verror (0, err, fmt, ap); + va_end (ap); +} + +static char const * +copy_attr_quote (struct error_context *ctx ATTRIBUTE_UNUSED, char const *str) +{ + return quote (str); +} + +static void +copy_attr_free (struct error_context *ctx ATTRIBUTE_UNUSED, + char const *str ATTRIBUTE_UNUSED) +{ +} + +static bool +copy_attr_by_fd (char const *src_path, int src_fd, + char const *dst_path, int dst_fd) +{ + struct error_context ctx = + { + .error = copy_attr_error, + .quote = copy_attr_quote, + .quote_free = copy_attr_free + }; + return 0 == attr_copy_fd (src_path, src_fd, dst_path, dst_fd, 0, &ctx); +} + +static bool +copy_attr_by_name (char const *src_path, char const *dst_path) +{ + struct error_context ctx = + { + .error = copy_attr_error, + .quote = copy_attr_quote, + .quote_free = copy_attr_free + }; + return 0 == attr_copy_file (src_path, dst_path, 0, &ctx); +} +#else /* USE_XATTR */ + +static bool +copy_attr_by_fd (char const *src_path, int src_fd, + char const *dst_path, int dst_fd) +{ + return true; +} + +static bool +copy_attr_by_name (char const *src_path, char const *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 +754,11 @@ copy_reg (char const *src_name, char const *dst_name, set_author (dst_name, dest_desc, src_sb); + if (x->preserve_xattr && ! copy_attr_by_fd (src_name, source_desc, + dst_name, dest_desc) + && x->require_preserve_xattr) + return false; + if (x->preserve_mode || x->move_mode) { if (copy_acl (src_name, source_desc, dst_name, dest_desc, src_mode) != 0 @@ -1985,6 +2063,10 @@ copy_internal (char const *src_name, char const *dst_name, set_author (dst_name, -1, &src_sb); + if (x->preserve_xattr && ! copy_attr_by_name (src_name, dst_name) + && x->require_preserve_xattr) + return 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 12b7c2d28..e6604ee71 100644 --- a/src/copy.h +++ b/src/copy.h @@ -173,6 +173,19 @@ 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; + + /* Useful only when preserve_xattr is true. + If true, a failed attempt to preserve file's extended attributes + propagates failure "out" to the caller. If false, a failure to + preserve file's extended attributes does not change the invoking + application's exit status. Give diagnostics for failed syscalls + regardless of this setting. For example, with "cp --preserve=xattr" + this flag is "true", while with "cp --preserve=all", it is false. */ + bool require_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 191f73e7b..9171fa652 100644 --- a/src/cp.c +++ b/src/cp.c @@ -187,7 +187,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\ @@ -764,6 +765,8 @@ 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_xattr = false; x->require_preserve = false; x->recursive = false; @@ -800,18 +803,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); @@ -852,6 +857,11 @@ 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; + x->require_preserve_xattr = on_off; + break; + case PRESERVE_ALL: x->preserve_mode = on_off; x->preserve_timestamps = on_off; @@ -859,6 +869,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: @@ -1099,6 +1110,12 @@ main (int argc, char **argv) "without an SELinux-enabled kernel")); } +#if !USE_XATTR + if (x.require_preserve_xattr) + error (EXIT_FAILURE, 0, _("cannot preserve extended attributes, cp is " + "built without xattr support")); +#endif + /* Allocate space for remembering copied and created files. */ hash_init (); diff --git a/src/install.c b/src/install.c index 9dda05ade..9bf9eee0f 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 a5ab95dcf..db9207bd5 100644 --- a/src/mv.c +++ b/src/mv.c @@ -124,6 +124,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; -- cgit v1.2.3-70-g09d2