# --- ROCK-COPYRIGHT-NOTE-BEGIN ---
# 
# This copyright note is auto-generated by ./scripts/Create-CopyPatch.
# Please add additional copyright information _after_ the line containing
# the ROCK-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by
# the ./scripts/Create-CopyPatch script. Do not edit this copyright text!
# 
# ROCK Linux: rock-src/package/base/coreutils/acl-xattr.diff
# ROCK Linux is Copyright (C) 1998 - 2006 Clifford Wolf
# 
# This patch file is dual-licensed. It is available under the license the
# patched project is licensed under, as long as it is an OpenSource license
# as defined at http://www.opensource.org/ (e.g. BSD, X11) or under the terms
# of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
# 
# --- ROCK-COPYRIGHT-NOTE-END ---

Andreas Gruenbacher patches for ACL and XATTR support in coreutils.

http://www.suse.de/~agruen/coreutils/5.91/coreutils-acl.diff
http://www.suse.de/~agruen/coreutils/5.91/coreutils-acl+posix.diff
http://www.suse.de/~agruen/coreutils/5.91/coreutils-xattr.diff

(merged using combinediff)

------------------------------------------------------------------------------

--- coreutils-5.91/doc/coreutils.texi
+++ coreutils-5.91/doc/coreutils.texi
@@ -5610,9 +5610,14 @@
 @end table
 
 Following the permission bits is a single character that specifies
-whether an alternate access method applies to the file.  When that
-character is a space, there is no alternate access method.  When it
-is a printing character (e.g., @samp{+}), then there is such a method.
+whether an alternate access method such as an access control list
+applies to the file. When the character following the permissions is a
+space, there is no alternate access method. When it is a printing
+character, then there is such a method.
+
+For a file with an extended access control list, a @samp{+} character is
+listed. Basic access control lists are equivalent to the permissions
+listed, and are not considered an alternate access method.
 
 @item -n
 @itemx --numeric-uid-gid
@@ -6345,6 +6350,18 @@
 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
@@ -6448,7 +6465,7 @@
 
 @table @samp
 @itemx mode
-Preserve the permission attributes.
+Preserve the permission attributes, including access control lists.
 @itemx ownership
 Preserve the owner and group.  On most modern systems,
 only the super-user may change the owner of a file, and regular users
@@ -6464,7 +6481,6 @@
 @itemx all
 Preserve all file attributes.
 Equivalent to specifying all of the above.
-@c Mention ACLs here.
 @end table
 
 Using @option{--preserve} with no @var{attribute_list} is equivalent
--- coreutils-5.91/lib/acl.c
+++ coreutils-5.91/lib/acl.c
@@ -22,18 +22,35 @@
 # include <config.h>
 #endif
 
+#include <stdlib.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #ifndef S_ISLNK
 # define S_ISLNK(Mode) 0
 #endif
 
+#include "error.h"
+#include "quote.h"
 #include "acl.h"
 
+#ifdef HAVE_ACL_LIBACL_H
+# include <acl/libacl.h>
+#endif
+
 #include <errno.h>
 #ifndef ENOSYS
 # define ENOSYS (-1)
 #endif
+#ifndef ENOTSUP
+# define ENOTSUP (-1)
+#endif
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+#else
+# define _(Text) Text
+#endif
 
 #ifndef MIN_ACL_ENTRIES
 # define MIN_ACL_ENTRIES 4
@@ -47,17 +64,196 @@
 {
-  /* FIXME: This implementation should work on recent-enough versions
-     of HP-UX, Solaris, and Unixware, but it simply returns 0 with
-     POSIX 1003.1e (draft 17 -- abandoned), AIX, GNU/Linux, Irix, and
-     Tru64.  Please see Samba's source/lib/sysacls.c file for
-     fix-related ideas.  */
+#if USE_ACL && HAVE_ACL && defined GETACLCNT
+  /* This implementation should work on recent-enough versions of HP-UX,
+     Solaris, and Unixware.  */
 
-#if HAVE_ACL && defined GETACLCNT
   if (! S_ISLNK (filestat->st_mode))
     {
       int n = acl (file, GETACLCNT, 0, NULL);
       return n < 0 ? (errno == ENOSYS ? 0 : -1) : (MIN_ACL_ENTRIES < n);
     }
+#elif USE_ACL && HAVE_ACL_EXTENDED_FILE
+  /* Linux specific version.  */
+
+  if (! S_ISLNK (filestat->st_mode))
+    {
+      int ret = acl_extended_file (file);
+      if (ret < 0)
+	return (errno == ENOSYS || errno == ENOTSUP) ? 0 : -1;
+      return ret;
+    }
+#endif
+
+  /* FIXME: Add support for POSIX 1003.1e (draft 17 -- abandoned), AIX, Irix,
+     and Tru64.  Please see Samba's source/lib/sysacls.c file for fix-related
+     ideas.  */
+
+  return 0;
+}
+
+/* Copy the access control list of src_file to dst_file. Fall back to
+   src_st.st_mode if access control lists are not supported for either
+   file.  */
+int
+copy_acl (char const *src_file, char const *dst_file, mode_t mode)
+{
+#if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && \
+    HAVE_ACL_FREE && HAVE_ACL_ENTRIES
+  /* Linux specific. Will work on all POSIX 1003.1e draft 17 (abandoned)
+     systems if the Linux specific acl_entries() function is substituted.  */
+
+  acl_t acl = acl_get_file (src_file, ACL_TYPE_ACCESS);
+  if (acl == NULL)
+    {
+      if (errno == ENOSYS || errno == ENOTSUP)
+	return set_acl (dst_file, mode);
+      else
+        {
+	  error (0, errno, "%s", quote (src_file));
+	  return -1;
+	}
+    }
+
+  if (acl_set_file (dst_file, ACL_TYPE_ACCESS, acl))
+    {
+      int saved_errno = errno;
+
+      if (errno == ENOSYS || errno == ENOTSUP)
+        {
+	  int n = acl_entries (acl);
+
+	  acl_free (acl);
+	  if (n == 3)
+	    {
+	      if (chmod (dst_file, mode))
+		saved_errno = errno;
+	      else
+		return 0;
+	    }
+	  else
+	    chmod (dst_file, mode);
+	}
+      else
+	{
+	  acl_free (acl);
+	  chmod (dst_file, mode);
+	}
+      error (0, saved_errno, _("preserving permissions for %s"),
+	     quote (dst_file));
+      return -1;
+    }
+  else
+    acl_free (acl);
+
+  if (mode & (S_ISUID | S_ISGID | S_ISVTX))
+    {
+      /* We did not call chmod so far, so the special bits have not yet
+         been set.  */
+
+      if (chmod (dst_file, mode))
+	{
+	  error (0, errno, _("preserving permissions for %s"),
+	  	 quote (dst_file));
+	  return -1;
+	}
+    }
+
+  if (S_ISDIR (mode))
+    {
+      acl = acl_get_file (src_file, ACL_TYPE_DEFAULT);
+      if (acl == NULL)
+	{
+	  error (0, errno, "%s", quote (src_file));
+	  return -1;
+	}
+
+      if (acl_set_file (dst_file, ACL_TYPE_DEFAULT, acl))
+	{
+	  error (0, errno, _("preserving permissions for %s"),
+		 quote (dst_file));
+	  acl_free(acl);
+	  return -1;
+	}
+      else
+        acl_free(acl);
+    }
+  return 0;
+#else
+  int ret = chmod (dst_file, mode);
+  if (ret)
+    error (0, errno, _("preserving permissions for %s"), quote (dst_file));
+  return ret;
 #endif
+}
+
+/* Set the access control list of path to the permissions defined by mode.  */
+int
+set_acl (char const *path, mode_t mode)
+{
+#if USE_ACL && HAVE_ACL_FROM_TEXT && HAVE_ACL_SET_FILE && HAVE_ACL_FREE && \
+    HAVE_ACL_DELETE_DEF_FILE
+  /* POSIX 1003.1e draft 17 (abandoned) specific version.  */
+
+  char acl_text[] = "u::---,g::---,o::---";
+  acl_t acl;
+
+  if (mode & S_IRUSR) acl_text[ 3] = 'r';
+  if (mode & S_IWUSR) acl_text[ 4] = 'w';
+  if (mode & S_IXUSR) acl_text[ 5] = 'x';
+  if (mode & S_IRGRP) acl_text[10] = 'r';
+  if (mode & S_IWGRP) acl_text[11] = 'w';
+  if (mode & S_IXGRP) acl_text[12] = 'x';
+  if (mode & S_IROTH) acl_text[17] = 'r';
+  if (mode & S_IWOTH) acl_text[18] = 'w';
+  if (mode & S_IXOTH) acl_text[19] = 'x';
 
+  acl = acl_from_text(acl_text);
+  if (!acl)
+    {
+      error (0, errno, "%s", quote (path));
+      return -1;
+    }
+
+  if (acl_set_file(path, ACL_TYPE_ACCESS, acl))
+    {
+      int saved_errno = errno;
+      acl_free (acl);
+
+      if (errno == ENOTSUP || errno == ENOSYS)
+	{
+	  if (chmod (path, mode))
+	    saved_errno = errno;
+	  else
+	    return 0;
+	}
+      error (0, saved_errno, _("setting permissions for %s"), quote (path));
+      return -1;
+    }
+  else
+    acl_free (acl);
+
+  if (mode & (S_ISUID | S_ISGID | S_ISVTX))
+    {
+      /* We did not call chmod so far, so the special bits have not yet
+         been set.  */
+
+      if (chmod (path, mode))
+	{
+	  error (0, errno, _("preserving permissions for %s"),
+	  	 quote (path));
+	  return -1;
+	}
+    }
+
+  if (S_ISDIR (mode) && acl_delete_def_file (path))
+    {
+      error (0, errno, _("setting permissions for %s"), quote (path));
+      return -1;
+    }
   return 0;
+#else
+  int ret = chmod (path, mode);
+  if (ret)
+    error (0, errno, _("setting permissions for %s"), quote (path));
+  return ret;
+#endif
 }
--- coreutils-5.91/lib/acl.h
+++ coreutils-5.91/lib/acl.h
@@ -18,11 +18,13 @@
 
    Written by Paul Eggert.  */
 
-#if HAVE_SYS_ACL_H && HAVE_ACL
+#if HAVE_SYS_ACL_H
 # include <sys/acl.h>
 #endif
-#if ! defined GETACLCNT && defined ACL_CNT
+#if defined HAVE_ACL && ! defined GETACLCNT && defined ACL_CNT
 # define GETACLCNT ACL_CNT
 #endif
 
 int file_has_acl (char const *, struct stat const *);
+int copy_acl(char const *, char const *, mode_t);
+int set_acl(char const *, mode_t);
--- coreutils-5.91/src/copy.c
+++ coreutils-5.91/src/copy.c
@@ -50,6 +50,14 @@
 #include "utimens.h"
 #include "xreadlink.h"
 #include "yesno.h"
+#include "acl.h"
+
+#if USE_XATTR
+# include "regex.h"
+# include <stdarg.h>
+# include <attr/error_context.h>
+# include <attr/libattr.h>
+#endif
 
 #ifndef HAVE_FCHMOD
 # define HAVE_FCHMOD false
@@ -101,26 +109,6 @@
 /* The invocation name of this program.  */
 extern char *program_name;
 
-/* Encapsulate selection of the file mode to be applied to
-   new non-directories.  */
-
-static mode_t
-get_dest_mode (const struct cp_options *option, mode_t mode)
-{
-  /* In some applications (e.g., install), use precisely the
-     specified mode.  */
-  if (option->set_mode)
-    return option->mode;
-
-  /* Honor the umask for `cp', but not for `mv' or `cp -p'.
-     In addition, `cp' without -p must clear the set-user-ID and set-group-ID
-     bits.  POSIX requires it do that when creating new files.  */
-  if (!option->move_mode && !option->preserve_mode)
-    mode &= (option->umask_kill & ~(S_ISUID | S_ISGID));
-
-  return mode;
-}
-
 /* FIXME: describe */
 /* FIXME: rewrite this to use a hash table so we avoid the quadratic
    performance hit that's probably noticeable only on trees deeper
@@ -138,6 +126,104 @@
   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
@@ -205,7 +291,6 @@
 static bool
 copy_reg (char const *src_name, char const *dst_name,
 	  const struct cp_options *x, mode_t dst_mode, bool *new_dst,
-	  bool *chown_succeeded,
 	  struct stat const *src_sb,
 	  struct stat const *dst_sb)
 {
@@ -435,9 +520,8 @@
   if (x->preserve_ownership
       && (*new_dst || !SAME_OWNER_AND_GROUP (*src_sb, *dst_sb)))
     {
-      if (fchown (dest_desc, src_sb->st_uid, src_sb->st_gid) == 0)
-	*chown_succeeded = true;
-      else if (! chown_failure_ok (x))
+      if (! fchown (dest_desc, src_sb->st_uid, src_sb->st_gid) == 0 &&
+     	  ! chown_failure_ok (x))
 	{
 	  error (0, errno, _("failed to preserve ownership for %s"),
 		 quote (dst_name));
@@ -454,27 +538,6 @@
   /* FIXME: Preserve the st_author field via the file descriptor dest_desc.  */
 #endif
 
-#if HAVE_FCHMOD
-  /* Permissions of newly-created regular files were set upon `open'.
-     But don't return early if there were any special bits and chown
-     succeeded, because the chown must have reset those bits.  */
-  if (!(*new_dst
-	&& !(*chown_succeeded && (src_sb->st_mode & ~S_IRWXUGO)))
-      && (x->preserve_mode || *new_dst)
-      && (x->copy_as_regular || S_ISREG (src_sb->st_mode)))
-    {
-      if (fchmod (dest_desc, get_dest_mode (x, src_sb->st_mode)) != 0)
-	{
-	  error (0, errno, _("setting permissions for %s"), quote (dst_name));
-	  if (x->set_mode || x->require_preserve)
-	    {
-	      return_val = false;
-	      goto close_src_and_dst_desc;
-	    }
-	}
-    }
-#endif
-
 close_src_and_dst_desc:
   if (close (dest_desc) < 0)
     {
@@ -909,12 +972,13 @@
   struct stat dst_sb;
   mode_t src_mode;
   mode_t src_type;
+  mode_t dst_mode IF_LINT (= 0);
+  int dst_mode_valid = 0;
   char *earlier_file = NULL;
   char *dst_backup = NULL;
   bool backup_succeeded = false;
   bool delayed_ok;
   bool copied_as_regular = false;
-  bool chown_succeeded = false;
   bool preserve_metadata;
 
   if (x->move_mode && rename_succeeded)
@@ -1430,22 +1494,43 @@
 
       if (new_dst || !S_ISDIR (dst_sb.st_mode))
 	{
-	  /* Create the new directory writable and searchable, so
-             we can create new entries in it.  */
-
-	  if (mkdir (dst_name, (src_mode & x->umask_kill) | S_IRWXU) != 0)
+	  if (mkdir (dst_name, src_mode) != 0)
 	    {
 	      error (0, errno, _("cannot create directory %s"),
 		     quote (dst_name));
 	      goto un_backup;
 	    }
 
+	  /* We need search and write permissions to the new directory
+	     for writing the directory's contents. Check if these
+	     permissions are there.  */
+
+	  if (lstat (dst_name, &dst_sb))
+	    {
+	      error (0, errno, _("cannot stat %s"), quote (dst_name));
+	      goto un_backup;
+	    }
+	  else if ((dst_sb.st_mode & S_IRWXU) != S_IRWXU)
+	    {
+	      /* Make the new directory searchable and writable. The
+		 original permissions will be restored later.  */
+
+	      dst_mode = dst_sb.st_mode;
+	      dst_mode_valid = 1;
+
+	      if (chmod (dst_name, dst_mode | S_IRWXU))
+		{
+		  error (0, errno, _("setting permissions for %s"),
+			 quote (dst_name));
+		  goto un_backup;
+		}
+	    }
+
 	  /* Insert the created directory's inode and device
              numbers into the search structure, so that we can
              avoid copying it again.  */
 
-	  if (! remember_created (dst_name))
-	    goto un_backup;
+	  remember_copied (dst_name, dst_sb.st_ino, dst_sb.st_dev);
 
 	  if (x->verbose)
 	    printf ("%s -> %s\n", quote_n (0, src_name), quote_n (1, dst_name));
@@ -1522,8 +1607,7 @@
       /* POSIX says the permission bits of the source file must be
 	 used as the 3rd argument in the open call, but that's not consistent
 	 with historical practice.  */
-      if (! copy_reg (src_name, dst_name, x,
-		      get_dest_mode (x, src_mode), &new_dst, &chown_succeeded,
+      if (! copy_reg (src_name, dst_name, x, src_mode, &new_dst,
 		      &src_sb, &dst_sb))
 	goto un_backup;
     }
@@ -1531,7 +1615,7 @@
 #ifdef S_ISFIFO
   if (S_ISFIFO (src_type))
     {
-      if (mkfifo (dst_name, get_dest_mode (x, src_mode)))
+      if (mkfifo (dst_name, src_mode))
 	{
 	  error (0, errno, _("cannot create fifo %s"), quote (dst_name));
 	  goto un_backup;
@@ -1542,7 +1626,7 @@
     if (S_ISBLK (src_type) || S_ISCHR (src_type)
 	|| S_ISSOCK (src_type))
     {
-      if (mknod (dst_name, get_dest_mode (x, src_mode), src_sb.st_rdev))
+      if (mknod (dst_name, src_mode, src_sb.st_rdev))
 	{
 	  error (0, errno, _("cannot create special file %s"),
 		 quote (dst_name));
@@ -1654,9 +1738,8 @@
   if (!(copied_as_regular && HAVE_FCHOWN) && x->preserve_ownership
       && (new_dst || !SAME_OWNER_AND_GROUP (src_sb, dst_sb)))
     {
-      if (chown (dst_name, src_sb.st_uid, src_sb.st_gid) == 0)
-	chown_succeeded = true;
-      else if (! chown_failure_ok (x))
+      if (! chown (dst_name, src_sb.st_uid, src_sb.st_gid) == 0 &&
+	  ! chown_failure_ok (x))
 	{
 	  error (0, errno, _("failed to preserve ownership for %s"),
 		 quote (dst_name));
@@ -1682,21 +1765,30 @@
   }
 #endif
 
-  /* Permissions of newly-created regular files are set by open and/or fchmod
-     in copy_reg.  But don't return early if there were any special bits and
-     chown succeeded, because the chown must have reset those bits.  */
-  if (copied_as_regular
-      && (HAVE_FCHMOD
-	  || (new_dst && !(chown_succeeded && (src_mode & ~S_IRWXUGO)))))
-    return delayed_ok;
+  if (! copy_extended_attributes (src_name, dst_name, x))
+    delayed_ok = false;
 
-  if ((x->preserve_mode || new_dst)
-      && (x->copy_as_regular || S_ISREG (src_type) || S_ISDIR (src_type)))
+  if (x->preserve_mode || x->move_mode)
     {
-      if (chmod (dst_name, get_dest_mode (x, src_mode)) != 0)
+      if (copy_acl (src_name, dst_name, src_mode) && x->require_preserve)
+	return false;
+    }
+  else if (x->set_mode)
+    {
+      if (chmod (dst_name, x->mode))
 	{
-	  error (0, errno, _("setting permissions for %s"), quote (dst_name));
-	  if (x->set_mode || x->require_preserve)
+	  error (0, errno, _("setting permissions for %s"),
+		 quote (dst_name));
+	  return false;
+	}
+    }
+  else if (dst_mode_valid)
+    {
+      if (chmod (dst_name, dst_mode))
+	{
+	  error (0, errno, _("preserving permissions for %s"),
+		 quote (dst_name));
+	  if (x->require_preserve)
 	    return false;
 	}
     }
--- coreutils-5.91/src/copy.h
+++ coreutils-5.91/src/copy.h
@@ -128,6 +128,10 @@
   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
@@ -165,9 +169,6 @@
      Create destination directories as usual. */
   bool symbolic_link;
 
-  /* The bits to preserve in created files' modes. */
-  mode_t umask_kill;
-
   /* If true, do not copy a nondirectory that has an existing destination
      with the same or newer modification time. */
   bool update;
--- coreutils-5.91/src/cp.c
+++ coreutils-5.91/src/cp.c
@@ -35,6 +35,7 @@
 #include "quotearg.h"
 #include "stat-time.h"
 #include "utimens.h"
+#include "acl.h"
 
 #define ASSIGN_BASENAME_STRDUPA(Dest, File_name)	\
   do							\
@@ -56,7 +57,8 @@
    need to be fixed after copying. */
 struct dir_attr
 {
-  bool is_new_dir;
+  mode_t mode;
+  bool mode_valid;
   size_t slash_offset;
   struct dir_attr *next;
 };
@@ -72,7 +74,8 @@
   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.  */
@@ -129,6 +132,7 @@
   {"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,
@@ -219,6 +223,13 @@
   -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 (_("\
@@ -327,9 +338,14 @@
 	    }
 	}
 
-      if (x->preserve_mode | p->is_new_dir)
+      if (x->preserve_mode)
+	{
+	  if (copy_acl (src_name, dst_name, src_sb.st_mode))
+	    return false;
+	}
+      else if (p->mode_valid)
 	{
-	  if (chmod (dst_name, src_sb.st_mode & x->umask_kill))
+	  if (chmod (dst_name, p->mode))
 	    {
 	      error (0, errno, _("failed to preserve permissions for %s"),
 		     quote (dst_name));
@@ -347,8 +363,7 @@
 
    SRC_OFFSET is the index in CONST_DIR (which is a destination
    directory) of the beginning of the source directory name.
-   Create any leading directories that don't already exist,
-   giving them permissions MODE.
+   Create any leading directories that don't already exist.
    If VERBOSE_FMT_STRING is nonzero, use it as a printf format
    string for printing a message after successfully making a directory.
    The format should take two string arguments: the names of the
@@ -364,9 +379,9 @@
 
 static bool
 make_dir_parents_private (char const *const_dir, size_t src_offset,
-			  mode_t mode, char const *verbose_fmt_string,
+			  char const *verbose_fmt_string,
 			  struct dir_attr **attr_list, bool *new_dst,
-			  int (*xstat) ())
+			  const struct cp_options *x)
 {
   struct stat stats;
   char *dir;		/* A copy of CONST_DIR we can change.  */
@@ -385,7 +400,7 @@
 
   *attr_list = NULL;
 
-  if ((*xstat) (dst_dir, &stats))
+  if (XSTAT (x, dst_dir, &stats))
     {
       /* A parent of CONST_DIR does not exist.
 	 Make all missing intermediate directories. */
@@ -404,16 +419,25 @@
 	  *attr_list = new;
 
 	  *slash = '\0';
-	  if ((*xstat) (dir, &stats))
+	  if (XSTAT (x, dir, &stats))
 	    {
+	      mode_t src_mode;
+
 	      /* This component does not exist.  We must set
-		 *new_dst and new->is_new_dir inside this loop because,
+		 *new_dst and new->mode inside this loop because,
 		 for example, in the command `cp --parents ../a/../b/c e_dir',
 		 make_dir_parents_private creates only e_dir/../a if
 		 ./b already exists. */
 	      *new_dst = true;
-	      new->is_new_dir = true;
-	      if (mkdir (dir, mode))
+	      if (XSTAT (x, src, &stats))
+		{
+		  error (0, errno, _("failed to get attributes of %s"),
+			 quote (src));
+		  return false;
+		}
+	      src_mode = stats.st_mode;
+
+	      if (mkdir (dir, src_mode))
 		{
 		  error (0, errno, _("cannot make directory %s"),
 			 quote (dir));
@@ -424,6 +448,45 @@
 		  if (verbose_fmt_string != NULL)
 		    printf (verbose_fmt_string, src, dir);
 		}
+
+	      /* We need search and write permissions to the new directory
+	         for writing the directory's contents. Check if these
+		 permissions are there.  */
+
+	      if (lstat (dir, &stats))
+		{
+		  error (0, errno, _("failed to get attributes of %s"),
+			 quote (dir));
+		  return false;
+		}
+	      else
+	        {
+		  if (x->preserve_mode)
+		    {
+		      new->mode = src_mode;
+		      new->mode_valid = (src_mode != stats.st_mode);
+		    }
+		  else
+		    {
+		      new->mode = stats.st_mode;
+		      new->mode_valid = false;
+		    }
+
+		  if ((stats.st_mode & S_IRWXU) != S_IRWXU)
+		    {
+		      /* Make the new directory searchable and writable. The
+			 original permissions will be restored later.  */
+
+		      new->mode_valid = true;
+
+		      if (chmod (dir, stats.st_mode | S_IRWXU))
+			{
+			  error (0, errno, _("setting permissions for %s"),
+				 quote (dir));
+			  return false;
+			}
+		    }
+		}
 	    }
 	  else if (!S_ISDIR (stats.st_mode))
 	    {
@@ -433,7 +496,7 @@
 	    }
 	  else
 	    {
-	      new->is_new_dir = false;
+	      new->mode_valid = false;
 	      *new_dst = false;
 	    }
 	  *slash++ = '/';
@@ -536,10 +599,6 @@
 	 Copy the files `file1' through `filen'
 	 to the existing directory `edir'. */
       int i;
-      int (*xstat)() = (x->dereference == DEREF_COMMAND_LINE_ARGUMENTS
-			|| x->dereference == DEREF_ALWAYS
-			? stat
-			: lstat);
 
       /* Initialize these hash tables only if we'll need them.
 	 The problems they're used to detect can arise only if
@@ -585,9 +644,9 @@
 	         leading directories. */
 	      parent_exists =
 		(make_dir_parents_private
-		 (dst_name, arg_in_concat - dst_name, S_IRWXU,
+		 (dst_name, arg_in_concat - dst_name,
 		  (x->verbose ? "%s -> %s\n" : NULL),
-		  &attr_list, &new_dst, xstat));
+		  &attr_list, &new_dst, x));
 	    }
 	  else
 	    {
@@ -697,16 +756,12 @@
   /* Not used.  */
   x->stdin_tty = false;
 
-  /* Find out the current file creation mask, to knock the right bits
-     when using chmod.  The creation mask is set to be liberal, so
-     that created directories can be written, even if it would not
-     have been allowed with the mask this process was started with.  */
-  x->umask_kill = ~ umask (0);
-
   x->update = false;
   x->verbose = false;
   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
@@ -894,6 +949,13 @@
 	  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;
@@ -987,9 +1049,6 @@
 				   version_control_string)
 		   : no_backups);
 
-  if (x.preserve_mode)
-    x.umask_kill = ~ (mode_t) 0;
-
   if (x.dereference == DEREF_UNDEFINED)
     {
       if (x.recursive)
--- coreutils-5.91/src/install.c
+++ coreutils-5.91/src/install.c
@@ -153,11 +153,12 @@
   x->mode = S_IRUSR | S_IWUSR;
   x->stdin_tty = false;
 
-  x->umask_kill = 0;
   x->update = false;
   x->verbose = false;
   x->dest_info = NULL;
   x->src_info = NULL;
+
+  x->attr_pattern = NULL;  /* no extended attributes */
 }
 
 /* FILE is the last operand of this command.  Return true if FILE is a
--- coreutils-5.91/src/ls.c
+++ coreutils-5.91/src/ls.c
@@ -193,13 +193,13 @@ struct fileinfo
 
     enum filetype filetype;
 
-#if HAVE_ACL
+#if USE_ACL
     /* For long listings, true if the file has an access control list.  */
     bool have_acl;
 #endif
   };
 
-#if HAVE_ACL
+#if USE_ACL
 # define FILE_HAS_ACL(F) ((F)->have_acl)
 #else
 # define FILE_HAS_ACL(F) 0
@@ -334,7 +334,7 @@ static int current_time_ns = -1;
 /* Whether any of the files has an ACL.  This affects the width of the
    mode column.  */
 
-#if HAVE_ACL
+#if USE_ACL
 static bool any_has_acl;
 #else
 enum { any_has_acl = false };
@@ -2469,7 +2469,7 @@ clear_files (void)
     }
 
   files_index = 0;
-#if HAVE_ACL
+#if USE_ACL
   any_has_acl = false;
 #endif
   inode_number_width = 0;
@@ -2580,7 +2580,7 @@ gobble_file (char const *name, enum file
 	  return 0;
 	}
 
-#if HAVE_ACL
+#if USE_ACL
       if (format == long_format)
 	{
 	  int n = file_has_acl (absolute_name, &f->stat);
--- coreutils-5.91/src/mv.c
+++ coreutils-5.91/src/mv.c
@@ -135,16 +135,12 @@
   x->mode = 0;
   x->stdin_tty = isatty (STDIN_FILENO);
 
-  /* Find out the current file creation mask, to knock the right bits
-     when using chmod.  The creation mask is set to be liberal, so
-     that created directories can be written, even if it would not
-     have been allowed with the mask this process was started with.  */
-  x->umask_kill = ~ umask (0);
-
   x->update = false;
   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
--- coreutils-5.91/m4/acl.m4
+++ coreutils-5.91/m4/acl.m4
@@ -14,5 +14,22 @@ AC_DEFUN([AC_FUNC_ACL],
 
   dnl Prerequisites of lib/acl.c.
   AC_CHECK_HEADERS(sys/acl.h)
+  if test "$ac_cv_header_sys_acl_h" = yes; then
+    use_acl=1
+  else
+    use_acl=0
+  fi
+  AC_DEFINE_UNQUOTED(USE_ACL, $use_acl,
+		     [Define if you want access control list support.])
   AC_CHECK_FUNCS(acl)
+  ac_save_LIBS="$LIBS"
+  AC_SEARCH_LIBS(acl_get_file, acl,
+  		 [test "$ac_cv_search_acl_get_file" = "none required" ||
+		  LIB_ACL=$ac_cv_search_acl_get_file])
+  AC_SUBST(LIB_ACL)
+  AC_CHECK_HEADERS(acl/libacl.h)
+  AC_CHECK_FUNCS(acl_get_file acl_set_file acl_free acl_to_text \
+		 acl_from_text acl_delete_def_file \
+		 acl_entries acl_extended_file)
+  LIBS="$ac_save_LIBS"
 ])
--- coreutils-5.91/src/Makefile.am
+++ coreutils-5.91/src/Makefile.am
@@ -92,6 +92,17 @@
 
 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_XATTR)
+mv_LDADD += $(LIB_XATTR)
+ginstall_LDADD += $(LIB_XATTR)
+
 $(PROGRAMS): ../lib/libcoreutils.a
 
 SUFFIXES = .sh
--- coreutils-5.91/configure.ac
+++ coreutils-5.91/configure.ac
@@ -248,6 +248,9 @@ AC_CHECK_DECLS([strtoimax, strtoumax])
 
 cu_LIB_CHECK
 
+# Extended attribute copying.
+AC_FUNC_XATTR
+
 AM_GNU_GETTEXT([external], [need-ngettext])
 AM_GNU_GETTEXT_VERSION(0.13.1)
 
--- coreutils-5.91/m4/xattr.m4
+++ coreutils-5.91/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
+])