diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2006-12-06 20:44:08 +0100 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2006-12-06 20:44:08 +0100 |
commit | a4f7b723f0723ec17b48ae25f0a218adcab2ff54 (patch) | |
tree | 17b957ba5b84ba3da91460fb0eb677f4e4f1dd01 /src/cp.c | |
parent | e7f7dcb9d150341b63b9b70b0aeb0593e8888857 (diff) | |
download | coreutils-a4f7b723f0723ec17b48ae25f0a218adcab2ff54.tar.xz |
* NEWS: Document the cp --preserve=ownership fix.
* m4/jm-macros.m4 (coreutils_MACROS): Check for fchmod.
* src/copy.c (fchmod_or_lchmod): New function.
(copy_reg): New arg OMITTED_PERMISSIONS. All uses changed.
Omit confusing and unused ", dst_mode" arg to 'open' without O_CREAT.
When creating a file, use O_EXCL, so we're more likely to detect
funny business by other processes. At the end, if permissions
were omitted, chmod them back in.
(copy_internal): If the ownership might change, omit some permissions
at first, then restore them after chowning the file.
* src/cp.c (make_dir_parents_private): Likewise.
* src/copy.c (cached_umask): New function.
* src/copy.h (cached_umask): New decl.
Diffstat (limited to 'src/cp.c')
-rw-r--r-- | src/cp.c | 45 |
1 files changed, 26 insertions, 19 deletions
@@ -413,6 +413,8 @@ make_dir_parents_private (char const *const_dir, size_t src_offset, if (XSTAT (x, dir, &stats)) { mode_t src_mode; + mode_t omitted_permissions; + mode_t mkdir_mode; /* This component does not exist. We must set *new_dst and new->mode inside this loop because, @@ -427,12 +429,15 @@ make_dir_parents_private (char const *const_dir, size_t src_offset, return false; } src_mode = stats.st_mode; + omitted_permissions = + x->preserve_ownership ? src_mode & (S_IRWXG | S_IRWXO) : 0; /* POSIX says mkdir's behavior is implementation-defined when (src_mode & ~S_IRWXUGO) != 0. However, common practice is to ask mkdir to copy all the CHMOD_MODE_BITS, letting mkdir decide what to do with S_ISUID | S_ISGID | S_ISVTX. */ - if (mkdir (dir, src_mode & CHMOD_MODE_BITS) != 0) + mkdir_mode = src_mode & CHMOD_MODE_BITS & ~omitted_permissions; + if (mkdir (dir, mkdir_mode) != 0) { error (0, errno, _("cannot make directory %s"), quote (dir)); @@ -454,28 +459,30 @@ make_dir_parents_private (char const *const_dir, size_t src_offset, 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; + if (! x->preserve_mode) + { + if (omitted_permissions & ~stats.st_mode) + omitted_permissions &= ~ cached_umask (); + if (omitted_permissions & ~stats.st_mode + || (stats.st_mode & S_IRWXU) != S_IRWXU) + { + new->mode = stats.st_mode | omitted_permissions; new->restore_mode = true; + } + } - if (lchmod (dir, stats.st_mode | S_IRWXU) != 0) - { - error (0, errno, _("setting permissions for %s"), - quote (dir)); - return false; - } + if ((stats.st_mode & S_IRWXU) != S_IRWXU) + { + /* Make the new directory searchable and writable. + The original permissions will be restored later. */ + + if (lchmod (dir, stats.st_mode | S_IRWXU) != 0) + { + error (0, errno, _("setting permissions for %s"), + quote (dir)); + return false; } } } |