On Sat, Jul 16, 2005 at 07:14:13PM -0700, Paul Eggert wrote:

> I assume you're talking about the -H, -h, -L, -P options.  You're
> right, these would be nice to add to coreutils.  

Please find enclosed a patch which adds the -H, -L and -P options
(with no long form).  This was actually pretty easy since fts()
provides all the required functionality.  I also enclose an entry for
the test suite for these three options (and the default).  I've tested
the test suite entry by backing out the change and seeing the new
tests fail.

Apologies for any formatting errors in the ChangeLog entry.

Adding the -h option is essentially orthogonal as this would be a
change to process_file(); if S_ISLNK(file_stats->st_mode), we would
need to use lchmod(2) (for which a test would need to be introduced
into configure.ac) on the symbolic link.  I haven't implemented this
yet.

Dave, could you define for us (i.e. the mailing list) how the "-h" and
"-L" options of chmod interact, both when -R is given and when it is
not?  Thanks.

Regards,
James.
Index: src/chmod.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/chmod.c,v
retrieving revision 1.113
diff -u -r1.113 chmod.c
--- src/chmod.c 29 Jun 2005 16:27:37 -0000      1.113
+++ src/chmod.c 17 Jul 2005 11:01:33 -0000
@@ -235,6 +235,21 @@
              ok = false;
            }
        }
+      else
+       {
+#if HAVE_LCHMOD
+         if (lchmod (file, new_mode) == 0)
+           chmod_succeeded = true;
+         else
+           {
+             if (! force_silent)
+               error (0, errno, _("changing permissions of symbolic link %s"),
+                      quote (file_full_name));
+             ok = false;
+           }
+#endif   
+       }
+      
     }
 
   if (verbosity != V_off)
@@ -343,6 +358,9 @@
   -v, --verbose           output a diagnostic for every file processed\n\
       --reference=RFILE   use RFILE's mode instead of MODE values\n\
   -R, --recursive         change files and directories recursively\n\
+  -P                      with -R, do not follow symblic links (default)\n\
+  -L                      with -R, follow all symbolic links\n\
+  -H                      with -R, follow links only for named files\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -368,7 +386,8 @@
   bool preserve_root = false;
   char const *reference_file = NULL;
   int c;
-
+  int symlink_options = FTS_PHYSICAL;
+  
   initialize_main (&argc, &argv);
   program_name = argv[0];
   setlocale (LC_ALL, "");
@@ -378,9 +397,9 @@
   atexit (close_stdout);
 
   recurse = force_silent = diagnose_surprises = false;
-
+  
   while ((c = getopt_long (argc, argv,
-                          "Rcfvr::w::x::X::s::t::u::g::o::a::,::+::=::",
+                          "HLPRcfvr::w::x::X::s::t::u::g::o::a::,::+::=::",
                           long_options, NULL))
         != -1)
     {
@@ -434,6 +453,15 @@
        case REFERENCE_FILE_OPTION:
          reference_file = optarg;
          break;
+       case 'H':
+         symlink_options = FTS_COMFOLLOW;
+         break;
+       case 'L':
+         symlink_options = FTS_LOGICAL;
+         break;
+       case 'P':               /* default if -R, ignored otherwise */
+         symlink_options = FTS_PHYSICAL;
+         break;
        case 'R':
          recurse = true;
          break;
@@ -507,7 +535,11 @@
       root_dev_ino = NULL;
     }
 
-  ok = process_files (argv + optind, FTS_COMFOLLOW);
+  /* Options -H, -L and -P are ignored in the absence of -R. */
+  if (!recurse)
+    symlink_options = FTS_COMFOLLOW;
+  
+  ok = process_files (argv + optind, symlink_options);
 
   exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
 }
--- /dev/null   2005-04-10 23:52:41.000000000 +0100
+++ tests/chmod/symlinks        2005-07-17 11:57:29.974020711 +0100
@@ -0,0 +1,99 @@
+#!/bin/sh
+# Make sure chmod options -H, -L, -P work as designed.
+# This is a feature from BSD's chmod.
+
+if test "$VERBOSE" = yes; then
+  set -x
+  chmod --version
+fi
+
+pwd=`pwd`
+tmp=equals.$$
+trap 'status=$?; cd $pwd; rm -rf A B C && exit $status' 0
+trap '(exit $?); exit' 1 2 13 15
+
+framework_failure=0
+
+if test $framework_failure = 1; then
+  echo "$0: failure in testing framework" 1>&2
+  (exit 1); exit 1
+fi
+
+fail=0
+
+# prepare our files.
+mkdir A B 
+ln -s B C
+( cd B ; ln -s ../A b )
+touch     A/xyzzy B/xyzzy
+chmod 555 A/xyzzy B/xyzzy
+
+expected_yes=-r-xr-x---
+expected_no=-r-xr-xr-x
+
+if test $fail -eq 0; then
+    : 1
+    # Test -P (the default).  
+    # B should be unaffected since c->B should not be followed.
+    chmod -R -P o= A C || fail=1
+    
+    # -P: A should be affected.  B should be unaffected
+    set _ `ls -l A/xyzzy`; shift; actual_perms=$1
+    test "$actual_perms" = "$expected_yes" || fail=1
+    set _ `ls -l B/xyzzy`; shift; actual_perms=$1
+    test "$actual_perms" = "$expected_no" || fail=1
+fi
+
+if test $fail -eq 0; then
+    : 2
+    # reset to initial conditions.
+    chmod -R 555 */xyzzy
+    
+    # -L: Both A and B should be affected, because
+    #     chmod should follow the link B/b -> ../A
+    chmod -R -L o= B || fail=1
+    set _ `ls -l A/xyzzy`; shift; actual_perms=$1
+    test "$actual_perms" = "$expected_yes" || fail=1
+    set _ `ls -l B/xyzzy`; shift; actual_perms=$1
+    test "$actual_perms" = "$expected_yes" || fail=1
+fi
+    
+if test $fail -eq 0; then
+    : 3a
+    # reset to initial conditions.
+    chmod -R 555 */xyzzy
+    
+    # -H: Only links named on the command line should
+    #     be followed.
+    chmod -R -H o= C || fail=1
+    # B/xyzzy should be affected since C is a symlink to A.
+    set _ `ls -l B/xyzzy`; shift; actual_perms=$1
+    test "$actual_perms" = "$expected_yes" || fail=1
+fi
+    
+if test $fail -eq 0; then
+    : 3b
+    # reset to initial conditions.
+    chmod -R 555 */xyzzy
+    chmod -R -H o= B || fail=1
+    # A/xyzzy should NOT be affected since the B/b symlink 
+    # should not be affected.
+    set _ `ls -l A/xyzzy`; shift; actual_perms=$1
+    test "$actual_perms" = "$expected_no" || fail=1
+fi
+    
+if test $fail -eq 0; then
+    : 4
+    # Check that the default behaviour is consistent with -P.
+    # reset to initial conditions.
+    chmod -R 555 */xyzzy
+    chmod -R -P o= A C || fail=1
+    
+    # -P: A should be affected.  B should be unaffected
+    set _ `ls -l A/xyzzy`; shift; actual_perms=$1
+    test "$actual_perms" = "$expected_yes" || fail=1
+    set _ `ls -l B/xyzzy`; shift; actual_perms=$1
+    test "$actual_perms" = "$expected_no" || fail=1
+fi
+
+(exit $fail); exit $fail
2005-07-17  James Youngman  <[EMAIL PROTECTED]>

        * src/chmod.c (main): Implemented options -H, -L and -P.
        * tests/chmod/symlinks: tests for chmod options -H, -L and -P.
        
_______________________________________________
Bug-coreutils mailing list
Bug-coreutils@gnu.org
http://lists.gnu.org/mailman/listinfo/bug-coreutils

Reply via email to