summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/coreutils.texi17
-rw-r--r--src/ls.c5
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/d_type-check37
-rw-r--r--tests/init.cfg10
-rwxr-xr-xtests/ls/stat-free-color54
6 files changed, 124 insertions, 1 deletions
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 457ecabb2..b77d8dfda 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -7042,6 +7042,23 @@ Piping a colorized listing through a pager like @command{more} or
@command{less} usually produces unreadable results. However, using
@code{more -f} does seem to work.
+@vindex LS_COLORS
+@vindex SHELL @r{environment variable, and color}
+Note that using the @option{--color} option may incur a noticeable
+performance penalty when run in a directory with very many entries,
+because the default settings require that @command{ls} @code{stat} every
+single file it lists.
+However, if you would like most of the file-type coloring
+but can live without the other coloring options (e.g.,
+executable, orphan, sticky, other-writable, capability), use
+@command{dircolors} to set the @env{LS_COLORS} environment variable like this,
+@example
+eval $(dircolors -p | perl -pe \
+ 's/^((CAP|S[ET]|O[TR]|M|E)\w+).*/$1 00/' | dircolors -)
+@end example
+and on a @code{dirent.d_type}-capable file system, @command{ls}
+will perform only one @code{stat} call per command line argument.
+
@item -F
@itemx --classify
@itemx --indicator-style=classify
diff --git a/src/ls.c b/src/ls.c
index 4262923ce..54876ce42 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -2740,7 +2740,10 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
/* When coloring a directory (we may know the type from
direct.d_type), we have to stat it in order to indicate
sticky and/or other-writable attributes. */
- || (type == directory && print_with_color)
+ || (type == directory && print_with_color
+ && (is_colored (C_OTHER_WRITABLE)
+ || is_colored (C_STICKY)
+ || is_colored (C_STICKY_OTHER_WRITABLE)))
/* When dereferencing symlinks, the inode and type must come from
stat, but readdir provides the inode and type of lstat. */
|| ((print_inode || format_needs_type)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6a8b79dcb..9bff3f00f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -10,6 +10,7 @@ EXTRA_DIST = \
CuSkip.pm \
CuTmpdir.pm \
check.mk \
+ d_type-check \
envvar-check \
filefrag-extent-compare \
fiemap-capable \
@@ -426,6 +427,7 @@ TESTS = \
ls/rt-1 \
ls/stat-dtype \
ls/stat-failed \
+ ls/stat-free-color \
ls/stat-free-symlinks \
ls/stat-vs-dirent \
ls/symlink-slash \
diff --git a/tests/d_type-check b/tests/d_type-check
new file mode 100644
index 000000000..e40904907
--- /dev/null
+++ b/tests/d_type-check
@@ -0,0 +1,37 @@
+#!/usr/bin/python
+# Exit 0 if "." has useful d_type information, else 1.
+# Intended to exit 0 only on Linux/GNU systems.
+import sys
+
+fail = 1
+try:
+ import ctypes
+
+ (DT_UNKNOWN, DT_DIR,) = (0, 4,)
+
+ class dirent(ctypes.Structure):
+ _fields_ = [
+ ("d_ino", ctypes.c_long),
+ ("d_off", ctypes.c_long),
+ ("d_reclen", ctypes.c_ushort),
+ ("d_type", ctypes.c_ubyte),
+ ("d_name", ctypes.c_char*256)]
+
+ direntp = ctypes.POINTER(dirent)
+
+ # FIXME: find a way to hard-coding libc's so-name.
+ libc = ctypes.cdll.LoadLibrary("libc.so.6")
+ libc.readdir.restype = direntp
+
+ dirp = libc.opendir(".")
+ if dirp:
+ ep = libc.readdir(dirp)
+ if ep:
+ name = ep.contents.d_name
+ if (name == "." or name == "..") and ep.contents.d_type == DT_DIR:
+ fail = 0
+
+except:
+ pass
+
+sys.exit(fail)
diff --git a/tests/init.cfg b/tests/init.cfg
index 92f841f94..55d757175 100644
--- a/tests/init.cfg
+++ b/tests/init.cfg
@@ -322,6 +322,16 @@ fiemap_capable_()
python $abs_srcdir/fiemap-capable "$@"
}
+# Skip the current test if "." lacks d_type support.
+require_dirent_d_type_()
+{
+ python < /dev/null \
+ || skip_test_ python missing: assuming no d_type support
+
+ python $abs_srcdir/d_type-check \
+ || skip_test_ requires d_type support
+}
+
# Does the current (working-dir) file system support sparse files?
require_sparse_support_()
{
diff --git a/tests/ls/stat-free-color b/tests/ls/stat-free-color
new file mode 100755
index 000000000..d11c6f49c
--- /dev/null
+++ b/tests/ls/stat-free-color
@@ -0,0 +1,54 @@
+#!/bin/sh
+# Show that --color need not use stat, as long as we have d_type support.
+
+# Copyright (C) 2011 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/init.sh"; path_prepend_ ../src
+print_ver_ ls
+require_strace_ stat
+require_dirent_d_type_
+
+ln -s nowhere dangle || framework_failure_
+
+# Disable enough features via LS_COLORS so that ls --color
+# can do its job without calling stat (other than the obligatory
+# one-call-per-command-line argument).
+cat <<EOF > color-without-stat || framework_failure_
+RESET 0
+DIR 01;34
+LINK 01;36
+FIFO 40;33
+SOCK 01;35
+DOOR 01;35
+BLK 40;33;01
+CHR 40;33;01
+ORPHAN 00
+SETUID 00
+SETGID 00
+CAPABILITY 00
+STICKY_OTHER_WRITABLE 00
+OTHER_WRITABLE 00
+STICKY 00
+EXEC 00
+MULTIHARDLINK 00
+EOF
+eval $(dircolors -b color-without-stat)
+
+strace -o log -e stat,lstat ls --color=always . || fail=1
+n_lines=$(wc -l < log)
+test $n_lines = 1 || fail=1
+
+Exit $fail