Hello,
[Resent to the list, too.]
[Jim: note that the version I've sent before made chmod_or_fchmod non-static;
the attached version fixes this, and otherwise is identical.]
here is a new version. I've merged the two patches; one without the other
isn't useful anyway, and I got in a mess splitting things cleanly between the
two. This now improves how autoconf's findings are used in acl.c, and cleans
up things a bit more. Big ChangeLog entry at the end.
What I'm puzzled by is the two lines that test for x->copy_as_regular in
copy_reg and copy_internal, and do the chmod depending on that. I don't see
what the intention of those is, and the semantics seem to be correct without
them. We may still need to add those checks back in though.
copy_reg:
(x->copy_as_regular || S_ISREG (src_sb->st_mode)
copy_internal:
(x->copy_as_regular || S_ISREG (src_type) || S_ISDIR (src_type))
The patch doesn't have copy_acl or set_acl support for Solaris and
Solaris-like systems. I can later send the code (in a second patch) if you
want, but I can't test it.
> mv-acl-test.diff
>
> A minor test case fix.
This one got lost: please apply.
Thanks,
Andreas.
--
Andreas Gruenbacher <[EMAIL PROTECTED]>
SUSE Labs, SUSE LINUX Products GmbH / Novell Inc.
Index: coreutils/tests/mv/acl
===================================================================
--- coreutils.orig/tests/mv/acl
+++ coreutils/tests/mv/acl
@@ -14,14 +14,15 @@ if test "$VERBOSE" = yes; then
setfacl --version
fi
+if test -z "$other_partition_tmpdir"; then
+ (exit 77); exit 77
+fi
+
pwd=`pwd`
t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
trap 'status=$?; cd $pwd; chmod -R u+rwx $t0; rm -rf $t0 && exit $status' 0
trap '(exit $?); exit $?' 1 2 13 15
-if test -z "$other_partition_tmpdir"; then
- (exit 77); exit 77
-fi
t0="$t0 $other_partition_tmpdir"
framework_failure=0
Index: coreutils/src/copy.c
===================================================================
--- coreutils.orig/src/copy.c
+++ coreutils/src/copy.c
@@ -30,6 +30,7 @@
#endif
#include "system.h"
+#include "acl.h"
#include "backupfile.h"
#include "buffer-lcm.h"
#include "copy.h"
@@ -52,9 +53,6 @@
#include "xreadlink.h"
#include "yesno.h"
-#ifndef HAVE_FCHMOD
-# define HAVE_FCHMOD false
-#endif
#ifndef HAVE_FCHOWN
# define HAVE_FCHOWN false
# define fchown(fd, uid, gid) (-1)
@@ -103,26 +101,6 @@ static char const *top_level_dst_name;
/* 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
@@ -201,23 +179,17 @@ copy_dir (char const *src_name_in, char
static bool
set_owner (const struct cp_options *x, char const *dst_name, int dest_desc,
- uid_t uid, gid_t gid, bool *chown_succeeded)
+ uid_t uid, gid_t gid)
{
if (HAVE_FCHOWN && dest_desc != -1)
{
if (fchown (dest_desc, uid, gid) == 0)
- {
- *chown_succeeded = true;
- return true;
- }
+ return true;
}
else
{
if (chown (dst_name, uid, gid) == 0)
- {
- *chown_succeeded = true;
- return true;
- }
+ return true;
}
if (! chown_failure_ok (x))
{
@@ -267,7 +239,6 @@ preserve_author (const char *dst_name, i
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)
{
char *buf;
@@ -527,8 +498,7 @@ copy_reg (char const *src_name, char con
if (x->preserve_ownership && ! SAME_OWNER_AND_GROUP (*src_sb, sb))
{
- if (! set_owner (x, dst_name, dest_desc, src_sb->st_uid, src_sb->st_gid,
- chown_succeeded))
+ if (! set_owner (x, dst_name, dest_desc, src_sb->st_uid, src_sb->st_gid))
{
return_val = false;
goto close_src_and_dst_desc;
@@ -537,25 +507,16 @@ copy_reg (char const *src_name, char con
preserve_author (dst_name, dest_desc, src_sb);
- /* 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 ((HAVE_FCHMOD
- ? fchmod (dest_desc, get_dest_mode (x, src_sb->st_mode))
- : chmod (dst_name, get_dest_mode (x, src_sb->st_mode))) == 0)
- goto close_src_and_dst_desc;
-
- 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;
- }
+ if (x->preserve_mode || x->move_mode)
+ {
+ if (copy_acl (src_name, source_desc, dst_name, dest_desc,
+ src_sb->st_mode) != 0 && x->require_preserve)
+ return_val = false;
+ }
+ else if (x->set_mode)
+ {
+ if (set_acl (dst_name, dest_desc, x->mode) != 0)
+ return_val = false;
}
close_src_and_dst_desc:
@@ -993,12 +954,13 @@ copy_internal (char const *src_name, cha
struct stat dst_sb;
mode_t src_mode;
mode_t src_type;
+ mode_t dst_mode IF_LINT (= 0);
+ bool restore_dst_mode = false;
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)
@@ -1514,22 +1476,42 @@ copy_internal (char const *src_name, cha
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) != 0)
+ {
+ 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. */
+
+ dst_mode = dst_sb.st_mode;
+ restore_dst_mode = true;
+
+ 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));
@@ -1606,16 +1588,14 @@ copy_internal (char const *src_name, cha
/* 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,
- &src_sb))
+ if (! copy_reg (src_name, dst_name, x, src_mode, &new_dst, &src_sb))
goto un_backup;
}
else
#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;
@@ -1626,7 +1606,7 @@ copy_internal (char const *src_name, cha
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));
@@ -1741,20 +1721,30 @@ copy_internal (char const *src_name, cha
if (x->preserve_ownership
&& (new_dst || !SAME_OWNER_AND_GROUP (src_sb, dst_sb)))
{
- if (! set_owner (x, dst_name, -1, src_sb.st_uid, src_sb.st_gid,
- &chown_succeeded))
+ if (! set_owner (x, dst_name, -1, src_sb.st_uid, src_sb.st_gid))
return false;
}
preserve_author (dst_name, -1, &src_sb);
- 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 (copy_acl (src_name, -1, dst_name, -1, src_mode) != 0
+ && x->require_preserve)
+ return false;
+ }
+ else if (x->set_mode)
{
- if (chmod (dst_name, get_dest_mode (x, src_mode)) != 0)
+ if (set_acl (dst_name, -1, x->mode) != 0)
+ return false;
+ }
+ else if (restore_dst_mode)
+ {
+ if (chmod (dst_name, dst_mode))
{
- error (0, errno, _("setting permissions for %s"), quote (dst_name));
- if (x->set_mode || x->require_preserve)
+ error (0, errno, _("preserving permissions for %s"),
+ quote (dst_name));
+ if (x->require_preserve)
return false;
}
}
Index: coreutils/doc/coreutils.texi
===================================================================
--- coreutils.orig/doc/coreutils.texi
+++ coreutils/doc/coreutils.texi
@@ -5688,9 +5688,14 @@ Otherwise.
@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
@@ -6527,7 +6532,7 @@ of one or more of the following strings:
@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
@@ -6543,7 +6548,6 @@ any links between corresponding source f
@itemx all
Preserve all file attributes.
Equivalent to specifying all of the above.
[EMAIL PROTECTED] Mention ACLs here.
@end table
Using @option{--preserve} with no @var{attribute_list} is equivalent
Index: coreutils/lib/acl.c
===================================================================
--- coreutils.orig/lib/acl.c
+++ coreutils/lib/acl.c
@@ -16,48 +16,394 @@
along with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- Written by Paul Eggert. */
+ Written by Paul Eggert and Andreas Gruenbacher. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef S_ISLNK
# define S_ISLNK(Mode) 0
#endif
+#ifdef HAVE_ACL_LIBACL_H
+# include <acl/libacl.h>
+#endif
+
#include "acl.h"
+#include "error.h"
+#include "quote.h"
#include <errno.h>
#ifndef ENOSYS
# define ENOSYS (-1)
#endif
+#ifndef ENOTSUP
+# define ENOTSUP (-1)
+#endif
-#ifndef MIN_ACL_ENTRIES
-# define MIN_ACL_ENTRIES 4
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+#else
+# define _(Text) Text
#endif
-/* Return 1 if FILE has a nontrivial access control list, 0 if not,
- and -1 (setting errno) if an error is encountered. */
+#ifndef HAVE_FCHMOD
+# define HAVE_FCHMOD false
+# define fchmod(fd, mode) (-1)
+#endif
+
+/* POSIX 1003.1e (draft 17) */
+#ifndef HAVE_ACL_GET_FD
+# define HAVE_ACL_GET_FD false
+# define acl_get_fd(fd) (NULL)
+#endif
+
+/* POSIX 1003.1e (draft 17) */
+#ifndef HAVE_ACL_SET_FD
+# define HAVE_ACL_SET_FD false
+# define acl_set_fd(fd, acl) (-1)
+#endif
+
+/* Linux-specific */
+#ifndef HAVE_ACL_EXTENDED_FILE
+# define HAVE_ACL_EXTENDED_FILE false
+# define acl_extended_file(name) (-1)
+#endif
+
+/* Linux-specific */
+#ifndef HAVE_ACL_FROM_MODE
+# define HAVE_ACL_FROM_MODE false
+# define acl_from_mode(mode) (NULL)
+#endif
+
+/* We detect presence of POSIX 1003.1e (draft 17 -- abandoned) support
+ by checking for HAVE_ACL_GET_FILE, HAVE_ACL_SET_FILE, and HAVE_ACL_FREE.
+ Systems that have acl_get_file, acl_set_file, and acl_free must also
+ have acl_to_text, acl_from_text, and acl_delete_def_file (all defined
+ in the draft); systems that don't would hit #error statements here. */
+
+#if USE_ACL && HAVE_ACL_GET_FILE && !HAVE_ACL_ENTRIES
+# ifndef HAVE_ACL_TO_TEXT
+# error Must have acl_to_text (see POSIX 1003.1e draft 17).
+# endif
+
+/* Return the number of entries in ACL. Linux implements acl_entries
+ as a more efficient extension than using this workaround. */
+
+static int
+acl_entries (acl_t acl)
+{
+ char *text = acl_to_text (acl, NULL), *t;
+ int entries;
+ if (text == NULL)
+ return -1;
+ for (entries = 0, t = text; ; t++, entries++) {
+ t = strchr (t, '\n');
+ if (t == NULL)
+ break;
+ }
+ acl_free (text);
+ return entries;
+}
+#endif
+
+/* If DESC is a valid file descriptor use fchmod to change the
+ file's mode to MODE on systems that have fchown. On systems
+ that don't have fchown and if DESC is invalid, use chown on
+ NAME instead. */
+
+static int
+chmod_or_fchmod (const char *name, int desc, mode_t mode)
+{
+ if (HAVE_FCHMOD && desc != -1)
+ return fchmod (desc, mode);
+ else
+ return chmod (name, mode);
+}
+
+/* Return 1 if NAME has a nontrivial access control list, 0 if
+ NAME only has no or a base access control list, and -1 on
+ error. SB must be set to the stat buffer of FILE. */
int
-file_has_acl (char const *file, struct stat const *filestat)
+file_has_acl (char const *name, struct stat const *sb)
{
- /* 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))
+# ifndef MIN_ACL_ENTRIES
+# define MIN_ACL_ENTRIES 4
+# endif
+
+ if (! S_ISLNK (sb->st_mode))
{
- int n = acl (file, GETACLCNT, 0, NULL);
+ int n = acl (name, GETACLCNT, 0, NULL);
return n < 0 ? (errno == ENOSYS ? 0 : -1) : (MIN_ACL_ENTRIES < n);
}
+#elif USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE
+ /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
+
+ if (! S_ISLNK (sb->st_mode))
+ {
+ int ret;
+
+ if (HAVE_ACL_EXTENDED_FILE)
+ ret = acl_extended_file (name);
+ else
+ {
+ acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS);
+ if (acl)
+ {
+ ret = (3 < acl_entries (acl));
+ acl_free (acl);
+ if (ret == 0 && S_ISDIR (sb->st_mode))
+ {
+ acl = acl_get_file (name, ACL_TYPE_DEFAULT);
+ if (acl)
+ {
+ ret = (0 < acl_entries (acl));
+ acl_free (acl);
+ }
+ else
+ ret = -1;
+ }
+ }
+ else
+ ret = -1;
+ }
+ if (ret < 0)
+ return (errno == ENOSYS || errno == ENOTSUP) ? 0 : -1;
+ return ret;
+ }
#endif
+ /* FIXME: Add support for AIX, Irix, and Tru64. Please see Samba's
+ source/lib/sysacls.c file for fix-related ideas. */
+
return 0;
}
+
+/* Copy access control lists from one file to another. If SOURCE_DESC is
+ a valid file descriptor, use file descriptor operations, else use
+ filename based operations on SRC_NAME. Likewise for DEST_DESC and
+ DEST_NAME.
+ If access control lists are not available, fchmod the target file to
+ MODE. Also sets the non-permission bits of the destination file
+ (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
+ System call return value semantics. */
+
+int
+copy_acl (const char *src_name, int source_desc, const char *dst_name,
+ int dest_desc, mode_t mode)
+{
+ int ret;
+
+#if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
+ /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */
+
+ acl_t acl;
+ if (HAVE_ACL_GET_FD && source_desc != -1)
+ acl = acl_get_fd (source_desc);
+ else
+ acl = acl_get_file (src_name, ACL_TYPE_ACCESS);
+ if (acl == NULL)
+ {
+ if (errno == ENOSYS || errno == ENOTSUP)
+ return set_acl (dst_name, dest_desc, mode);
+ else
+ {
+ error (0, errno, "%s", quote (src_name));
+ return -1;
+ }
+ }
+
+ if (HAVE_ACL_SET_FD && dest_desc != -1)
+ ret = acl_set_fd (dest_desc, acl);
+ else
+ ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl);
+ if (ret != 0)
+ {
+ int saved_errno = errno;
+
+ if (errno == ENOSYS || errno == ENOTSUP)
+ {
+ int n = acl_entries (acl);
+
+ acl_free (acl);
+ if (n == 3)
+ {
+ if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0)
+ saved_errno = errno;
+ else
+ return 0;
+ }
+ else
+ chmod_or_fchmod (dst_name, dest_desc, mode);
+ }
+ else
+ {
+ acl_free (acl);
+ chmod_or_fchmod (dst_name, dest_desc, mode);
+ }
+ error (0, saved_errno, _("preserving permissions for %s"),
+ quote (dst_name));
+ 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_or_fchmod (dst_name, dest_desc, mode) != 0)
+ {
+ error (0, errno, _("preserving permissions for %s"),
+ quote (dst_name));
+ return -1;
+ }
+ }
+
+ if (S_ISDIR (mode))
+ {
+ acl = acl_get_file (src_name, ACL_TYPE_DEFAULT);
+ if (acl == NULL)
+ {
+ error (0, errno, "%s", quote (src_name));
+ return -1;
+ }
+
+ if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl))
+ {
+ error (0, errno, _("preserving permissions for %s"),
+ quote (dst_name));
+ acl_free (acl);
+ return -1;
+ }
+ else
+ acl_free (acl);
+ }
+ return 0;
+#else
+ ret = chmod_or_fchmod (dst_name, dest_desc, mode);
+ if (ret != 0)
+ error (0, errno, _("preserving permissions for %s"), quote (dst_name));
+ return ret;
+#endif
+}
+
+/* Set the access control lists of a file. If DESC is a valid file
+ descriptor, use file descriptor operations where available, else use
+ filename based operations on NAME. If access control lists are not
+ available, fchmod the target file to MODE. Also sets the
+ non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX)
+ to those from MODE if any are set. System call return value
+ semantics. */
+
+int
+set_acl (char const *name, int desc, mode_t mode)
+{
+#if USE_ACL && HAVE_ACL_SET_FILE && HAVE_ACL_FREE
+ /* POSIX 1003.1e draft 17 (abandoned) specific version. */
+
+ /* We must also have have_acl_from_text and acl_delete_def_file.
+ (acl_delete_def_file could be emulated with acl_init followed
+ by acl_set_file, but acl_set_file with an empty acl is
+ unspecified.) */
+
+# ifndef HAVE_ACL_FROM_TEXT
+# error Must have acl_from_text (see POSIX 1003.1e draft 17).
+# endif
+# ifndef HAVE_ACL_DELETE_DEF_FILE
+# error Must have acl_delete_def_file (see POSIX 1003.1e draft 17).
+# endif
+
+ acl_t acl;
+ int ret;
+
+ if (HAVE_ACL_FROM_MODE)
+ {
+ acl = acl_from_mode (mode);
+ if (!acl)
+ {
+ error (0, errno, "%s", quote (name));
+ return -1;
+ }
+ }
+ else
+ {
+ char acl_text[] = "u::---,g::---,o::---";
+
+ 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 (name));
+ return -1;
+ }
+ }
+ if (HAVE_ACL_SET_FD && desc != -1)
+ ret = acl_set_fd (desc, acl);
+ else
+ ret = acl_set_file (name, ACL_TYPE_ACCESS, acl);
+ if (ret != 0)
+ {
+ int saved_errno = errno;
+ acl_free (acl);
+
+ if (errno == ENOTSUP || errno == ENOSYS)
+ {
+ if (chmod_or_fchmod (name, desc, mode) != 0)
+ saved_errno = errno;
+ else
+ return 0;
+ }
+ error (0, saved_errno, _("setting permissions for %s"), quote (name));
+ return -1;
+ }
+ else
+ acl_free (acl);
+
+ if (S_ISDIR (mode) && acl_delete_def_file (name))
+ {
+ error (0, errno, _("setting permissions for %s"), quote (name));
+ return -1;
+ }
+
+ 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_or_fchmod (name, desc, mode))
+ {
+ error (0, errno, _("preserving permissions for %s"), quote (name));
+ return -1;
+ }
+ }
+ return 0;
+#else
+ int ret = chmod_or_fchmod (name, desc, mode);
+ if (ret)
+ error (0, errno, _("setting permissions for %s"), quote (name));
+ return ret;
+#endif
+}
Index: coreutils/lib/acl.h
===================================================================
--- coreutils.orig/lib/acl.h
+++ coreutils/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 *, int, char const *, int, mode_t);
+int set_acl (char const *, int, mode_t);
Index: coreutils/src/copy.h
===================================================================
--- coreutils.orig/src/copy.h
+++ coreutils/src/copy.h
@@ -165,9 +165,6 @@ struct cp_options
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;
Index: coreutils/src/cp.c
===================================================================
--- coreutils.orig/src/cp.c
+++ coreutils/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 restore_mode;
size_t slash_offset;
struct dir_attr *next;
};
@@ -327,9 +329,14 @@ re_protect (char const *const_dst_name,
}
}
- if (x->preserve_mode | p->is_new_dir)
+ if (x->preserve_mode)
{
- if (chmod (dst_name, src_sb.st_mode & x->umask_kill))
+ if (copy_acl (src_name, -1, dst_name, -1, src_sb.st_mode))
+ return false;
+ }
+ else if (p->restore_mode)
+ {
+ if (chmod (dst_name, p->mode))
{
error (0, errno, _("failed to preserve permissions for %s"),
quote (dst_name));
@@ -347,8 +354,7 @@ re_protect (char const *const_dst_name,
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 +370,9 @@ re_protect (char const *const_dst_name,
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 +391,7 @@ make_dir_parents_private (char const *co
*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. */
@@ -400,20 +406,30 @@ make_dir_parents_private (char const *co
fixing later. */
struct dir_attr *new = xmalloc (sizeof *new);
new->slash_offset = slash - dir;
+ new->restore_mode = false;
new->next = *attr_list;
*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 +440,41 @@ make_dir_parents_private (char const *co
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->restore_mode = (src_mode != stats.st_mode);
+ }
+
+ if ((stats.st_mode & S_IRWXU) != S_IRWXU)
+ {
+ /* Make the new directory searchable and writable. The
+ original permissions will be restored later. */
+
+ new->mode = stats.st_mode;
+ new->restore_mode = 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))
{
@@ -432,10 +483,7 @@ make_dir_parents_private (char const *co
return false;
}
else
- {
- new->is_new_dir = false;
- *new_dst = false;
- }
+ *new_dst = false;
*slash++ = '/';
/* Avoid unnecessary calls to `stat' when given
@@ -536,10 +584,6 @@ do_copy (int n_files, char **file, const
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 +629,9 @@ do_copy (int n_files, char **file, const
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,12 +741,6 @@ cp_option_init (struct cp_options *x)
/* 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;
@@ -987,9 +1025,6 @@ main (int argc, char **argv)
version_control_string)
: no_backups);
- if (x.preserve_mode)
- x.umask_kill = ~ (mode_t) 0;
-
if (x.dereference == DEREF_UNDEFINED)
{
if (x.recursive)
Index: coreutils/src/install.c
===================================================================
--- coreutils.orig/src/install.c
+++ coreutils/src/install.c
@@ -153,7 +153,6 @@ cp_option_init (struct cp_options *x)
x->mode = S_IRUSR | S_IWUSR;
x->stdin_tty = false;
- x->umask_kill = 0;
x->update = false;
x->verbose = false;
x->dest_info = NULL;
Index: coreutils/src/ls.c
===================================================================
--- coreutils.orig/src/ls.c
+++ coreutils/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 };
@@ -2477,7 +2477,7 @@ clear_files (void)
}
files_index = 0;
-#if HAVE_ACL
+#if USE_ACL
any_has_acl = false;
#endif
inode_number_width = 0;
@@ -2588,7 +2588,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);
Index: coreutils/src/mv.c
===================================================================
--- coreutils.orig/src/mv.c
+++ coreutils/src/mv.c
@@ -134,12 +134,6 @@ cp_option_init (struct cp_options *x)
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;
Index: coreutils/m4/acl.m4
===================================================================
--- coreutils.orig/m4/acl.m4
+++ coreutils/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_get_fd acl_set_file acl_set_fd \
+ acl_free acl_from_mode acl_from_text acl_to_text \
+ acl_delete_def_file acl_entries acl_extended_file)
+ LIBS="$ac_save_LIBS"
])
Index: coreutils/src/Makefile.am
===================================================================
--- coreutils.orig/src/Makefile.am
+++ coreutils/src/Makefile.am
@@ -93,6 +93,13 @@ uptime_LDADD = $(LDADD) $(GETLOADAVG_LIB
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)
+
$(PROGRAMS): ../lib/libcoreutils.a
SUFFIXES = .sh
Index: coreutils/ChangeLog
===================================================================
--- coreutils.orig/ChangeLog
+++ coreutils/ChangeLog
@@ -1,4 +1,42 @@
-2005-12-05 Andreas Gruenbacher
+2005-12-05 Andreas Gruenbacher <[EMAIL PROTECTED]>
+
+ * lib/acl.h: Fix for POSIX ACLs.
+ * lib/acl.h (copy_acl, set_acl): Add declarations.
+ * lib/acl.c (acl_entries): Add fallback implementation for POSIX ACL
+ systems other than Linux.
+ * lib/acl.c (chmod_or_fchmod): Add function that does fchmod when
+ possible and chmod otherwise.
+ * lib/acl.c (file_has_acl): Add a POSIX ACL implementation, with a
+ Linux-specific subcase.
+ * lib/acl.c (copy_acl): Add: copy an acl and S_ISUID, S_ISGID, and
+ S_ISVTX from one file to another. Fall back to fchmod/chmod when
+ acls are unsupported.
+ * lib/acl.c (set_acl): Add: set a file's acl and S_ISUID, S_ISGID, and
+ S_ISVTX to a defined value. Fall back to fchmod/chmod when acls
+ are unsupported.
+ * src/ls.c: Switch back from HAVE_ACL to USE_ACL: The acl() syscall
+ is no requirement for ACL support; particularly, it does not exist
+ on systems that have POSIX ACLs.
+ * src/cp.c, src/mv.c, src/install.c (umask_kill): With default acls,
+ the umask is not to be applied. Remove umask_kill, don't change the
+ process umask, and let the kernel apply the umask where appropriate.
+ * src/cp.c (make_path_private): Fix logic for POSIX ACLs.
+ * src/copy.c (get_dest_mode): Remove; it is obsolete after removing
+ umask_kill.
+ * src/copy.c (copy_reg, copy_internal): Use copy_acl and set_acl
+ instead of fchown/chown. Fix the logic for POSIX ACLs.
+ * src/copy.c (chown_succeded): Remove; we now always copy acls and
+ preserve S_ISUID, S_ISGID, and S_ISVTX when needed, no matter if we
+ did a chown before or not.
+ * doc/coreutils.texi (ls): Clarify the Alternate Access Method
+ description.
+ * doc/coreutils.texi (cp): Clarify that --preserve=mode also preserves
+ acls.
+ * src/Makefile.am: On systems that have one, add the acl library to
+ *_LDADD for the utilities that need it.
+ * m4/acl.m4: Add POSIX ACL and Linux-specific acl tests.
+
+2005-12-05 Andreas Gruenbacher <[EMAIL PROTECTED]>
* Version 6.0-cvs.
_______________________________________________
Bug-coreutils mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/bug-coreutils