--- /dev/null 2004-02-23 21:02:56.000000000 +0000 +++ coreutils-5.2.1/m4/posix_acl.m4 2004-03-13 11:50:03.000000000 +0000 @@ -0,0 +1,28 @@ +#serial 1 + +dnl Written by Andreas Gruenbacher . + +dnl Posix 1003.1e draft standard 17 (abandoned) and similar +dnl access control list support +AC_DEFUN([ag_POSIX_ACL], +[ + AC_CHECK_HEADERS(sys/acl.h) + AC_CHECK_LIB(acl, main, cu_cv_lacl=yes, cu_cv_lacl=no) + if test "$cu_cv_lacl" = yes; then + LIBACL=-lacl + else + LIBACL= + fi + AC_SUBST(LIBACL) + OLDLIBS="$LIBS" + LIBS="$LIBS $LIBACL" + AC_CHECK_FUNCS(acl_get_file acl_set_file acl_free acl_to_text \ + acl_from_text acl_delete_def_file) + # Linux specific extensions: + AC_CHECK_FUNCS(acl_entries acl_extended_file) + LIBS="$OLDLIBS" + + if test $ac_cv_header_sys_acl_h = yes; then + AC_DEFINE(USE_ACL, 1, [Define if you want access control list support.]) + fi +]) --- coreutils-5.2.1/m4/Makefile.am.acl 2004-03-08 09:56:31.000000000 +0000 +++ coreutils-5.2.1/m4/Makefile.am 2004-03-13 11:50:03.000000000 +0000 @@ -108,6 +108,7 @@ EXTRA_DIST += path-concat.m4 EXTRA_DIST += pathmax.m4 EXTRA_DIST += perl.m4 +EXTRA_DIST += posix_acl.m4 EXTRA_DIST += physmem.m4 EXTRA_DIST += po.m4 EXTRA_DIST += posixtm.m4 --- coreutils-5.2.1/lib/acl.h.acl 2004-02-02 08:13:21.000000000 +0000 +++ coreutils-5.2.1/lib/acl.h 2004-03-13 11:50:03.000000000 +0000 @@ -18,11 +18,16 @@ Written by Paul Eggert. */ -#if HAVE_SYS_ACL_H && HAVE_ACL +#if HAVE_SYS_ACL_H # include #endif +#if HAVE_SYS_TYPES_H +# include +#endif #if ! 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.2.1/lib/acl.c.acl 2004-02-02 08:13:21.000000000 +0000 +++ coreutils-5.2.1/lib/acl.c 2004-03-13 11:50:03.000000000 +0000 @@ -22,18 +22,30 @@ # include #endif +#if ENABLE_NLS +# include +# define _(Text) gettext (Text) +#else +# define _(Text) Text +#endif + #include #include #ifndef S_ISLNK # define S_ISLNK(Mode) 0 #endif +#include + #include "acl.h" #include #ifndef ENOSYS # define ENOSYS (-1) #endif +#ifndef ENOTSUP +# define ENOTSUP (-1) +#endif #ifndef MIN_ACL_ENTRIES # define MIN_ACL_ENTRIES 4 @@ -45,19 +57,201 @@ int file_has_acl (char const *path, struct stat const *pathstat) { - /* 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 HAVE_ACL && defined GETACLCNT + /* This implementation should work on recent-enough versions of HP-UX, + Solaris, and Unixware. */ + if (! S_ISLNK (pathstat->st_mode)) { int n = acl (path, GETACLCNT, 0, NULL); return n < 0 ? (errno == ENOSYS ? 0 : -1) : (MIN_ACL_ENTRIES < n); } +#elif HAVE_ACL_EXTENDED_FILE + + /* Linux specific. */ + + if (! S_ISLNK (pathstat->st_mode)) + { + int ret = acl_extended_file (path); + if (ret < 0) + return (errno == ENOSYS || errno == ENOTSUP) ? 0 : -1; + return ret; + } +#else + /* FIXME: Add support for AIX, Irix, and Tru64, FreeBSD, etc. + Please see Samba's source/lib/sysacls.c file for fix-related ideas. */ #endif return 0; } + +/* Copy the permissions from SRC_PATH to DST_PATH, including access control + lists on systems where this is supported. MODE is the file mode for + DST_PATH, including the file type. + Also sets special bits in MODE on DST_PATH. */ + +int +copy_acl (char const *src_path, char const *dst_path, mode_t mode) +{ +#if 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) + compliant systems if the acl_entries() function is implemented. */ + + acl_t acl = acl_get_file (src_path, ACL_TYPE_ACCESS); + if (acl == NULL) + { + if (errno == ENOSYS || errno == ENOTSUP) + return set_acl (dst_path, mode); + else + { + error (0, errno, "%s", quote (src_path)); + return -1; + } + } + + if (acl_set_file (dst_path, 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_path, mode)) + saved_errno = errno; + else + return 0; + } + else + chmod (dst_path, mode); + } + else + { + acl_free (acl); + chmod (dst_path, mode); + } + error (0, saved_errno, _("preserving permissions for %s"), + quote (dst_path)); + return -1; + } + 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_path, mode)) + { + error (0, errno, _("preserving permissions for %s"), + quote (dst_path)); + return -1; + } + } + + if (S_ISDIR (mode)) + { + acl = acl_get_file (src_path, ACL_TYPE_DEFAULT); + if (acl == NULL) + { + error (0, errno, "%s", quote (src_path)); + return -1; + } + + if (acl_set_file (dst_path, ACL_TYPE_DEFAULT, acl)) + { + error (0, errno, _("preserving permissions for %s"), + quote (dst_path)); + acl_free(acl); + return -1; + } + else + acl_free(acl); + } + return 0; +#else + int ret = chmod (dst_path, mode); + if (ret) + error (0, errno, _("preserving permissions for %s"), quote (dst_path)); + return ret; +#endif +} + +/* Set the permissions of PATH, overwriting access control lists, on systems + where this is supported. MODE is the file mode for PATH, including the + file type. Also sets special bits in MODE on PATH. */ + +int +set_acl (char const *path, mode_t mode) +{ +#if HAVE_ACL_FROM_TEXT && HAVE_ACL_SET_FILE && HAVE_ACL_FREE && \ + HAVE_ACL_DELETE_DEF_FILE + 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; + } + 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.2.1/src/mv.c.acl 2004-02-07 15:41:02.000000000 +0000 +++ coreutils-5.2.1/src/mv.c 2004-03-13 11:50:03.000000000 +0000 @@ -132,12 +132,6 @@ 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 = 0; x->verbose = 0; x->dest_info = NULL; --- coreutils-5.2.1/src/ls.c.acl 2004-03-13 11:50:03.000000000 +0000 +++ coreutils-5.2.1/src/ls.c 2004-03-13 11:50:03.000000000 +0000 @@ -188,13 +188,13 @@ enum filetype filetype; -#if HAVE_ACL +#if HAVE_ACL || USE_ACL /* For long listings, true if the file has an access control list. */ bool have_acl; #endif }; -#if HAVE_ACL +#if HAVE_ACL || USE_ACL # define FILE_HAS_ACL(F) ((F)->have_acl) #else # define FILE_HAS_ACL(F) 0 @@ -2409,7 +2409,7 @@ return 0; } -#if HAVE_ACL +#if HAVE_ACL || USE_ACL if (format == long_format) { int n = file_has_acl (path, &f->stat); --- coreutils-5.2.1/src/install.c.acl 2004-03-13 11:50:03.000000000 +0000 +++ coreutils-5.2.1/src/install.c 2004-03-13 11:50:03.000000000 +0000 @@ -242,7 +242,6 @@ x->mode = S_IRUSR | S_IWUSR; x->stdin_tty = 0; - x->umask_kill = 0; x->update = 0; x->verbose = 0; x->dest_info = NULL; --- coreutils-5.2.1/src/cp.c.acl 2004-02-07 15:55:09.000000000 +0000 +++ coreutils-5.2.1/src/cp.c 2004-03-13 11:50:03.000000000 +0000 @@ -58,7 +58,8 @@ need to be fixed after copying. */ struct dir_attr { - int is_new_dir; + int mode_valid; + mode_t mode; int slash_offset; struct dir_attr *next; }; @@ -333,9 +334,14 @@ } } - if (x->preserve_mode || p->is_new_dir) - { - if (chmod (dst_path, src_sb.st_mode & x->umask_kill)) + if (x->preserve_mode) + { + if (copy_acl (src_path, dst_path, src_sb.st_mode)) + return 1; + } + else if (p->mode_valid) + { + if (chmod (dst_path, p->mode)) { error (0, errno, _("failed to preserve permissions for %s"), quote (dst_path)); @@ -353,8 +359,7 @@ SRC_OFFSET is the index in CONST_DIRPATH (which is a destination path) 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 @@ -369,15 +374,20 @@ /* FIXME: find a way to synch this function with the one in lib/makepath.c. */ static int -make_path_private (const char *const_dirpath, int src_offset, int mode, +make_path_private (const char *const_dirpath, int src_offset, const char *verbose_fmt_string, struct dir_attr **attr_list, - int *new_dst, int (*xstat)()) + int *new_dst, const struct cp_options *x) { struct stat stats; char *dirpath; /* A copy of CONST_DIRPATH we can change. */ char *src; /* Source name in `dirpath'. */ char *dst_dirname; /* Leading path of `dirpath'. */ size_t dirlen; /* Length of leading path of `dirpath'. */ + mode_t mode; + int (*xstat)() = (x->dereference == DEREF_COMMAND_LINE_ARGUMENTS + || x->dereference == DEREF_ALWAYS + ? stat + : lstat); ASSIGN_STRDUPA (dirpath, const_dirpath); @@ -412,12 +422,20 @@ if ((*xstat) (dirpath, &stats)) { /* This element of the path does not exist. We must set - *new_dst and new->is_new_dir inside this loop because, + *new_dst inside this loop because, for example, in the command `cp --parents ../a/../b/c e_dir', make_path_private creates only e_dir/../a if ./b already exists. */ *new_dst = 1; - new->is_new_dir = 1; + + if ((*xstat) (src, &stats)) + { + error (0, errno, _("failed to get attributes of %s"), + quote (src)); + return 1; + } + mode = stats.st_mode; + if (mkdir (dirpath, mode)) { error (0, errno, _("cannot make directory %s"), @@ -429,6 +447,46 @@ if (verbose_fmt_string != NULL) printf (verbose_fmt_string, src, dirpath); } + + /* We need search and write permissions to the new directory + for adding the directory's contents. Check if these + permissions are already there. */ + + if (lstat (dirpath, &stats)) + { + error (0, errno, _("failed to get attributes of %s"), + quote (dirpath)); + return 1; + } + else + { + if (x->preserve_mode && mode != stats.st_mode) + { + new->mode = mode; + new->mode_valid = 1; + } + else + new->mode_valid = 0; + + if ((stats.st_mode & S_IRWXU) != S_IRWXU) + { + /* Make the new directory writable and searchable. The + original permissions will be restored later. */ + + if (!new->mode_valid) + { + new->mode = stats.st_mode; + new->mode_valid = 1; + } + + if (chmod (dirpath, stats.st_mode | S_IRWXU)) + { + error (0, errno, _("setting permissions for %s"), + quote (dirpath)); + return 1; + } + } + } } else if (!S_ISDIR (stats.st_mode)) { @@ -438,7 +496,7 @@ } else { - new->is_new_dir = 0; + new->mode_valid = 0; *new_dst = 0; } *slash++ = '/'; @@ -552,10 +610,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); for (i = 0; i < n_files; i++) { @@ -593,11 +647,9 @@ leading directories. */ parent_exists = !make_path_private (dst_path, arg_in_concat - dst_path, - S_IRWXU, (x->verbose ? "%s -> %s\n" : NULL), - &attr_list, &new_dst, - xstat); + &attr_list, &new_dst, x); } else { @@ -731,12 +783,6 @@ /* Not used. */ x->stdin_tty = 0; - /* 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 = 0; x->verbose = 0; x->dest_info = NULL; @@ -1011,9 +1057,6 @@ version_control_string) : none); - if (x.preserve_mode == 1) - x.umask_kill = ~ (mode_t) 0; - if (x.dereference == DEREF_UNDEFINED) { if (x.recursive) --- coreutils-5.2.1/src/copy.h.acl 2004-02-07 16:00:59.000000000 +0000 +++ coreutils-5.2.1/src/copy.h 2004-03-13 11:50:03.000000000 +0000 @@ -143,9 +143,6 @@ Create destination directories as usual. */ int symbolic_link; - /* The bits to preserve in created files' modes. */ - mode_t umask_kill; - /* If nonzero, do not copy a nondirectory that has an existing destination with the same or newer modification time. */ int update; --- coreutils-5.2.1/src/copy.c.acl 2004-03-12 11:48:59.000000000 +0000 +++ coreutils-5.2.1/src/copy.c 2004-03-13 11:50:43.000000000 +0000 @@ -95,26 +95,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 @@ -817,13 +797,13 @@ struct stat src_sb; struct stat dst_sb; mode_t src_mode; - mode_t src_type; + mode_t dst_mode; char *earlier_file = NULL; char *dst_backup = NULL; int backup_succeeded = 0; int delayed_fail; int copied_as_regular = 0; - int ran_chown = 0; + int dst_mode_valid = 0; int preserve_metadata; if (x->move_mode && rename_succeeded) @@ -837,11 +817,9 @@ return 1; } - src_type = src_sb.st_mode; - src_mode = src_sb.st_mode; - if (S_ISDIR (src_type) && !x->recursive) + if (S_ISDIR (src_mode) && !x->recursive) { error (0, 0, _("omitting directory %s"), quote (src_path)); return 1; @@ -909,7 +887,7 @@ if (!S_ISDIR (dst_sb.st_mode)) { - if (S_ISDIR (src_type)) + if (S_ISDIR (src_mode)) { error (0, 0, _("cannot overwrite non-directory %s with directory %s"), @@ -935,7 +913,7 @@ } } - if (!S_ISDIR (src_type)) + if (!S_ISDIR (src_mode)) { if (S_ISDIR (dst_sb.st_mode)) { @@ -963,7 +941,7 @@ This may be due to an interactive `negative' reply to the prompt about the existing file. It may also be due to the use of the --reply=no option. */ - if (!S_ISDIR (src_type)) + if (!S_ISDIR (src_mode)) { /* cp and mv treat -i and -f differently. */ if (x->move_mode) @@ -1084,7 +1062,7 @@ /* If the source is a directory, we don't always create the destination directory. So --verbose should not announce anything until we're sure we'll create a directory. */ - if (x->verbose && !S_ISDIR (src_type)) + if (x->verbose && !S_ISDIR (src_mode)) { printf ("%s -> %s", quote_n (0, src_path), quote_n (1, dst_path)); if (backup_succeeded) @@ -1132,7 +1110,7 @@ || (command_line_arg && x->dereference == DEREF_COMMAND_LINE_ARGUMENTS) || x->dereference == DEREF_ALWAYS)) - || (x->recursive && S_ISDIR (src_type))) + || (x->recursive && S_ISDIR (src_mode))) { earlier_file = remember_copied (dst_path, src_sb.st_ino, src_sb.st_dev); } @@ -1145,7 +1123,7 @@ /* Avoid damaging the destination filesystem by refusing to preserve hard-linked directories (which are found at least in Netapp snapshot directories). */ - if (S_ISDIR (src_type)) + if (S_ISDIR (src_mode)) { /* If src_path and earlier_file refer to the same directory entry, then warn about copying a directory into itself. */ @@ -1197,7 +1175,7 @@ { if (rename (src_path, dst_path) == 0) { - if (x->verbose && S_ISDIR (src_type)) + if (x->verbose && S_ISDIR (src_mode)) printf ("%s -> %s\n", quote_n (0, src_path), quote_n (1, dst_path)); if (rename_succeeded) *rename_succeeded = 1; @@ -1310,7 +1288,7 @@ In such cases, set this variable to zero. */ preserve_metadata = 1; - if (S_ISDIR (src_type)) + if (S_ISDIR (src_mode)) { struct dir_list *dir; @@ -1335,16 +1313,38 @@ 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_path, (src_mode & x->umask_kill) | S_IRWXU)) + if (mkdir (dst_path, src_mode)) { error (0, errno, _("cannot create directory %s"), quote (dst_path)); goto un_backup; } + /* We need search and write permissions to the new directory + for adding the directory's contents. Check if these permissions + are already there. */ + + if (lstat (dst_path, &dst_sb)) + { + error (0, errno, _("cannot stat %s"), quote (dst_path)); + delayed_fail = 1; + } + else if ((dst_sb.st_mode & S_IRWXU) != S_IRWXU) + { + /* Make the new directory writable and searchable. The original + permissions will be restored later. */ + + dst_mode_valid = 1; + dst_mode = dst_sb.st_mode; + + if (chmod (dst_path, dst_mode | S_IRWXU)) + { + error (0, errno, _("setting permissions for %s"), + quote (dst_path)); + goto un_backup; + } + } + /* Insert the created directory's inode and device numbers into the search structure, so that we can avoid copying it again. */ @@ -1420,23 +1420,22 @@ goto un_backup; } } - else if (S_ISREG (src_type) - || (x->copy_as_regular && !S_ISDIR (src_type) - && !S_ISLNK (src_type))) + else if (S_ISREG (src_mode) + || (x->copy_as_regular && !S_ISDIR (src_mode) + && !S_ISLNK (src_mode))) { copied_as_regular = 1; /* 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_path, dst_path, x, - get_dest_mode (x, src_mode), &new_dst, &src_sb)) + if (copy_reg (src_path, dst_path, x, src_mode, &new_dst, &src_sb)) goto un_backup; } else #ifdef S_ISFIFO - if (S_ISFIFO (src_type)) + if (S_ISFIFO (src_mode)) { - if (mkfifo (dst_path, get_dest_mode (x, src_mode))) + if (mkfifo (dst_path, src_mode)) { error (0, errno, _("cannot create fifo %s"), quote (dst_path)); goto un_backup; @@ -1444,10 +1443,10 @@ } else #endif - if (S_ISBLK (src_type) || S_ISCHR (src_type) - || S_ISSOCK (src_type)) + if (S_ISBLK (src_mode) || S_ISCHR (src_mode) + || S_ISSOCK (src_mode)) { - if (mknod (dst_path, get_dest_mode (x, src_mode), src_sb.st_rdev)) + if (mknod (dst_path, src_mode, src_sb.st_rdev)) { error (0, errno, _("cannot create special file %s"), quote (dst_path)); @@ -1456,7 +1455,7 @@ } else #ifdef S_ISLNK - if (S_ISLNK (src_type)) + if (S_ISLNK (src_mode)) { char *src_link_val = xreadlink (src_path); if (src_link_val == NULL) @@ -1560,7 +1559,25 @@ if (x->preserve_ownership && (new_dst || !SAME_OWNER_AND_GROUP (src_sb, dst_sb))) { - ran_chown = 1; + /* The chown() system call may clear the SUID and SGID bits, so we + need to set them again later. (But we don't care if we will + overwrite the permissions of the destination file anyway.) */ + + if ((src_mode & (S_ISUID | S_ISGID)) + && !x->preserve_mode && !x->move_mode && !x->set_mode) + { + if (lstat (dst_path, &dst_sb)) + { + error (0, errno, _("cannot stat %s"), quote (dst_path)); + delayed_fail = 1; + } + else + { + dst_mode_valid = 1; + dst_mode = dst_sb.st_mode; + } + } + if (DO_CHOWN (chown, dst_path, src_sb.st_uid, src_sb.st_gid)) { error (0, errno, _("failed to preserve ownership for %s"), @@ -1587,20 +1604,23 @@ } #endif - /* Permissions of newly-created regular files were set upon `open' in - copy_reg. But don't return early if there were any special bits and - we had to run chown, because the chown must have reset those bits. */ - if ((new_dst && copied_as_regular) - && !(ran_chown && (src_mode & ~S_IRWXUGO))) - return delayed_fail; - - 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_path, get_dest_mode (x, src_mode))) - { - error (0, errno, _("setting permissions for %s"), quote (dst_path)); - if (x->set_mode || x->require_preserve) + if (copy_acl (src_path, dst_path, src_mode) && x->require_preserve) + return 1; + } + else if (x->set_mode) + { + if (set_acl (dst_path, x->mode) && x->require_preserve) + return 1; + } + else if (dst_mode_valid) + { + if (chmod (dst_path, dst_mode)) + { + error (0, errno, _("preserving permissions for %s"), + quote (dst_path)); + if (x->require_preserve) return 1; } } --- coreutils-5.2.1/src/Makefile.am.acl 2004-02-02 08:12:57.000000000 +0000 +++ coreutils-5.2.1/src/Makefile.am 2004-03-13 11:50:03.000000000 +0000 @@ -32,10 +32,13 @@ # replacement functions defined in libfetish.a. LDADD = ../lib/libfetish.a $(LIBINTL) ../lib/libfetish.a -dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) -ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) +dir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) @LIBACL@ +ls_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) @LIBACL@ shred_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) -vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) +vdir_LDADD = $(LDADD) $(LIB_CLOCK_GETTIME) @LIBACL@ +cp_LDADD = $(LDADD) @LIBACL@ +ginstall_LDADD = $(LDADD) @LIBACL@ +mv_LDADD = $(LDADD) @LIBACL@ ## If necessary, add -lm to resolve use of pow in lib/strtod.c. sort_LDADD = $(LDADD) $(POW_LIB) --- coreutils-5.2.1/configure.ac.acl 2004-03-02 22:47:31.000000000 +0000 +++ coreutils-5.2.1/configure.ac 2004-03-13 11:50:03.000000000 +0000 @@ -16,6 +16,9 @@ AC_PROG_RANLIB AC_PROG_LN_S AC_CANONICAL_HOST +AM_C_PROTOTYPES +AC_PROG_YACC +AC_SUBST(YACC) AC_CHECK_FUNCS(uname, @@ -235,6 +238,8 @@ AM_GNU_GETTEXT([external], [need-ngettext]) AM_GNU_GETTEXT_VERSION(0.13.1) +ag_POSIX_ACL + AC_CONFIG_FILES( Makefile doc/Makefile --- coreutils-5.2.1/config.hin.acl 2004-03-11 08:59:16.000000000 +0000 +++ coreutils-5.2.1/config.hin 2004-03-13 11:50:03.000000000 +0000 @@ -96,6 +96,30 @@ /* Define to 1 if you have the `acl' function. */ #undef HAVE_ACL +/* Define to 1 if you have the `acl_delete_def_file' function. */ +#undef HAVE_ACL_DELETE_DEF_FILE + +/* Define to 1 if you have the `acl_entries' function. */ +#undef HAVE_ACL_ENTRIES + +/* Define to 1 if you have the `acl_extended_file' function. */ +#undef HAVE_ACL_EXTENDED_FILE + +/* Define to 1 if you have the `acl_free' function. */ +#undef HAVE_ACL_FREE + +/* Define to 1 if you have the `acl_from_text' function. */ +#undef HAVE_ACL_FROM_TEXT + +/* Define to 1 if you have the `acl_get_file' function. */ +#undef HAVE_ACL_GET_FILE + +/* Define to 1 if you have the `acl_set_file' function. */ +#undef HAVE_ACL_SET_FILE + +/* Define to 1 if you have the `acl_to_text' function. */ +#undef HAVE_ACL_TO_TEXT + /* Define to 1 if you have the `alarm' function. */ #undef HAVE_ALARM @@ -489,6 +513,9 @@ /* Define to 1 if you have the `lchown' function. */ #undef HAVE_LCHOWN +/* Define to 1 if you have the `acl' library (-lacl). */ +#undef HAVE_LIBACL + /* Define to 1 if you have the `dgc' library (-ldgc). */ #undef HAVE_LIBDGC @@ -1335,6 +1362,9 @@ . */ #undef UMAX4_3 +/* Define if you want access control list support. */ +#undef USE_ACL + /* Version number of package */ #undef VERSION --- coreutils-5.2.1/NEWS.acl 2004-03-12 19:04:30.000000000 +0000 +++ coreutils-5.2.1/NEWS 2004-03-13 11:50:03.000000000 +0000 @@ -1,3 +1,6 @@ +[4.5.3acl] +* ACL framework and Linux ACL support. +* `cp -p' and `mv' now preserve ACLs GNU coreutils NEWS -*- outline -*- * Major changes in release 5.2.1 (2004-03-12) [stable] --- coreutils-5.2.1/ChangeLog.acl 2004-03-12 19:03:44.000000000 +0000 +++ coreutils-5.2.1/ChangeLog 2004-03-13 11:50:03.000000000 +0000 @@ -0,0 +1,45 @@ +2002-07-01 Bernhard Rosenkraenzer + * Port the following patch to 4.1.9: + +2002-04-10 Andreas Gruenbacher + + * Version 4.1.8acl. + + * src/copy.c (get_dest_mode): Remove. + * src/copy.c (copy_internal): Merge src_mode and src_type. + * src/copy.c (copy_internal): Add dst_mode and dst_mode_valid, + which are set when the destination file mode is changed temporarily. + * src/copy.c (copy_internal): Check effective permissions after + mkdir(). Add S_IRWXU only after saving the default permissions, so + the default permissions can be restored. This is needed with + default ACLs on some systems. + * src/copy.c (copy_internal): Use dst_mode and dst_mode_valid for + ran_chown. Save the current permissions if needed before chown(). + * src/copy.c (copy_internal): Clean up the final permission setting + code and prepare for copy/set ACL support. + * src/cp.c, src/install.c, src/mv.c, src/copy.h: Remove umask_kill, + and never change the startup umask. The functions creating files need + the original umask to be active to create the correct permissions + inside directories with default ACLs; umask_kill no longer works. + * src/cp.c (struct dir_attr, re_protect, make_path_private): Remove + is_new_dir and add mode and mode_valid instead. + * src/cp.c (make_path_private): Remove the mode parameter. Pass in + cp_options, instead of cp_options->xstat only. Stat the source dir, + and create the destination dir with the source dir's mode as create + mode (see analog change to src/copy.c (copy_internal)). Check if the + effective permissions include S_IRWXU. Remember the original code only + if needed later. + * lib/acl.h, lib/acl.c (copy_acl, set_acl): Add these functions, + initially with the bare non-ACL functionality. + * src/copy.c (copy_internal): Use copy_acl and set_acl instead of chmod. + * src/cp.c (re_protect): Use copy_acl instead of chmod. + * m4/posix_acl.m4, configure.ac (ag_POSIX_ACL): Add POSIX ACL tests. + * lib/acl.h: Remove HAVE_ACL symbol; is needed for POSIX + ACLs even if there is no acl system call. + * lib/acl.c (ENOTSUP): Provide default value. + * lib/acl.c (file_has_acl, copy_acl, set_acl): Add Linux ACL + implementations. + * src/ls.c: change `HAVE_ACL' to `HAVE_ACL || USE_ACL' for POSIX ACLs: + there is no acl system call for POSIX ACLs. + * tests/misc: Add my own small test suite so it doesn't get lost. + diff -urN coreutils-4.5.10.org/tests/misc/README coreutils-4.5.10/tests/misc/README --- coreutils-4.5.10.org/tests/misc/README Thu Jan 1 01:00:00 1970 +++ coreutils-4.5.10/tests/misc/README Mon Mar 24 16:30:58 2003 @@ -0,0 +1,6 @@ +Use the run script to run any of the *.test scripts, e.g., + + run cp.test + +The cp.test script can be run as any user; the cp-root +script requires root privileges. diff -urN coreutils-4.5.10.org/tests/misc/acl coreutils-4.5.10/tests/misc/acl --- coreutils-4.5.10.org/tests/misc/acl Thu Jan 1 01:00:00 1970 +++ coreutils-4.5.10/tests/misc/acl Mon Mar 24 16:30:58 2003 @@ -0,0 +1,3 @@ +#!/bin/sh + +getfacl "$@" | sed -e 's/[ ]*#.*$//' -e '/^$/d' diff -urN coreutils-4.5.10.org/tests/misc/cp-root.test coreutils-4.5.10/tests/misc/cp-root.test --- coreutils-4.5.10.org/tests/misc/cp-root.test Thu Jan 1 01:00:00 1970 +++ coreutils-4.5.10/tests/misc/cp-root.test Mon Mar 24 16:30:58 2003 @@ -0,0 +1,26 @@ +! Tests the access control list extensions to cp. +! This script must be run as root. +! +$ rm -rf test +$ mkdir test +$ cd test +$ umask 022 +$ touch f +$ chmod u+xs,g+xs f +$ mode f + -rwsr-sr-- f +$ cp -p f g +$ mode g + -rwsr-sr-- g +$ cp f h +$ mode h + -rwsr-sr-- h +$ chown bin h +$ cp h i +$ mode i + -rwsr-sr-- i +! +! cleanup +! +$cd .. +$ rm -rf test diff -urN coreutils-4.5.10.org/tests/misc/cp.test coreutils-4.5.10/tests/misc/cp.test --- coreutils-4.5.10.org/tests/misc/cp.test Thu Jan 1 01:00:00 1970 +++ coreutils-4.5.10/tests/misc/cp.test Mon Mar 24 16:30:58 2003 @@ -0,0 +1,86 @@ +! Tests the access control list extensions to cp (and also of ls). +! Requires a system with POSIX access control lists and the +! getfacl and setfacl utilities. +! +$ rm -rf test +$ mkdir test +$ cd test +$ umask 022 +$ touch f +$ mode . f + drwxr-xr-x . + -rw-r--r-- f +$ setfacl -m u:@OWNER@:rw- f +$ mode f + -rw-rw-r--+ f +$ acl f + user::rw- + user:@OWNER@:rw- + group::r-- + mask::rw- + other::r-- +! +! cp and cp -p +! +$ cp f g +$ cp -p f h +$ mode g h + -rw-r--r-- g + -rw-rw-r--+ h +$ acl h + user::rw- + user:@OWNER@:rw- + group::r-- + mask::rw- + other::r-- +$ mkdir d +$ setfacl -d -m u::rwx,u:@OWNER@:r-x,g::---,m::r-x,o::--- d +$ acl d + user::rwx + group::r-x + other::r-x + default:user::rwx + default:user:@OWNER@:r-x + default:group::--- + default:mask::r-x + default:other::--- +$ touch d/i +$ acl d/i + user::rw- + user:@OWNER@:r-x + group::--- + mask::r-- + other::--- +$ cp f d/f +$ acl d/f + user::rw- + user:@OWNER@:r-x + group::--- + mask::r-- + other::--- +$ chmod go-rwx g +$ cp g d/g +$ acl d/g + user::rw- + user:@OWNER@:r-x + group::--- + mask::--- + other::--- +$ cp -p h d/h +$ acl h + user::rw- + user:@OWNER@:rw- + group::r-- + mask::rw- + other::r-- +$ touch j +$ cp -p j d/j +$ mode d/j + -rw-r--r-- d/j +$ +! mv +! +! cleanup +! +$cd .. +$ rm -rf test diff -urN coreutils-4.5.10.org/tests/misc/mode coreutils-4.5.10/tests/misc/mode --- coreutils-4.5.10.org/tests/misc/mode Thu Jan 1 01:00:00 1970 +++ coreutils-4.5.10/tests/misc/mode Mon Mar 24 16:30:58 2003 @@ -0,0 +1,2 @@ +#!/bin/sh +ls -dl $* | awk -- '!/^total/ { print $1, $8; }' diff -urN coreutils-4.5.10.org/tests/misc/run coreutils-4.5.10/tests/misc/run --- coreutils-4.5.10.org/tests/misc/run Thu Jan 1 01:00:00 1970 +++ coreutils-4.5.10/tests/misc/run Mon Mar 24 16:30:58 2003 @@ -0,0 +1,164 @@ +#!/usr/bin/perl + +use strict; +use FileHandle; +use POSIX qw(geteuid getegid isatty); + +my $pwd = `pwd`; +chomp $pwd; +$ENV{'PATH'} = $pwd . ":../../src:" . $ENV{'PATH'}; + +my $owner = getpwuid(geteuid()); +my $group = getgrgid(getegid()); + +my ($OK, $FAILED) = ("ok", "failed"); +if (isatty(fileno(STDOUT))) { + $OK = "\033[32m" . $OK . "\033[m"; + $FAILED = "\033[31m\033[1m" . $FAILED . "\033[m"; +} + +my ($prog, $in, $out) = ([], [], []); +my $line = 0; +my $prog_line; +my ($tests, $failed); + +for (;;) { + my $script = <>; $line++; + $script =~ s/\@OWNER\@/$owner/g; + $script =~ s/\@GROUP\@/$group/g; + next if (defined($script) && $script =~ /^!/); + if (!defined($script) || $script =~ s/^\$ ?//) { + if (@$prog) { + #print "[$prog_line] \$ ", join(' ', @$prog), " -- "; + my $p = [ @$prog ]; + print "[$prog_line] \$ ", join(' ', + map { s/\s/\\$&/g; $_ } @$p), " -- "; + my $result = exec_test($prog, $in); + my $good = 1; + my $nmax = (@$out > @$result) ? @$out : @$result; + for (my $n=0; $n < $nmax; $n++) { + if (!defined($out->[$n]) || !defined($result->[$n]) || + $out->[$n] ne $result->[$n]) { + $good = 0; + #chomp $out->[$n]; + #chomp $result->[$n]; + #print "$out->[$n] != $result->[$n]"; + } + } + $tests++; + $failed++ unless $good; + print $good ? $OK : $FAILED, "\n"; + if (!$good) { + for (my $n=0; $n < $nmax; $n++) { + my $l = defined($out->[$n]) ? $out->[$n] : "~"; + chomp $l; + my $r = defined($result->[$n]) ? $result->[$n] : "~"; + chomp $r; + print sprintf("%-37s | %-39s\n", $l, $r); + } + } + } + #$prog = [ split /\s+/, $script ] if $script; + $prog = [ map { s/\\(.)/$1/g; $_ } split /(? ?//) { + push @$in, $script; + } else { + $script =~ s/^[ \t]*//; # ignore leading whitespace + push @$out, $script; + } + last unless defined($script); +} +my $status = sprintf("%d commands (%d passed, %d failed)", + $tests, $tests-$failed, $failed); +if (isatty(fileno(STDOUT))) { + if ($failed) { + $status = "\033[31m\033[1m" . $status . "\033[m"; + } else { + $status = "\033[32m" . $status . "\033[m"; + } +} +print $status, "\n"; + +sub exec_test($$) { + my ($prog, $in) = @_; + local (*IN, *IN_DUP, *IN2, *OUT_DUP, *OUT, *OUT2); + + if ($prog->[0] eq "umask") { + umask oct $prog->[1]; + return []; + } elsif ($prog->[0] eq "cd") { + if (!chdir $prog->[1]) { + return [ "chdir: $prog->[1]: $!\n" ]; + } + return []; + } + + pipe *IN2, *OUT + or die "Can't create pipe for reading: $!"; + open *IN_DUP, "<&STDIN" + or *IN_DUP = undef; + open *STDIN, "<&IN2" + or die "Can't duplicate pipe for reading: $!"; + close *IN2; + + open *OUT_DUP, ">&STDOUT" + or die "Can't duplicate STDOUT: $!"; + pipe *IN, *OUT2 + or die "Can't create pipe for writing: $!"; + open *STDOUT, ">&OUT2" + or die "Can't duplicate pipe for writing: $!"; + close *OUT2; + + *STDOUT->autoflush(); + *OUT->autoflush(); + + if (fork()) { + # Server + if (*IN_DUP) { + open *STDIN, "<&IN_DUP" + or die "Can't duplicate STDIN: $!"; + close *IN_DUP + or die "Can't close STDIN duplicate: $!"; + } + open *STDOUT, ">&OUT_DUP" + or die "Can't duplicate STDOUT: $!"; + close *OUT_DUP + or die "Can't close STDOUT duplicate: $!"; + + foreach my $line (@$in) { + #print "> $line"; + print OUT $line; + } + close *OUT + or die "Can't close pipe for writing: $!"; + + my $result = []; + while () { + #print "< $_"; + push @$result, $_; + } + return $result; + } else { + # Client + close IN + or die "Can't close read end for input pipe: $!"; + close OUT + or die "Can't close write end for output pipe: $!"; + close OUT_DUP + or die "Can't close STDOUT duplicate: $!"; + local *ERR_DUP; + open ERR_DUP, ">&STDERR" + or die "Can't duplicate STDERR: $!"; + open STDERR, ">&STDOUT" + or die "Can't join STDOUT and STDERR: $!"; + + #print ERR_DUP "<", join(' ', @$prog), ">\n"; + exec @$prog; + print ERR_DUP $prog->[0], ": $!\n"; + exit; + } +} + --- coreutils-5.2.1/po/pl.po.orig 2003-12-28 23:21:11.000000000 +0100 +++ coreutils-5.2.1/po/pl.po 2003-12-28 23:43:19.632649608 +0100 @@ -1011,6 +1011,11 @@ msgid "setting permissions for %s" msgstr "nie można ustawić uprawnień do %s" +#: src/copy.c:1568 +#, c-format +msgid "preserving permissions for %s" +msgstr "nie można zachować uprawnień do %s" + #: src/copy.c:1624 src/ln.c:332 #, c-format msgid "cannot un-backup %s"