summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS6
-rw-r--r--bootstrap.conf2
-rw-r--r--doc/coreutils.texi13
-rw-r--r--m4/prereq.m41
-rw-r--r--m4/xattr.m436
-rw-r--r--po/POTFILES.in3
-rw-r--r--src/Makefile.am6
-rw-r--r--src/copy.c84
-rw-r--r--src/copy.h13
-rw-r--r--src/cp.c23
-rw-r--r--src/install.c1
-rw-r--r--src/mv.c1
-rw-r--r--tests/Makefile.am1
-rwxr-xr-xtests/misc/xattr111
14 files changed, 291 insertions, 10 deletions
diff --git a/NEWS b/NEWS
index 99fc182f8..a83ca66dc 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,12 @@ GNU coreutils NEWS -*- outline -*-
** New features
+ Add extended attribute support available on certain filesystems like ext2
+ and XFS.
+ cp: Tries to copy xattrs when --preserve=xattr specified
+ mv: Always tries to copy xattrs
+ install: Never copies xattrs
+
cp and mv accept a new option, --no-clobber (-n): silently refrain
from overwriting any existing destination file
diff --git a/bootstrap.conf b/bootstrap.conf
index 1388782be..89564fe29 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -102,7 +102,7 @@ gnulib_modules="
userspec utimecmp utimens
vasprintf-posix
vc-list-files
- verify version-etc-fsf
+ verify version-etc-fsf verror
warnings
wcwidth winsz-ioctl winsz-termios write-any-file
xalloc
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index d8b90876d..7ba872ebb 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -7365,7 +7365,7 @@ symbolic links in the destination are always followed if possible.
@itemx @w{@kbd{--preserve}[=@var{attribute_list}]}
@opindex -p
@opindex --preserve
-@cindex file information, preserving
+@cindex file information, preserving, extended attributes, xattr
Preserve the specified attributes of the original files.
If specified, the @var{attribute_list} must be a comma-separated list
of one or more of the following strings:
@@ -7392,6 +7392,11 @@ 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.
+@itemx xattr
+Preserve extended attributes if @command{cp} is built with xattr support,
+and xattrs are supported and enabled on your file system.
+If SELinux context and/or ACLs are implemented using xattrs,
+they are preserved by this option as well.
@itemx all
Preserve all file attributes.
Equivalent to specifying all of the above.
@@ -7935,6 +7940,9 @@ attributes of destination files. It is typically used in Makefiles to
copy programs into their destination directories. It refuses to copy
files onto themselves.
+@cindex extended attributes, xattr
+@command{install} never preserves extended attributes (xattr).
+
The program accepts the following options. Also see @ref{Common options}.
@table @samp
@@ -8083,6 +8091,9 @@ directory succeeded, but the second didn't, the first would be left on
the destination partition and the second and third would be left on the
original partition.
+@cindex extended attributes, xattr
+@command{mv} always tries to copy extended attributes (xattr).
+
@cindex prompting, and @command{mv}
If a destination file exists but is normally unwritable, standard input
is a terminal, and the @option{-f} or @option{--force} option is not given,
diff --git a/m4/prereq.m4 b/m4/prereq.m4
index e65682fea..536070efe 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 000000000..c5bf12988
--- /dev/null
+++ b/m4/xattr.m4
@@ -0,0 +1,36 @@
+# xattr.m4 - check for Extended Attributes (Linux)
+
+# Copyright (C) 2003, 2008 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Originally written by Andreas Gruenbacher.
+# http://www.suse.de/~agruen/coreutils/5.91/coreutils-xattr.diff
+
+AC_DEFUN([gl_FUNC_XATTR],
+[
+ AC_ARG_ENABLE([xattr],
+ AC_HELP_STRING([--disable-xattr],
+ [do not support 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_CHECK_FUNCS([attr_copy_file])
+ LIBS=$xattr_saved_LIBS
+ AC_SUBST([LIB_XATTR])
+ fi
+])
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 9bd8c43a9..6c291ccb6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,5 +1,5 @@
# List of files which contain translatable strings.
-# Copyright (C) 1996-2008 Free Software Foundation, Inc.
+# Copyright (C) 1996-2009 Free Software Foundation, Inc.
# These are nominally temporary...
lib/argmatch.c
@@ -22,6 +22,7 @@ lib/rpmatch.c
lib/set-mode-acl.c
lib/unicodeio.c
lib/userspec.c
+lib/verror.c
lib/version-etc.c
lib/xalloc-die.c
lib/xfreopen.c
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 <attr/error_context.h>
+# include <attr/libattr.h>
+# include <stdarg.h>
+# 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;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4f8e40855..99d2856c5 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -234,6 +234,7 @@ TESTS = \
misc/tty-eof \
misc/unexpand \
misc/uniq \
+ misc/xattr \
chmod/c-option \
chmod/equal-x \
chmod/equals \
diff --git a/tests/misc/xattr b/tests/misc/xattr
new file mode 100755
index 000000000..4137c53cb
--- /dev/null
+++ b/tests/misc/xattr
@@ -0,0 +1,111 @@
+#!/bin/sh
+# Ensure that cp --preserve=xattr and mv preserve extended attributes and
+# install does not preserve extended attributes.
+
+# Copyright (C) 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
+# 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
+ mv --version
+ ginstall --version
+fi
+
+. $srcdir/test-lib.sh
+
+# Skip this test if cp was built without xattr support:
+touch src dest || framework_failure
+cp --preserve=xattr -n src dest 2>/dev/null \
+ || skip_test_ "coreutils built without xattr support"
+
+# this code was taken from test mv/backup-is-src
+cleanup_() { rm -rf "$other_partition_tmpdir"; }
+. "$abs_srcdir/other-fs-tmpdir"
+b_other="$other_partition_tmpdir/b"
+rm -f $b_other || framework_failure
+
+# 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"
+grep -F "$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"
+grep -F "$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"
+grep -F "$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"
+grep -F "$xattr_pair" out_b >/dev/null || fail=1
+
+rm b || framework_failure
+
+# install should never preserve xattr
+ginstall a b || fail=1
+getfattr -d b >out_b || skip_test_ "failed to get xattr of file"
+grep -F "$xattr_pair" out_b >/dev/null && fail=1
+
+# mv should preserve xattr when renaming within a file system.
+# This is implicitly done by rename () and doesn't need explicit
+# xattr support in mv.
+mv a b || fail=1
+getfattr -d b >out_b || skip_test_ "failed to get xattr of file"
+grep -F "$xattr_pair" out_b >/dev/null || cat >&2 <<EOF
+=================================================================
+$0: WARNING!!!
+rename () does not preserve extended attributes
+=================================================================
+EOF
+
+# try to set user xattr on file on other partition
+test_mv=1
+touch $b_other || framework_failure
+setfattr -n "$xattr_name" -v "$xattr_value" $b_other >out_a 2>/dev/null \
+ || test_mv=0
+getfattr -d $b_other >out_b 2>/dev/null || test_mv=0
+grep -F "$xattr_pair" out_b >/dev/null || test_mv=0
+rm -f $b_other || framework_failure
+
+if test $test_mv -eq 1; then
+ # mv should preserve xattr when copying content from one partition to another
+ mv b $b_other || fail=1
+ getfattr -d $b_other >out_b 2>/dev/null || skip_test_ "failed to get xattr of file"
+ grep -F "$xattr_pair" out_b >/dev/null || fail=1
+else
+ cat >&2 <<EOF
+=================================================================
+$0: WARNING!!!
+failed to set xattr of file $b_other
+=================================================================
+EOF
+fi
+
+Exit $fail