]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
"cp -p" tries to preserve GID even if preserving the UID fails.
authorLasse Collin <lasse.collin@tukaani.org>
Fri, 9 Nov 2007 23:07:37 +0000 (01:07 +0200)
committerJim Meyering <meyering@redhat.com>
Sat, 24 Nov 2007 14:06:43 +0000 (15:06 +0100)
* 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.

ChangeLog
NEWS
src/copy.c
src/cp.c

index b34ad8da14223dc26ce694163af67538f5babe24..3caaaa36ff5259cd39a6f579973b1064ee8d18a9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-11-24  Jim Meyering  <meyering@redhat.com>
+
+       "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.
+
 2007-11-23  Jim Meyering  <meyering@redhat.com>
 
        * src/runcon.c (main): Remove unused parameter, "envp".
diff --git a/NEWS b/NEWS
index 14fb3cd8ba0fbb228384aefcdc26fec92b040de4..03e16a5d1359e9000581e7c9c3bc507329930b0c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -29,6 +29,9 @@ GNU coreutils NEWS                                    -*- outline -*-
 
   Add SELinux support (FIXME: add details here)
 
+  cp -p tries to preserve the GID of a file even if preserving the UID
+  is not possible.
+
   uniq accepts a new option: --zero-terminated (-z).  As with the sort
   option of the same name, this makes uniq consume and produce
   NUL-terminated lines rather than newline-terminated lines.
index 280fbf8d9cfb37b81e3c67bf798e0f8f7102e08a..4dec5166e12429718e1a03259bb21e1552550e33 100644 (file)
@@ -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))
index 5859f8c1d88d3656dfa6674b722c8f1f54f9dcfb..599498dd7dcdf46942a17875dbfa6b66be936c61 100644 (file)
--- a/src/cp.c
+++ b/src/cp.c
@@ -316,13 +316,18 @@ re_protect (char const *const_dst_name, size_t src_offset,
 
       if (x->preserve_ownership)
        {
-         if (lchown (dst_name, p->st.st_uid, p->st.st_gid) != 0
-             && ! chown_failure_ok (x))
-           {
-             error (0, errno, _("failed to preserve ownership for %s"),
-                    quote (dst_name));
-             return false;
-           }
+          if (lchown (dst_name, p->st.st_uid, p->st.st_gid) != 0)
+            {
+              if (! chown_failure_ok (x))
+                {
+                  error (0, errno, _("failed to preserve ownership for %s"),
+                         quote (dst_name));
+                  return false;
+                }
+              /* Failing to preserve ownership is OK. Still, try to preserve
+                 the group, but ignore the possible error. */
+              (void) lchown (dst_name, -1, p->st.st_gid);
+            }
        }
 
       if (x->preserve_mode)