summaryrefslogtreecommitdiff
path: root/src/copy.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2005-12-17 10:33:33 +0000
committerJim Meyering <jim@meyering.net>2005-12-17 10:33:33 +0000
commitf634e88445a138465e461743cac208f717b08f2b (patch)
treead03617da413217642b9ffbebc7593d9f372d9f2 /src/copy.c
parente6ece7ba6cea1a99c52a409138a842f4bc0b5ceb (diff)
downloadcoreutils-f634e88445a138465e461743cac208f717b08f2b.tar.xz
(get_dest_mode): Remove; it is obsolete after removing umask_kill.
(copy_reg, copy_internal): Use copy_acl and set_acl instead of fchown/chown. Fix the logic for POSIX ACLs. (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.
Diffstat (limited to 'src/copy.c')
-rw-r--r--src/copy.c136
1 files changed, 63 insertions, 73 deletions
diff --git a/src/copy.c b/src/copy.c
index 729530bac..1bfb4da6b 100644
--- a/src/copy.c
+++ b/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 const *dst_name_in, bool new_dst,
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))
{
@@ -261,13 +233,12 @@ preserve_author (const char *dst_name, int dest_desc, const struct stat *src_sb)
Use DST_MODE as the 3rd argument in the call to open.
X provides many option settings.
Return true if successful.
- *NEW_DST and *CHOWN_SUCCEEDED are as in copy_internal.
+ *NEW_DST is as in copy_internal.
SRC_SB is the result of calling XSTAT (aka stat) on SRC_NAME. */
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 const *dst_name,
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 const *dst_name,
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 (x->preserve_mode || x->move_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 (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, char const *dst_name,
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, char const *dst_name,
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, char const *dst_name,
/* 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, char const *dst_name,
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, char const *dst_name,
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;
}
}