summaryrefslogtreecommitdiff
path: root/src/copy.c
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2007-11-10 01:07:37 +0200
committerJim Meyering <meyering@redhat.com>2007-11-24 15:06:43 +0100
commitcbc06bb6390c1ad4a227723078ecd7f7689251cc (patch)
treee15224e4c5e1cdbb6817b2ae74e22587b6882099 /src/copy.c
parentad8fbe0dd2c77fe41457311f91bfcf49b0bf7616 (diff)
downloadcoreutils-cbc06bb6390c1ad4a227723078ecd7f7689251cc.tar.xz
"cp -p" tries to preserve GID even if preserving the UID fails.
* NEWS: Mention this new feature. * src/copy.c (set_owner): Try to preserve just the GID, when initial fchown/lchown fails. * src/cp.c (re_protect): Likewise.
Diffstat (limited to 'src/copy.c')
-rw-r--r--src/copy.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/src/copy.c b/src/copy.c
index 280fbf8d9..4dec5166e 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -172,7 +172,8 @@ copy_dir (char const *src_name_in, char const *dst_name_in, bool new_dst,
safety prefer lchown if the system supports it since no
symbolic links should be involved. DEST_DESC must
refer to the same file as DEST_NAME if defined.
- Return 1 if the syscall succeeds, 0 if it fails but it's OK
+ Upon failure to set both UID and GID, try to set only the GID.
+ Return 1 if the initial syscall succeeds, 0 if it fails but it's OK
not to preserve ownership, -1 otherwise. */
static int
@@ -183,11 +184,27 @@ set_owner (const struct cp_options *x, char const *dst_name, int dest_desc,
{
if (fchown (dest_desc, uid, gid) == 0)
return 1;
+ if (errno == EPERM || errno == EINVAL)
+ {
+ /* We've failed to set *both*. Now, try to set just the group
+ ID, but ignore any failure here, and don't change errno. */
+ int saved_errno = errno;
+ (void) fchown (dest_desc, -1, gid);
+ errno = saved_errno;
+ }
}
else
{
if (lchown (dst_name, uid, gid) == 0)
return 1;
+ if (errno == EPERM || errno == EINVAL)
+ {
+ /* We've failed to set *both*. Now, try to set just the group
+ ID, but ignore any failure here, and don't change errno. */
+ int saved_errno = errno;
+ (void) lchown (dst_name, -1, gid);
+ errno = saved_errno;
+ }
}
if (! chown_failure_ok (x))