]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
ls: treat --time=mtime consistently with other time selectors
authorPádraig Brady <P@draigBrady.com>
Thu, 27 Jun 2024 17:15:02 +0000 (18:15 +0100)
committerPádraig Brady <P@draigBrady.com>
Thu, 27 Jun 2024 17:37:23 +0000 (18:37 +0100)
* src/ls.c: Track if --time=mtime is explicitly specified,
so that we can apply the GNU extension of sorting by the
specified time, when not displaying (-l not specified),
and not explicitly sorting (-t not specified).
* tests/ls/ls-time.sh: Add / Update test cases.
Fixes https://bugs.gnu.org/71803

src/ls.c
tests/ls/ls-time.sh

index 5e2f7c3e764a33e6889dff34a2dfb3dbde7c6b77..f7ffe1086ef188afebf403c2634abd9486ead7d2 100644 (file)
--- a/src/ls.c
+++ b/src/ls.c
@@ -468,6 +468,7 @@ enum time_type
   };
 
 static enum time_type time_type;
+static bool explicit_time;
 
 /* The file characteristic to sort by.  Controlled by -t, -S, -U, -X, -v.
    The values of each item of this enum are important since they are
@@ -1943,6 +1944,7 @@ decode_switches (int argc, char **argv)
 
         case 'c':
           time_type = time_ctime;
+          explicit_time = true;
           break;
 
         case 'd':
@@ -2017,6 +2019,7 @@ decode_switches (int argc, char **argv)
 
         case 'u':
           time_type = time_atime;
+          explicit_time = true;
           break;
 
         case 'v':
@@ -2146,6 +2149,7 @@ decode_switches (int argc, char **argv)
 
         case TIME_OPTION:
           time_type = XARGMATCH ("--time", optarg, time_args, time_types);
+          explicit_time = true;
           break;
 
         case FORMAT_OPTION:
@@ -2372,18 +2376,12 @@ decode_switches (int argc, char **argv)
   if (eolbyte < dired)
     error (LS_FAILURE, 0, _("--dired and --zero are incompatible"));
 
-  /* If -c or -u is specified and not -l (or any other option that implies -l),
-     and no sort-type was specified, then sort by the ctime (-c) or atime (-u).
-     The behavior of ls when using either -c or -u but with neither -l nor -t
-     appears to be unspecified by POSIX.  So, with GNU ls, '-u' alone means
-     sort by atime (this is the one that's not specified by the POSIX spec),
-     -lu means show atime and sort by name, -lut means show atime and sort
-     by atime.  */
+  /* If a time type is explicitly specified (with -c, -u, or --time=)
+     and we're not showing a time (-l not specified), then sort by that time,
+     rather than by name.  Note this behavior is unspecified by POSIX.  */
 
   sort_type = (0 <= sort_opt ? sort_opt
-               : (format != long_format
-                  && (time_type == time_ctime || time_type == time_atime
-                      || time_type == time_btime))
+               : (format != long_format && explicit_time)
                ? sort_time : sort_name);
 
   if (format == long_format)
index f27a5dbbe9bf6d0f6f616c2a9478209afad628e1..be8a8355659f9df250801eb105b9ecb4dbe148bb 100755 (executable)
@@ -33,11 +33,15 @@ u2='1998-01-14 12:00'
 u3='1998-01-14 13:00'
 
 touch -m -d "$t3" a || framework_failure_
-touch -m -d "$t2" b || framework_failure_
+touch -m -d "$t2" B || framework_failure_  # Capital to distinguish name sort
 touch -m -d "$t1" c || framework_failure_
 
+# Check default name sorting works
+set $(ls a B c)
+test "$*" = 'B a c' || fail=1
+
 touch -a -d "$u3" c || framework_failure_
-touch -a -d "$u2" b || framework_failure_
+touch -a -d "$u2" B || framework_failure_
 # Make sure A has ctime at least 1 second more recent than C's.
 sleep 2
 touch -a -d "$u1" a || framework_failure_
@@ -47,7 +51,9 @@ touch -a -d "$u1" a || framework_failure_
 
 
 # A has ctime more recent than C.
-set $(ls -c a c)
+set $(ls -t -c a c)
+test "$*" = 'a c' || fail=1
+set $(ls -c a c)  # Not specified by POSIX
 test "$*" = 'a c' || fail=1
 
 # Sleep so long in an attempt to avoid spurious failures
@@ -93,13 +99,17 @@ EOF
   ;;
 esac
 
-set $(ls -ut a b c)
-test "$*" = 'c b a' && : || fail=1
-test $fail = 1 && ls -l --full-time --time=access a b c
-
-set $(ls -t a b c)
-test "$*" = 'a b c' && : || fail=1
-test $fail = 1 && ls -l --full-time a b c
+set $(ls -ut a B c)
+test "$*" = 'c B a' || fail=1
+set $(ls -u a B c)  # not specified by POSIX
+test "$*" = 'c B a' || fail=1
+test $fail = 1 && ls -l --full-time --time=access a B c
+
+set $(ls -t a B c)
+test "$*" = 'a B c' || fail=1
+set $(ls --time=mtime a B c)
+test "$*" = 'a B c' || fail=1
+test $fail = 1 && ls -l --full-time a B c
 
 # Now, C should have ctime more recent than A.
 set $(ls -ct a c)