static char *color_buf;
/* True means to check for orphaned symbolic link, for displaying
- colors. */
+ colors, or to group symlink to directories with other dirs. */
-static bool check_symlink_color;
+static bool check_symlink_mode;
/* True means mention the inode number of each file. -i */
/* Test print_with_color again, because the call to parse_ls_color
may have just reset it -- e.g., if LS_COLORS is invalid. */
- if (print_with_color)
+ if (directories_first)
+ check_symlink_mode = true;
+ else if (print_with_color)
{
/* Avoid following symbolic links when possible. */
if (is_colored (C_ORPHAN)
|| (is_colored (C_EXEC) && color_symlink_as_referent)
|| (is_colored (C_MISSING) && format == long_format))
- check_symlink_color = true;
+ check_symlink_mode = true;
}
if (dereference == DEREF_UNDEFINED)
|| ((print_inode || format_needs_type)
&& (type == symbolic_link || type == unknown)
&& (dereference == DEREF_ALWAYS
- || color_symlink_as_referent || check_symlink_color))
+ || color_symlink_as_referent || check_symlink_mode))
/* Command line dereferences are already taken care of by the above
assertion that the inode number is not yet known. */
|| (print_inode && inode == NOT_AN_INODE_NUMBER)
}
if (S_ISLNK (f->stat.st_mode)
- && (format == long_format || check_symlink_color))
+ && (format == long_format || check_symlink_mode))
{
struct stat linkstats;
/* Avoid following symbolic links when possible, ie, when
they won't be traced and when no indicator is needed. */
if (linkname
- && (file_type <= indicator_style || check_symlink_color)
+ && (file_type <= indicator_style || check_symlink_mode)
&& stat (linkname, &linkstats) == 0)
{
f->linkok = true;
-
- /* Symbolic links to directories that are mentioned on the
- command line are automatically traced if not being
- listed as files. */
- if (!command_line_arg || format == long_format
- || !S_ISDIR (linkstats.st_mode))
- {
- /* Get the linked-to file's mode for the filetype indicator
- in long listings. */
- f->linkmode = linkstats.st_mode;
- }
+ f->linkmode = linkstats.st_mode;
}
free (linkname);
}
return f->filetype == directory || f->filetype == arg_directory;
}
+/* Return true if F refers to a (symlinked) directory. */
+static bool
+is_linked_directory (const struct fileinfo *f)
+{
+ return f->filetype == directory || f->filetype == arg_directory
+ || S_ISDIR (f->linkmode);
+}
+
/* Put the name of the file that FILENAME is a symbolic link to
into the LINKNAME field of 'f'. COMMAND_LINE_ARG indicates whether
FILENAME is a command-line argument. */
#define DIRFIRST_CHECK(a, b) \
do \
{ \
- bool a_is_dir = is_directory ((struct fileinfo const *) a); \
- bool b_is_dir = is_directory ((struct fileinfo const *) b); \
+ bool a_is_dir = is_linked_directory ((struct fileinfo const *) a);\
+ bool b_is_dir = is_linked_directory ((struct fileinfo const *) b);\
if (a_is_dir && !b_is_dir) \
return -1; /* a goes before b */ \
if (!a_is_dir && b_is_dir) \
--- /dev/null
+#!/bin/sh
+# test --group-directories-first
+
+# Copyright (C) 2018 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 <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+# Isolate output files from directory being listed
+mkdir dir dir/b || framework_failure_
+touch dir/a || framework_failure_
+ln -s b dir/bl || framework_failure_
+
+ls --group dir > out || fail=1
+cat <<\EOF > exp
+b
+bl
+a
+EOF
+compare exp out || fail=1
+
+ls --group -d dir/* > out || fail=1
+cat <<\EOF > exp
+dir/b
+dir/bl
+dir/a
+EOF
+compare exp out || fail=1
+
+Exit $fail