Seems to me that a recursive chown/chgrp, in a large directory with
_most_but_not_all files already set to the desired owner/group, can
be rather wastefull.  As near as I can tell, the kernel is called
for every file, even those for whom the update of attributes is
effectively a no-op.  Further, these no-op calls apparently trigger
other non-updates to the filesystem whjich can affect files' mtime
and/or atime.

(FWIW, I frequently end up with such a directory when a CVS update
picks up a new file and I forgot to su(8) to the owner's UID first!
The new files get my current owner uid while all the other files
are owned by someone else.)

I propose the attached enhancement to chown/chgrp to avoid setting
a new user/group value if the desired values are already set.  The
change is pretty simple.

Note that this change also modifies the changes that might be made
to a file's setuid/setgid mode bits.  Current code simply clears the
bits for every file, whether or not the user/group is really being
updated.  The attached patch only clears the bits if the user/group
is also being _changed_ from its current value.

Comments?  Useful?  Suggestions?  Should I commit?

+--------------------+--------------------------+----------------------+
| Paul Goyette       | PGP Key fingerprint:     | E-mail addresses:    |
| (Retired)          | FA29 0E3B 35AF E8AE 6651 | p...@whooppee.com    |
| Software Developer | 0786 F758 55DE 53BA 7731 | pgoye...@netbsd.org  |
| & Network Engineer |                          | pgoyett...@gmail.com |
+--------------------+--------------------------+----------------------+
Index: chgrp.1
===================================================================
RCS file: /cvsroot/src/sbin/chown/chgrp.1,v
retrieving revision 1.8
diff -u -p -r1.8 chgrp.1
--- chgrp.1     4 Jul 2017 06:52:20 -0000       1.8
+++ chgrp.1     28 Apr 2023 19:01:05 -0000
@@ -31,7 +31,7 @@
 .\"     from: @(#)chgrp.1      8.3 (Berkeley) 3/31/94
 .\"    $NetBSD: chgrp.1,v 1.8 2017/07/04 06:52:20 wiz Exp $
 .\"
-.Dd October 22, 2012
+.Dd May 1, 2023
 .Dt CHGRP 1
 .Os
 .Sh NAME
@@ -86,6 +86,9 @@ option is specified, no symbolic links a
 .It Fl R
 Change the group ID for the file hierarchies rooted
 in the files instead of just the files themselves.
+.It Fl d
+Do not attempt to update a file's group if it is already set to the
+desired value.
 .It Fl f
 The force option ignores errors, except for usage errors and doesn't
 query about strange modes (unless the user does not have proper permissions).
@@ -164,6 +167,8 @@ utility is expected to be POSIX 1003.2 c
 .Pp
 The
 .Fl v
-option and the use of ``#'' to force a numeric group ID
+and
+.Fl d
+options and the use of ``#'' to force a numeric group ID
 are extensions to
 .St -p1003.2 .
Index: chown.8
===================================================================
RCS file: /cvsroot/src/sbin/chown/chown.8,v
retrieving revision 1.12
diff -u -p -r1.12 chown.8
--- chown.8     4 Jul 2017 06:53:12 -0000       1.12
+++ chown.8     28 Apr 2023 19:01:05 -0000
@@ -28,7 +28,7 @@
 .\"     from: @(#)chown.8      8.3 (Berkeley) 3/31/94
 .\"    $NetBSD: chown.8,v 1.12 2017/07/04 06:53:12 wiz Exp $
 .\"
-.Dd September 11, 2016
+.Dd May 1, 2023
 .Dt CHOWN 8
 .Os
 .Sh NAME
@@ -84,6 +84,9 @@ option is specified, no symbolic links a
 .It Fl R
 Change the user ID and/or the group ID for the file hierarchies rooted
 in the files instead of just the files themselves.
+.It Fl d
+Do not attempt to update a file's owner or group if it is already
+set to the desired value.
 .It Fl f
 Do not report any failure to change file owner or group, nor modify
 the exit status to reflect such failures.
@@ -174,7 +177,9 @@ command is expected to be POSIX 1003.2 c
 .Pp
 The
 .Fl v
-option and the use of ``#'' to force a numeric lookup
+and
+.Fl d
+options and the use of ``#'' to force a numeric lookup
 are extensions to
 .St -p1003.2 .
 .Sh HISTORY
Index: chown.c
===================================================================
RCS file: /cvsroot/src/sbin/chown/chown.c,v
retrieving revision 1.9
diff -u -p -r1.9 chown.c
--- chown.c     28 Apr 2023 09:56:45 -0000      1.9
+++ chown.c     28 Apr 2023 19:01:05 -0000
@@ -82,7 +82,7 @@ main(int argc, char **argv)
 {
        FTS *ftsp;
        FTSENT *p;
-       int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval, vflag;
+       int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval, vflag, 
dflag;
        char *cp, *reference;
        int (*change_owner)(const char *, uid_t, gid_t);
 
@@ -94,13 +94,16 @@ main(int argc, char **argv)
        ischown = (myname[2] == 'o');
        reference = NULL;
 
-       Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
-       while ((ch = getopt_long(argc, argv, "HLPRfhv",
+       Hflag = Lflag = Rflag = fflag = hflag = vflag = dflag = 0;
+       while ((ch = getopt_long(argc, argv, "HLPRdfhv",
            chown_longopts, NULL)) != -1)
                switch (ch) {
                case 1:
                        reference = optarg;
                        break;
+               case 'd':
+                       dflag = 1;
+                       break;
                case 'H':
                        Hflag = 1;
                        Lflag = 0;
@@ -232,6 +235,15 @@ main(int argc, char **argv)
                        break;
                }
 
+               /*
+                * If dflag was set, and the owner and group are already
+                * set to the right value, skip any attempt to update.
+                */
+               if (dflag &&
+                   ( uid == -1 || p->fts_statp->st_uid == uid ) &&
+                   ( gid == -1 || p->fts_statp->st_gid == gid ))
+                       continue;
+
                if ((*change_owner)(p->fts_accpath, uid, gid) && !fflag) {
                        warn("%s", p->fts_path);
                        rval = EXIT_FAILURE;
@@ -294,8 +306,8 @@ usage(void)
 {
 
        (void)fprintf(stderr,
-           "Usage: %s [-R [-H | -L | -P]] [-fhv] %s file ...\n"
-           "\t%s [-R [-H | -L | -P]] [-fhv] --reference=rfile file ...\n",
+           "Usage: %s [-R [-H | -L | -P]] [-dfhv] %s file ...\n"
+           "\t%s [-R [-H | -L | -P]] [-dfhv] --reference=rfile file ...\n",
            myname, ischown ? "owner:group|owner|:group" : "group",
            myname);
        exit(EXIT_FAILURE);

Reply via email to