]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
chown --dereference did nothing when the owner/group of a
authorJim Meyering <jim@meyering.net>
Sun, 16 May 2004 21:39:35 +0000 (21:39 +0000)
committerJim Meyering <jim@meyering.net>
Sun, 16 May 2004 21:39:35 +0000 (21:39 +0000)
symlink matched the desired owner/group.  Reported by David Malone.
Also reported in 1999 as http://bugs.debian.org/39642.

(change_file_owner): When --dereference has
been specified, and when processing a symlink, stat it to get the
owner and group of the referent.

src/chown-core.c

index 82fb4de0fddabd302b55c98a161db29c433ba3dd..b52837bbd3e51e9da02c4a9fd717e90c6b70d0fd 100644 (file)
@@ -175,7 +175,9 @@ change_file_owner (FTS *fts, FTSENT *ent,
                   struct Chown_option const *chopt)
 {
   const char *file_full_name = ent->fts_path;
-  struct stat *file_stats = ent->fts_statp;
+  struct stat const *file_stats = ent->fts_statp;
+  struct stat const *target_stats;
+  struct stat stat_buf;
   int errors = 0;
 
   /* This is the second time we've seen this directory.  */
@@ -207,12 +209,28 @@ change_file_owner (FTS *fts, FTSENT *ent,
       return 1;
     }
 
-  if ((old_uid == (uid_t) -1 || file_stats->st_uid == old_uid)
-      && (old_gid == (gid_t) -1 || file_stats->st_gid == old_gid))
+  /* If this is a symlink and we're dereferencing them,
+     stat it to get the permissions of the referent.  */
+  if (S_ISLNK (file_stats->st_mode) && chopt->affect_symlink_referent)
     {
-      uid_t new_uid = (uid == (uid_t) -1 ? file_stats->st_uid : uid);
-      gid_t new_gid = (gid == (gid_t) -1 ? file_stats->st_gid : gid);
-      if (new_uid != file_stats->st_uid || new_gid != file_stats->st_gid)
+      if (stat (ent->fts_accpath, &stat_buf) != 0)
+       {
+         error (0, errno, _("cannot dereference %s"), quote (file_full_name));
+         return 1;
+       }
+      target_stats = &stat_buf;
+    }
+  else
+    {
+      target_stats = file_stats;
+    }
+
+  if ((old_uid == (uid_t) -1 || target_stats->st_uid == old_uid)
+      && (old_gid == (gid_t) -1 || target_stats->st_gid == old_gid))
+    {
+      uid_t new_uid = (uid == (uid_t) -1 ? target_stats->st_uid : uid);
+      gid_t new_gid = (gid == (gid_t) -1 ? target_stats->st_gid : gid);
+      if (new_uid != target_stats->st_uid || new_gid != target_stats->st_gid)
        {
          const char *file = ent->fts_accpath;
          int fail;