ls: fix output of dangling symlinks colored as target
authorPádraig Brady <P@draigBrady.com>
Sat, 1 Oct 2011 00:47:53 +0000 (01:47 +0100)
committerPádraig Brady <P@draigBrady.com>
Sat, 1 Oct 2011 01:15:12 +0000 (02:15 +0100)
This is related to commit b7f2b51c, 2010-01-01,
"ls: fix color of broken symlinks colored as target"
which didn't handle the --dereference case.
The simplest way to reproduce the resultant
erroneous "argetm" is as follows:

 $ ln -s /no-such dangle
 $ env LS_COLORS=ln=target ls --dereference --color
 ls: cannot access dangle: No such file or directory
 argetmdangle

This is also an issue with the `tree` utility,
reported here: http://bugs.debian.org/586765

* src/ls.c (print_color_indicator): Move the handling
of 'ln=target' in $LS_COLORS (color_symlink_as_referent == true)
to a higher scope, to handle all cases where type == C_LINK.
* tests/misc/ls-misc: Add a test case for the specific issue,
and 2 further test cases to verify other code paths in this area.

Reported by Jason Glassey.

src/ls.c
tests/misc/ls-misc

index c1b1918..1b0c250 100644 (file)
--- a/src/ls.c
+++ b/src/ls.c
@@ -4203,10 +4203,7 @@ print_color_indicator (const struct fileinfo *f, bool symlink_target)
             type = C_STICKY;
         }
       else if (S_ISLNK (mode))
-        type = ((!linkok
-                 && (color_symlink_as_referent
-                     || color_indicator[C_ORPHAN].string))
-                ? C_ORPHAN : C_LINK);
+        type = C_LINK;
       else if (S_ISFIFO (mode))
         type = C_FIFO;
       else if (S_ISSOCK (mode))
@@ -4241,6 +4238,14 @@ print_color_indicator (const struct fileinfo *f, bool symlink_target)
         }
     }
 
+  /* Adjust the color for orphaned symlinks.  */
+  if (type == C_LINK && !linkok)
+    {
+      if (color_symlink_as_referent
+          || color_indicator[C_ORPHAN].string)
+        type = C_ORPHAN;
+    }
+
   {
     const struct bin_str *const s
       = ext ? &(ext->seq) : &color_indicator[type];
index 8b356d4..b159bbf 100755 (executable)
@@ -223,6 +223,47 @@ my @Tests =
                     restore_ls_colors; }},
      ],
 
+     # Test for a bug fixed after coreutils-8.13
+     # where 'argetm' was errenously printed for dangling links
+     # when ln=target was used in LS_COLORS
+     ['sl-dangle6', '-L --color=always d',
+      {OUT => "s\n"},
+      {PRE => sub {mkdir 'd',0755 or die "d: $!\n";
+                   symlink 'dangle', 'd/s' or die "d/s: $!\n";
+                   push_ls_colors('ln=target')
+       }},
+      {POST => sub {unlink 'd/s' or die "d/s: $!\n";
+                    rmdir 'd' or die "d: $!\n";
+                    restore_ls_colors; }},
+      {ERR => "ls: cannot access d/s: No such file or directory\n"},
+      {EXIT => 1}
+     ],
+     # Related to the above fix, is this case where
+     # the code simulates "linkok".  In this case "linkmode"
+     # should always be zero, and hence not trigger any
+     # issues with type being set to C_LINK
+     ['sl-dangle7', '--color=always d',
+      {OUT => "$e\e[ms$e\n"},
+      {PRE => sub {mkdir 'd',0755 or die "d: $!\n";
+                   symlink 'dangle', 'd/s' or die "d/s: $!\n";
+                   push_ls_colors('ln=target:or=:ex=:')
+       }},
+      {POST => sub {unlink 'd/s' or die "d/s: $!\n";
+                    rmdir 'd' or die "d: $!\n";
+                    restore_ls_colors; }},
+     ],
+     # Another case with simulated "linkok", that does
+     # actually use the value of 'ln' from $LS_COLORS.
+     # This path is not taken though when 'ln=target'.
+     ['sl-dangle8', '--color=always s',
+      {OUT => "$e\e[1;36ms$e\n"},
+      {PRE => sub {symlink 'dangle', 's' or die "s: $!\n";
+                   push_ls_colors('ln=1;36:or=:')
+       }},
+      {POST => sub {unlink 's' or die "s: $!\n";
+                    restore_ls_colors; }},
+     ],
+
      # Test for a bug that was introduced in coreutils-4.5.4; fixed in 4.5.5.
      # To demonstrate it, the file in question (with executable bit set)
      # must not be a command line argument.