# --- 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 #endif +#include #include #include #ifndef S_ISLNK # define S_ISLNK(Mode) 0 #endif +#include "error.h" +#include "quote.h" #include "acl.h" +#ifdef HAVE_ACL_LIBACL_H +# include +#endif + #include #ifndef ENOSYS # define ENOSYS (-1) #endif +#ifndef ENOTSUP +# define ENOTSUP (-1) +#endif + +#if ENABLE_NLS +# include +# 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 #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 +# include +# include +#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 +])