|
|
# --- 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 (©_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 = ©_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) == 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
+])
|