bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Bug#249177: coreutils: chown is not POSIXLY_CORRECT even when the va


From: Paul Eggert
Subject: Re: Bug#249177: coreutils: chown is not POSIXLY_CORRECT even when the variable is set
Date: Tue, 18 May 2004 15:56:28 -0700
User-agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3 (gnu/linux)

Jim Meyering <address@hidden> writes:

> I've fixed them for the next upstream release.

I looked at POSIX and found some other incompatibilities with
coreutils chown and chgrp.  Here's a proposed patch to fix everything
I found.  When in doubt I did what BSD does.  Sorry about the size,
but there do seem to be a lotta gotchas in this area.

2004-05-18  Paul Eggert  <address@hidden>

        Several fixes to chgrp and chown for compatibility with POSIX and BSD:

          Check for incompatible options.  When -R and --dereference are
          both used, then either -H or -L must also be used.  When -R and -h
          are both used, then -P must be in effect.

          -H, -L, and -P have no effect unless -R is also specified.
          If -P and -R are both specified, -h is assumed.

          Do not optimize away the chown() system call when the file's owner
          and group already have the desired value.  This optimization was
          incorrect, as it failed to updated the last-changed time and reset
          special permission bits, as POSIX requires.

          Do not report an error if the owner or group of a
          recursively-encountered symbolic link cannot be updated because
          the file system does not support it.

        * NEWS: Document the above.
        
        * lib/fts.c (fts_stat, fts_alloc): Always allocate and use a struct
        stat, even if the user isn't interested in the results.
        This prevents a core dump in cycle_check when FTS_NOSTAT is set.
        * lib/lchown.c (lchown): Return EOPNOTSUPP if not supported; this
        is what POSIX-2004 specifies.
        * lib/lchown.h (EOPNOTSUPP): Define if not defined.
        (ENOSYS): Remove.

        * src/chgrp.c (main): Check for incompatible options.  -R --dereference
        requires either -H or -L, and -R -h requires -P.  If -H, specify
        FTS_PHYSICAL as well as FTS_COMFOLLOW; this is faster.  Make this
        file as much like chown.c as possible.
        * src/chown.c (main): Likewise.

        * src/chown-core.c (change_file_owner): Use ent->fts_statp only if
        needed.  Chown a directory only after chowning its children; this
        avoids problems if the new directory ownership doesn't permit
        access to the children.  Dereference symlinks before doing
        ROOT_DEV_INO_CHECK, not after, so that we catch symlinks to /.
        Do not optimize away the chown() system call when the file's owner
        and group already have the desired value.  POSIX does not permit
        this optimization.  Rely on chown and lchown to do the right
        thing with symlinks and/or -1 arguments, now that we have wrappers
        to do this.  Use ENOTSUPP not ENOSYS, and ignore all ENOTSUPP
        errors, not just command-line errors.
        (chown_files): Pass FTS_STAT to xfts_open if we don't need file status.

        * src/system.h (ENOTSUP): Remove.

        * tests/chgrp/basic: Use chown --from to discover whether the
        group changed, since chgrp now changes unconditionally.  This
        complicates the sed script a bit.  Do not specify --dereference,
        since it's the default (and we want to test this).  Adjust output
        to match the fact that chgrp no longer optimizes the case of
        changing a file's group to the same value as before.
        * tests/chgrp/posix-H: Do not attempt to combine -h and -H; these
        options are incompatible, and their behavior is undefined with POSIX.
        (changed, not_changed): Adjust to match the fact that -h is no longer
        specified.  Sort names.
        * tests/chown/deref: Adjust error-diagnostic spelling to match new
        behavior.

Index: NEWS
===================================================================
RCS file: /home/meyering/coreutils/cu/NEWS,v
retrieving revision 1.209
diff -p -u -r1.209 NEWS
--- NEWS        17 May 2004 12:11:54 -0000      1.209
+++ NEWS        18 May 2004 22:49:27 -0000
@@ -4,12 +4,30 @@ GNU coreutils NEWS                      
 
 ** Bug fixes
 
-  chgrp and chown no longer affect symbolic links by default.
-  Now, they operate on whatever a symbolic points to, instead.
-  To get the old behavior, use --no-dereference (-h).
+  Several fixes to chgrp and chown for compatibility with POSIX and BSD:
 
-  chown --dereference now works, even when the specified owner
-  and/or group match those of an affected symlink.
+    Do not affect symbolic links by default.
+    Now, operate on whatever a symbolic points to, instead.
+    To get the old behavior, use --no-dereference (-h).
+
+    --dereference now works, even when the specified owner
+    and/or group match those of an affected symlink.
+
+    Check for incompatible options.  When -R and --dereference are
+    both used, then either -H or -L must also be used.  When -R and -h
+    are both used, then -P must be in effect.
+
+    -H, -L, and -P have no effect unless -R is also specified.
+    If -P and -R are both specified, -h is assumed.
+
+    Do not optimize away the chown() system call when the file's owner
+    and group already have the desired value.  This optimization was
+    incorrect, as it failed to updated the last-changed time and reset
+    special permission bits, as POSIX requires.
+
+    Do not report an error if the owner or group of a
+    recursively-encountered symbolic link cannot be updated because
+    the file system does not support it.
 
   rm no longer required read access to the current directory.
 
Index: lib/fts.c
===================================================================
RCS file: /home/meyering/coreutils/cu/lib/fts.c,v
retrieving revision 1.14
diff -p -u -r1.14 fts.c
--- lib/fts.c   29 Mar 2004 07:28:52 -0000      1.14
+++ lib/fts.c   18 May 2004 19:16:32 -0000
@@ -1136,19 +1136,14 @@ fts_stat(sp, p, follow)
        register FTSENT *p;
        int follow;
 {
-       struct stat *sbp, sb;
+       struct stat *sbp = p->fts_statp;
        int saved_errno;
 
-       /* If user needs stat info, stat buffer already allocated. */
-       sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
-
 #if defined FTS_WHITEOUT && 0
        /* check for whiteout */
        if (p->fts_flags & FTS_ISW) {
-               if (sbp != &sb) {
-                       memset(sbp, '\0', sizeof (*sbp));
-                       sbp->st_mode = S_IFWHT;
-               }
+               memset(sbp, '\0', sizeof (*sbp));
+               sbp->st_mode = S_IFWHT;
                return (FTS_W);
        }
 #endif
@@ -1247,16 +1242,14 @@ fts_alloc(sp, name, namelen)
        size_t len;
 
        /*
-        * The file name is a variable length array and no stat structure is
-        * necessary if the user has set the nostat bit.  Allocate the FTSENT
+        * The file name is a variable length array.  Allocate the FTSENT
         * structure, the file name and the stat structure in one chunk, but
         * be careful that the stat structure is reasonably aligned.  Since the
         * fts_name field is declared to be of size 1, the fts_name pointer is
         * namelen + 2 before the first possible address of the stat structure.
         */
        len = sizeof(FTSENT) + namelen;
-       if (!ISSET(FTS_NOSTAT))
-               len += sizeof(struct stat) + ALIGNBYTES;
+       len += sizeof(struct stat) + ALIGNBYTES;
        if ((p = malloc(len)) == NULL)
                return (NULL);
 
@@ -1264,8 +1257,7 @@ fts_alloc(sp, name, namelen)
        memmove(p->fts_name, name, namelen);
        p->fts_name[namelen] = '\0';
 
-       if (!ISSET(FTS_NOSTAT))
-               p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
+       p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
        p->fts_namelen = namelen;
        p->fts_path = sp->fts_path;
        p->fts_errno = 0;
Index: lib/lchown.c
===================================================================
RCS file: /home/meyering/coreutils/cu/lib/lchown.c,v
retrieving revision 1.13
diff -p -u -r1.13 lchown.c
--- lib/lchown.c        3 May 2004 12:50:24 -0000       1.13
+++ lib/lchown.c        18 May 2004 18:27:50 -0000
@@ -44,24 +44,22 @@ extern int errno;
 int chown ();
 
 /* Work just like chown, except when FILE is a symbolic link.
-   In that case, set errno to ENOSYS and return -1.
+   In that case, set errno to EOPNOTSUPP and return -1.
    But if autoconf tests determined that chown modifies
    symlinks, then just call chown.  */
 
 int
 lchown (const char *file, uid_t uid, gid_t gid)
 {
-#if CHOWN_MODIFIES_SYMLINK
-  return chown (file, uid, gid);
-#else
+#if ! CHOWN_MODIFIES_SYMLINK
   struct stat stats;
 
   if (lstat (file, &stats) == 0 && S_ISLNK (stats.st_mode))
     {
-      errno = ENOSYS;
+      errno = EOPNOTSUPP;
       return -1;
     }
+#endif
 
   return chown (file, uid, gid);
-#endif
 }
Index: lib/lchown.h
===================================================================
RCS file: /home/meyering/coreutils/cu/lib/lchown.h,v
retrieving revision 1.2
diff -p -u -r1.2 lchown.h
--- lib/lchown.h        5 Sep 1999 06:56:50 -0000       1.2
+++ lib/lchown.h        18 May 2004 07:29:59 -0000
@@ -1,9 +1,9 @@
-/* Some systems don't have ENOSYS.  */
-#ifndef ENOSYS
+/* Some systems don't have EOPNOTSUPP.  */
+#ifndef EOPNOTSUPP
 # ifdef ENOTSUP
-#  define ENOSYS ENOTSUP
+#  define EOPNOTSUPP ENOTSUP
 # else
 /* Some systems don't have ENOTSUP either.  */
-#  define ENOSYS EINVAL
+#  define EOPNOTSUPP EINVAL
 # endif
 #endif
Index: src/chgrp.c
===================================================================
RCS file: /home/meyering/coreutils/cu/src/chgrp.c,v
retrieving revision 1.110
diff -p -u -r1.110 chgrp.c
--- src/chgrp.c 17 May 2004 12:08:17 -0000      1.110
+++ src/chgrp.c 18 May 2004 22:12:34 -0000
@@ -169,10 +169,16 @@ int
 main (int argc, char **argv)
 {
   gid_t gid;
+
   /* Bit flags that control how fts works.  */
   int bit_flags = FTS_PHYSICAL;
+
+  /* 1 if --dereference, 0 if --no-dereference, -1 if neither has been
+     specified.  */
+  int dereference = -1;
+
   struct Chown_option chopt;
-  int fail = 0;
+  int fail;
   int optc;
 
   initialize_main (&argc, &argv);
@@ -194,7 +200,7 @@ main (int argc, char **argv)
          break;
 
        case 'H': /* Traverse command-line symlinks-to-directories.  */
-         bit_flags = FTS_COMFOLLOW;
+         bit_flags = FTS_COMFOLLOW | FTS_PHYSICAL;
          break;
 
        case 'L': /* Traverse all symlinks-to-directories.  */
@@ -206,12 +212,12 @@ main (int argc, char **argv)
          break;
 
        case 'h': /* --no-dereference: affect symlinks */
-         chopt.affect_symlink_referent = false;
+         dereference = 0;
          break;
 
        case DEREFERENCE_OPTION: /* --dereference: affect the referent
                                    of each symlink */
-         chopt.affect_symlink_referent = true;
+         dereference = 1;
          break;
 
        case REFERENCE_FILE_OPTION:
@@ -241,6 +247,28 @@ main (int argc, char **argv)
        }
     }
 
+  if (chopt.recurse)
+    {
+      if (bit_flags == FTS_PHYSICAL)
+       {
+         if (dereference == 1)
+           error (EXIT_FAILURE, 0,
+                  _("-R --dereference requires either -H or -L"));
+         chopt.affect_symlink_referent = false;
+       }
+      else
+       {
+         if (dereference == 0)
+           error (EXIT_FAILURE, 0, _("-R -h requires -P"));
+         chopt.affect_symlink_referent = true;
+       }
+    }
+  else
+    {
+      bit_flags = FTS_PHYSICAL;
+      chopt.affect_symlink_referent = (dereference != 0);
+    }
+
   if (argc - optind + (reference_file ? 1 : 0) <= 1)
     {
       error (0, 0, _("too few arguments"));
@@ -254,8 +282,8 @@ main (int argc, char **argv)
        error (EXIT_FAILURE, errno, _("failed to get attributes of %s"),
               quote (reference_file));
 
-      chopt.group_name = gid_to_name (ref_stats.st_gid);
       gid = ref_stats.st_gid;
+      chopt.group_name = gid_to_name (ref_stats.st_gid);
     }
   else
     {
Index: src/chown-core.c
===================================================================
RCS file: /home/meyering/coreutils/cu/src/chown-core.c,v
retrieving revision 1.23
diff -p -u -r1.23 chown-core.c
--- src/chown-core.c    17 May 2004 12:07:48 -0000      1.23
+++ src/chown-core.c    18 May 2004 22:21:24 -0000
@@ -175,17 +175,24 @@ change_file_owner (FTS *fts, FTSENT *ent
                   struct Chown_option const *chopt)
 {
   const char *file_full_name = ent->fts_path;
-  struct stat const *file_stats = ent->fts_statp;
-  struct stat const *target_stats;
+  struct stat const *file_stats IF_LINT (= NULL);
   struct stat stat_buf;
   int errors = 0;
-
-  /* This is the second time we've seen this directory.  */
-  if (ent->fts_info == FTS_DP)
-    return 0;
+  bool do_chown = true;
+  bool symlink_changed = true;
 
   switch (ent->fts_info)
     {
+    case FTS_D:
+      if (chopt->recurse)
+       return 0;
+      break;
+
+    case FTS_DP:
+      if (! chopt->recurse)
+       return 0;
+      break;
+
     case FTS_NS:
       error (0, ent->fts_errno, _("cannot access %s"), quote (file_full_name));
       return 1;
@@ -203,104 +210,85 @@ change_file_owner (FTS *fts, FTSENT *ent
       break;
     }
 
-  if (ROOT_DEV_INO_CHECK (chopt->root_dev_ino, file_stats))
+  if (old_uid != (uid_t) -1 || old_gid != (gid_t) -1
+      || (chopt->root_dev_ino && chopt->affect_symlink_referent))
     {
-      ROOT_DEV_INO_WARN (file_full_name);
-      return 1;
+      file_stats = ent->fts_statp;
+
+      /* 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)
+       {
+         if (stat (ent->fts_accpath, &stat_buf) != 0)
+           {
+             error (0, errno, _("cannot dereference %s"),
+                    quote (file_full_name));
+             return 1;
+           }
+
+         file_stats = &stat_buf;
+       }
+
+      do_chown = ((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)
+  if (do_chown)
     {
-      if (stat (ent->fts_accpath, &stat_buf) != 0)
+      const char *file = ent->fts_accpath;
+
+      if (ROOT_DEV_INO_CHECK (chopt->root_dev_ino, file_stats))
        {
-         error (0, errno, _("cannot dereference %s"), quote (file_full_name));
+         ROOT_DEV_INO_WARN (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)
+      if (chopt->affect_symlink_referent)
        {
-         const char *file = ent->fts_accpath;
-         int fail;
-         int symlink_changed = 1;
-         int saved_errno;
+         /* Applying chown to a symlink and expecting it to affect
+            the referent is not portable, but here we may be using a
+            wrapper that tries to correct for unconforming chown.  */
+         errors = chown (file, uid, gid);
+       }
+      else
+       {
+         errors = lchown (file, uid, gid);
 
-         if (S_ISLNK (file_stats->st_mode))
+         /* Ignore any error due to lack of support; POSIX requires
+            this behavior for top-level symbolic links with -h, and
+            implies that it's required for all symbolic links.  */
+         if (errors && errno == EOPNOTSUPP)
            {
-             if (chopt->affect_symlink_referent)
-               {
-                 /* Applying chown to a symlink and expecting it to affect
-                    the referent is not portable, but here we may be using a
-                    wrapper that tries to correct for unconforming chown.  */
-                 fail = chown (file, new_uid, new_gid);
-               }
-             else
-               {
-                 bool is_command_line_argument = (ent->fts_level == 1);
-                 fail = lchown (file, new_uid, new_gid);
-
-                 /* Ignore the failure if it's due to lack of support (ENOSYS)
-                    and this is not a command line argument.  */
-                 if (!is_command_line_argument && fail && errno == ENOSYS)
-                   {
-                     fail = 0;
-                     symlink_changed = 0;
-                   }
-               }
+             errors = 0;
+             symlink_changed = false;
            }
-         else
-           {
-             fail = chown (file, new_uid, new_gid);
-           }
-         saved_errno = errno;
+       }
 
-         if (chopt->verbosity == V_high
-             || (chopt->verbosity == V_changes_only && !fail))
-           {
-             enum Change_status ch_status = (! symlink_changed
-                                             ? CH_NOT_APPLIED
-                                             : (fail
-                                                ? CH_FAILED : CH_SUCCEEDED));
-             describe_change (file_full_name, ch_status,
-                              chopt->user_name, chopt->group_name);
-           }
+      /* On some systems (e.g., Linux-2.4.x),
+        the chown function resets the `special' permission bits.
+        Do *not* restore those bits;  doing so would open a window in
+        which a malicious user, M, could subvert a chown command run
+        by some other user and operating on files in a directory
+        where M has write access.  */
+
+      if (errors && ! chopt->force_silent)
+       error (0, errno, (uid != (uid_t) -1
+                         ? _("changing ownership of %s")
+                         : _("changing group of %s")),
+              quote (file_full_name));
+    }
 
-         if (fail)
-           {
-             if ( ! chopt->force_silent)
-               error (0, saved_errno, (uid != (uid_t) -1
-                                       ? _("changing ownership of %s")
-                                       : _("changing group of %s")),
-                      quote (file_full_name));
-             errors = 1;
-           }
-         else
-           {
-             /* The change succeeded.  On some systems (e.g., Linux-2.4.x),
-                the chown function resets the `special' permission bits.
-                Do *not* restore those bits;  doing so would open a window in
-                which a malicious user, M, could subvert a chown command run
-                by some other user and operating on files in a directory
-                where M has write access.  */
-           }
-       }
-      else if (chopt->verbosity == V_high)
-       {
-         describe_change (file_full_name, CH_NO_CHANGE_REQUESTED,
-                          chopt->user_name, chopt->group_name);
-       }
+  if (chopt->verbosity == V_high
+      || (chopt->verbosity == V_changes_only && !errors))
+    {
+      enum Change_status ch_status = (!do_chown ? CH_NO_CHANGE_REQUESTED
+                                     : !symlink_changed ? CH_NOT_APPLIED
+                                     : errors ? CH_FAILED
+                                     : CH_SUCCEEDED);
+      describe_change (file_full_name, ch_status,
+                      chopt->user_name, chopt->group_name);
     }
 
   if ( ! chopt->recurse)
@@ -326,7 +314,14 @@ chown_files (char **files, int bit_flags
 {
   int fail = 0;
 
-  FTS *fts = xfts_open (files, bit_flags, NULL);
+  /* Use lstat and stat only if they're needed.  */
+  int stat_flags = ((chopt->root_dev_ino
+                    || required_uid != (uid_t) -1
+                    || required_gid != (gid_t) -1)
+                   ? 0
+                   : FTS_NOSTAT);
+
+  FTS *fts = xfts_open (files, bit_flags | stat_flags, NULL);
 
   while (1)
     {
Index: src/chown.c
===================================================================
RCS file: /home/meyering/coreutils/cu/src/chown.c,v
retrieving revision 1.115
diff -p -u -r1.115 chown.c
--- src/chown.c 17 May 2004 12:08:09 -0000      1.115
+++ src/chown.c 18 May 2004 22:09:40 -0000
@@ -170,6 +170,10 @@ main (int argc, char **argv)
   /* Bit flags that control how fts works.  */
   int bit_flags = FTS_PHYSICAL;
 
+  /* 1 if --dereference, 0 if --no-dereference, -1 if neither has been
+     specified.  */
+  int dereference = -1;
+
   struct Chown_option chopt;
   int fail;
   int optc;
@@ -193,7 +197,7 @@ main (int argc, char **argv)
          break;
 
        case 'H': /* Traverse command-line symlinks-to-directories.  */
-         bit_flags = FTS_COMFOLLOW;
+         bit_flags = FTS_COMFOLLOW | FTS_PHYSICAL;
          break;
 
        case 'L': /* Traverse all symlinks-to-directories.  */
@@ -205,12 +209,12 @@ main (int argc, char **argv)
          break;
 
        case 'h': /* --no-dereference: affect symlinks */
-         chopt.affect_symlink_referent = false;
+         dereference = 0;
          break;
 
        case DEREFERENCE_OPTION: /* --dereference: affect the referent
                                    of each symlink */
-         chopt.affect_symlink_referent = true;
+         dereference = 1;
          break;
 
        case NO_PRESERVE_ROOT:
@@ -257,6 +261,28 @@ main (int argc, char **argv)
        default:
          usage (EXIT_FAILURE);
        }
+    }
+
+  if (chopt.recurse)
+    {
+      if (bit_flags == FTS_PHYSICAL)
+       {
+         if (dereference == 1)
+           error (EXIT_FAILURE, 0,
+                  _("-R --dereference requires either -H or -L"));
+         chopt.affect_symlink_referent = false;
+       }
+      else
+       {
+         if (dereference == 0)
+           error (EXIT_FAILURE, 0, _("-R -h requires -P"));
+         chopt.affect_symlink_referent = true;
+       }
+    }
+  else
+    {
+      bit_flags = FTS_PHYSICAL;
+      chopt.affect_symlink_referent = (dereference != 0);
     }
 
   if (argc - optind + (reference_file ? 1 : 0) <= 1)
Index: src/system.h
===================================================================
RCS file: /home/meyering/coreutils/cu/src/system.h,v
retrieving revision 1.87
diff -p -u -r1.87 system.h
--- src/system.h        18 Apr 2004 13:09:27 -0000      1.87
+++ src/system.h        18 May 2004 07:31:26 -0000
@@ -127,9 +127,6 @@ extern int errno;
 #ifndef ENOSYS
 # define ENOSYS (-1)
 #endif
-#ifndef ENOTSUP
-# define ENOTSUP (-1)
-#endif
 #ifndef EISDIR
 # define EISDIR (-1)
 #endif
Index: tests/chgrp/basic
===================================================================
RCS file: /home/meyering/coreutils/cu/tests/chgrp/basic,v
retrieving revision 1.14
diff -p -u -r1.14 basic
--- tests/chgrp/basic   17 May 2004 12:10:43 -0000      1.14
+++ tests/chgrp/basic   18 May 2004 22:02:12 -0000
@@ -60,32 +60,36 @@ test "$VERBOSE" = yes && set +x
 
   # This should not change the group of f.
   chgrp -h -c $g2 symlink 2> /dev/null
-  chgrp -c $g2 f
+  chown --from=:$g1 -c :$g2 f
 
   # This *should* change the group of f.
   # Though note that the diagnostic is misleading in that
   # it says the `group of `symlink'' has been changed.
-  chgrp --dereference -c $g1 symlink
+  chgrp -c $g1 symlink
+  chown --from=:$g1 -c :$g2 f
 
-) 2>&1 | sed "s/ $g1$/ G1/;s/ $g2$/ G2/" > actual
+) 2>&1 | sed "s/\([ :]\)$g1$/\1G1/;s/\([ :]\)$g2$/\1G2/" > actual
 
 cat <<\EOF > expected
 changed group of `f' to G1
 changed group of `f' to G2
+changed group of `f' to G2
+changed group of `f' to G1
 changed group of `f' to G1
-group of `f' retained as G1
 changed group of `f' to G2
-changed group of `d' to G2
 changed group of `d/f3' to G2
-changed group of `d' to G1
-changed group of `d/f3' to G1
 changed group of `d' to G2
-changed group of `d/f3' to G2
+changed group of `d/f3' to G1
 changed group of `d' to G1
+changed group of `d/f3' to G2
+changed group of `d' to G2
 changed group of `d/f3' to G1
+changed group of `d' to G1
 changed group of `d' to G2
-changed group of `f' to G2
+changed group of `symlink' to G2
+changed ownership of `f' to :G2
 changed group of `symlink' to G1
+changed ownership of `f' to :G2
 EOF
 
 cmp expected actual \
Index: tests/chgrp/posix-H
===================================================================
RCS file: /home/meyering/coreutils/cu/tests/chgrp/posix-H,v
retrieving revision 1.2
diff -p -u -r1.2 posix-H
--- tests/chgrp/posix-H 17 May 2004 12:10:47 -0000      1.2
+++ tests/chgrp/posix-H 18 May 2004 21:06:03 -0000
@@ -33,7 +33,7 @@ fi
 
 fail=0
 
-chgrp -h -HR $g2 1s 2 || fail=1
+chgrp -H -R $g2 1s 2 || fail=1
 
 # These must have group $g2.
 # =========================
@@ -41,8 +41,8 @@ changed='
 1
 1/1F
 2
-2/2s
 2/2F
+3
 '
 for i in $changed; do
   # Filter out symlinks (entries that end in `s'), since it's not
@@ -56,9 +56,9 @@ done
 # These must have group $g1.
 # =========================
 not_changed='
-3
-3/3F
 1s
+2/2s
+3/3F
 '
 for i in $not_changed; do
   # Filter out symlinks (entries that end in `s'), since it's not
Index: tests/chown/deref
===================================================================
RCS file: /home/meyering/coreutils/cu/tests/chown/deref,v
retrieving revision 1.2
diff -p -u -r1.2 deref
--- tests/chown/deref   16 May 2004 14:17:53 -0000      1.2
+++ tests/chown/deref   17 May 2004 23:30:32 -0000
@@ -33,7 +33,7 @@ chown --dereference $user dangle 2> out1
 sed 's/: [^:]*$//' out1 > out
 
 cat <<\EOF > exp || fail=1
-chown: cannot dereference `dangle'
+chown: changing ownership of `dangle'
 EOF
 
 cmp out exp || fail=1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]