Forgot to attach the patches, sorry.

On Mon, Jul 13, 2026 at 11:17 AM James Youngman <[email protected]> wrote:
>
> These patches fix some test coverage issues for find -ls:
>
> 1. Improve detection of bugs on systems where the name of the user's
>    primary group is the same as their username.
> 2. Detect accidental changes to the spacing between fields.
> 3. Check the block count field of the -ls output.
>
From bb8e0b7805bcbf80d858bc8a02e27c10fdb413c2 Mon Sep 17 00:00:00 2001
From: James Youngman <[email protected]>
Date: Mon, 13 Jul 2026 09:27:09 +0100
Subject: [PATCH 1/2] maint: use a distinct group name in ls-format-file.sh if
 possible.

Also, check the block count.

* tests/find/ls-format-file.sh: where possible, set the test file up
such that its group owner is a group whose name is not the same as the
username of the current process.  Check the block count also.
---
 tests/find/ls-format-file.sh | 104 ++++++++++++++++++++++++++++-------
 1 file changed, 84 insertions(+), 20 deletions(-)

diff --git a/tests/find/ls-format-file.sh b/tests/find/ls-format-file.sh
index 9a9989d0..ec9f2331 100755
--- a/tests/find/ls-format-file.sh
+++ b/tests/find/ls-format-file.sh
@@ -28,11 +28,28 @@ LC_ALL=C
 export LC_ALL
 unset LANG
 
-# Create a test file with some known properties.
+user_owner="$( id -u -n )"
+if [ -z "${user_owner}" ]
+then
+    # This could mean that there is no entry in the password database.
+    skip_ "unable to determine username of the current user"
+fi
+
+# Create a test file with some known properties.  Because of
+# differences we cannot set a specific expectation for the number of
+# blocks occupied by a file, but we should be able to expect it to be
+# consistent with "ls -s".
 umask 077
+# If you change the value of testfile here to include any characters
+# special in either glob patterns or regular expressions, you will
+# need to re-check the tests in this file to ensure that they still do
+# what you want.
 testfile='lsme'
 filesize=765
 rm -f -- "${testfile}"
+# We get the data for the body from "yes" rather than /dev/zero just in case
+# the file system has some kind of optimization for files containing only
+# zero bytes (e.g. converting it to a hole).
 if ! ( yes non-empty | dd bs=1 count="${filesize}" of="${testfile}" ) 2>/dev/null
 then
     framework_failure_ "failed to create test file ${testfile}"
@@ -46,27 +63,62 @@ then
     framework_failure_ "failed to set mtime of ${testfile}"
 fi
 
-# Check the actual properties of the file (to verify that the setup
-# was successful).
-check_prop() {
-    printf_fmt="${1}"
-    expected="${2}"
-    got="$( find "${testfile}" -printf "${printf_fmt}" )"
-
-    if [ "${expected}" != "${got}" ]
+# The script may be running with an effective group id which has the
+# same name as the user's username.  This is inconvenient as we would
+# not detect cases where the user and group name are swapped, either
+# by find or by this test, or where the test checks against the wrong
+# value (as in 9d50e9964449fb5e9f3da84a7c19c29dbf001bb5).
+#
+# So, find a group of which the current user is a member and which, if
+# possible is not the same as the user's username.
+choose_distinct_group() {
+    chosen=N
+    unset group_name
+    for group_name in $(groups)
+    do
+        if [ "${group_name}" != "${user_owner}" ]
+        then
+            printf '%s\n' "${group_name}"
+            chosen=Y
+            break
+        fi
+    done
+    if [ "${chosen}" = N ]
     then
-	framework_failure_ "expected test file ${testfile} to have -printf '${printf_fmt}\n' result '${expected}' but we got '${got}'"
+        # The user's only group is the same as their username.
+        # Default to the last (and only unless two groups have the
+        # same name) group name in the output of groups.
+        echo "${group_name:-}"
     fi
 }
+group_owner="$(choose_distinct_group)"
+if [ -z "${group_owner}" ]
+then
+    # This is very unusual, because even if /etc/group has been
+    # deleted, id should have printed the numeric value of the user's
+    # primary group.  However, there are situations in which this
+    # could happen.  For example, getgid() can fail on GNU Hurd.
+    skip_ "unable to find a group of which the current user is a member"
+fi
 
-check_prop '%M' "-rw-------"  # file mode
-check_prop '%n' 1	      # link count
-check_prop '%s' "${filesize}" # size in bytes
-check_prop '%TF' "1992-03-14" # modification date
-check_prop '%TH:%TM' "19:00"  # modification time (without seconds)
+if ! chgrp "${group_owner}" "${testfile}"
+then
+    # There are some circumstances in which we cannot use a group in
+    # the filesystem even though getgroups(2) returns it.  An example
+    # is NFS version 2, on which the protocol limits the total number
+    # of group IDs that a process can use.  If I recall correctly the
+    # limit is 16.  Anyway, in this situation we will not claim that
+    # the test framework failed, because it is generally not going to
+    # be useful for the findutils maintainers to investigate these
+    # cases.  We also will not continue with a fallback value as these
+    # situations would be difficult to reproduce in the event of a bug
+    # report.
+    skip_ "failed to change group of ${testfile} to ${group_owner}"
+fi
 
 # Remember the file's inode number and block count.
-inum="$( find "${testfile}" -printf '%i\n')"
+inum="$( find "${testfile}" -printf '%i\n' )"
+blocks_expected="$( ls -s "${testfile}" | sed -e "s/${testfile}//g" )"
 # The system's value of BLOCKSIZE is implementation-dependent
 # ("ls -k" forces ls to use 1KiB blocks, but -ls is intended
 # to look like the output of ls -dils, without -k)
@@ -89,7 +141,13 @@ then
     fail_ "find -ls output does not end in newline"
 fi
 
-grep -e ' lsme$' < output.txt >/dev/null || fail_ "find -ls output should end with the file name"
+###############################################################################
+# Checks on the output fields generated by -ls, ignoring differences in the
+# number of spaces between fields.  If these tests break, this likely indicates
+# a bug in find.
+###############################################################################
+
+grep -e " ${testfile}"'$' < output.txt >/dev/null || fail_ "find -ls output should end with the file name"
 
 # The output is supposed to look like this:
 
@@ -108,9 +166,10 @@ awk < output.txt  \
     -v ME="${ME_}" \
     -v filename_expected="${testfile}" \
     -v inodenum="${inum}" \
+    -v blocks_expected="${blocks_expected}" \
     -v filesize="${filesize}" \
     -v uowner="$(id -un)" \
-    -v gowner="$(id -gn)" '
+    -v gowner="${group_owner}" '
 BEGIN {
       rv=2
 }
@@ -146,8 +205,13 @@ NR == 1 {
     printf("%s: failed test: expected inode number %d, got %s\n", ME, inodenum, $1);
   }
 
-  # field 2: size in blocks is ignored as we probably cannot assume
-  # any particular value for BLOCKSIZE.
+  # field 2: size in blocks
+  if (st_blocks != blocks_expected) {
+    rv=1
+    printf("%s: failed test: expected block count %d got %d\n", ME, blocks_expected, st_blocks);
+  } else {
+    printf("%s: block count %d looks OK\n", ME, st_blocks);
+  }
 
   # field 3 is the symbolic mode; we allow a final +
   # in case there is somehow a non-default ACL on the file.
-- 
2.47.3

From 67e926036e8f6857440af51ccce0f54081e426f1 Mon Sep 17 00:00:00 2001
From: James Youngman <[email protected]>
Date: Mon, 13 Jul 2026 09:49:06 +0100
Subject: [PATCH 2/2] maint: check spacing of fields in find -ls, and the block
 count.

* tests/find/ls-format-file.sh: check the output of -ls against the
output of a -printf format which should generate the same
output (though only for files which aren't symlinks or device nodes).
This serves as a guard against accidental changes to field widths.  If
an output field is incorrect, carry out the remaining test steps
anyway (but the test still fails). Remove redundant sanity-checks on
the properties of the test file. These were useful during development
of the test but for someone investigating a test failure, they are
distracting noise. Add a check for the block count field.
* tests/find/ls-format-symlink.sh: add a similar check.  If an output
field is incorrect, carry out the remaining test steps anyway (but the
test still fails).  Eliminate redundant test of the "a -> b" part of
the output.  Remove redundant sanity-checks on the properties of the
test file. Skip the test if we cannot create a symbolic link.
---
 tests/find/ls-format-file.sh    | 47 ++++++++++++++++--
 tests/find/ls-format-symlink.sh | 86 +++++++++++++++++++++++----------
 2 files changed, 103 insertions(+), 30 deletions(-)

diff --git a/tests/find/ls-format-file.sh b/tests/find/ls-format-file.sh
index ec9f2331..cee3737e 100755
--- a/tests/find/ls-format-file.sh
+++ b/tests/find/ls-format-file.sh
@@ -28,6 +28,11 @@ LC_ALL=C
 export LC_ALL
 unset LANG
 
+# We set fail to a nonzero value to indicate that one of the test
+# steps showed a difference between the expected and actual behaviour
+# (that is, the test failed).
+fail=0
+
 user_owner="$( id -u -n )"
 if [ -z "${user_owner}" ]
 then
@@ -149,18 +154,19 @@ fi
 
 grep -e " ${testfile}"'$' < output.txt >/dev/null || fail_ "find -ls output should end with the file name"
 
-# The output is supposed to look like this:
+# The output is supposed to look like this (though we've removed
+# consecutive spaces here):
 
 # st_ino  st_blocks
 # |       | symbolic st_mode
 # |       | |          st_nlink
 # |       | |          |  Username corresponding to st_uid
-# |       | |          |  |    Group corresponding to st_gid
+# |       | |          |  |    Group name corresponding to st_gid
 # |       | |          |  |    |     Size in bytes
 # |       | |          |  |    |     |   st_mtime
 # |       | |          |  |    |     |   |            file name
 # |       | |          |  |    |     |   |            |
-# 4485432 1 -rw------- 1 james james 765 Mar 14  1992 lsme
+# 4485432 1 -rw------- 1 james group 765 Mar 14  1992 lsme
 
 awk < output.txt  \
     -v ME="${ME_}" \
@@ -283,4 +289,37 @@ END {
 '
 rv=$?
 echo "Awk exit status was ${rv}"
-Exit "${rv}"
+if [ "${rv}" -ne 0 ]
+then
+    warn_ "${ME_}: one of the field values was incorrect (see above) so the test will eventually fail, but we will carry out the remaining test steps anyway"
+    fail=1
+fi
+
+
+###############################################################################
+# Checks on the output generated by -ls, including the spaces between
+# fields.  If these tests break, this may indicate a bug in find, or
+# alternatively a deliberate change to the spacing of the output
+# (e.g. a deliberate change to lib/listfile.c).  If you are
+# deliberately changing the output spacing, it is OK to update the
+# tests below to reflect this.  If not, this is likely an
+# unintentional change which you should investigate.
+###############################################################################
+
+# Generate "by hand" in the file printf-output.txt some output which
+# should match the output of -ls.
+rm -f -- printf-output.txt
+if ! find "${testfile}" -printf '%9i %6b %M %3n %-8u %-8g %8s %3Tb %2Td %5TY %p\n' > printf-output.txt
+then
+    framework_failure_ "unable to create printf-output.txt"
+fi
+
+if ! compare printf-output.txt output.txt
+then
+    # The detailed nature of the problem should already be visible in
+    # the diff output we just emitted into the log.
+    fail=1
+    warn_ "${ME_}: the output of the -ls action seems to be incorrect"
+fi
+
+Exit "${fail}"
diff --git a/tests/find/ls-format-symlink.sh b/tests/find/ls-format-symlink.sh
index 6bf17599..c240ac47 100755
--- a/tests/find/ls-format-symlink.sh
+++ b/tests/find/ls-format-symlink.sh
@@ -28,17 +28,29 @@ LC_ALL=C
 export LC_ALL
 unset LANG
 
+# We set fail to a nonzero value to indicate that one of the test
+# steps showed a difference between the expected and actual behaviour
+# (that is, the test failed).
+fail=0
+
 # Create a test file with some known properties.
 umask 077
+# Note that symlink_target and symlink should not contain characters
+# which are special to find -printf.  It's best also to avoid
+# characters which are special to the shell, too.
 symlink_target='target'
 symlink='symlink'
+
 filesize=765
 rm -f -- "${symlink_target}" "${symlink}"
 if ! ( yes non-empty | dd bs=1 count="${filesize}" of="${symlink_target}" ) 2>/dev/null
 then
     framework_failure_ "failed to create test file ${symlink_target}"
 fi
-ln -s "${symlink_target}" "${symlink}"
+if ! ln -s "${symlink_target}" "${symlink}"
+then
+    skip_ "unable to create a symbolic link"
+fi
 
 # Any specific time for the test will do as long as it is far enough
 # away from now for ls to display the year.  This happens to be the
@@ -53,32 +65,12 @@ then
     framework_failure_ "failed to set mtime of ${symlink}"
 fi
 
-# Check the actual properties of the file (to verify that the setup
-# was successful).
-check_prop() {
-    printf_fmt="${1}"
-    expected="${2}"
-    got="$( find "${symlink}" -printf "${printf_fmt}" )"
-
-    if [ "${expected}" != "${got}" ]
-    then
-	framework_failure_ "expected test file ${symlink} to have -printf '${printf_fmt}\n' result '${expected}' but we got '${got}'"
-    fi
-}
-
-check_prop '%M' "lrwxrwxrwx"  # file mode
-check_prop '%n' 1	      # link count
-check_prop '%s' 6             # size in bytes (length of "target")
-check_prop '%TF' "1999-12-31" # modification date
-check_prop '%TH:%TM' "23:59"  # modification time (without seconds)
-
 # Remember the file's inode number and block count.
 inum="$( find "${symlink}" -printf '%i\n')"
 # The system's value of BLOCKSIZE is implementation-dependent
 # ("ls -k" forces ls to use 1KiB blocks, but -ls is intended
 # to look like the output of ls -dils, without -k)
 
-
 # Generate the ls output.
 find "${symlink}" -ls > output.txt
 
@@ -88,15 +80,20 @@ cat output.txt
 echo "same thing in od -c format:"
 od -c output.txt
 
-# Determine whether there is a trailing newline.  If not, output.txt
-# is not actually a text file and some other checks may not work the
-# way we expect.
+# Determine whether there is a trailing newline.
 if [ $(sed -n -e '$ s/.*//p'  < output.txt | wc -c) -eq 0 ]
 then
+    # If we get to here, output.txt is not actually a text file and
+    # some other checks may not work the way we expect, so we stop
+    # now.
     fail_ "find -ls output does not end in newline"
 fi
 
-grep -e ' symlink -> target$' < output.txt >/dev/null || fail_ "find -ls output should end with symlink -> target"
+###############################################################################
+# Checks on the output fields generated by -ls, ignoring differences in the
+# number of spaces between fields.  If these tests break, this likely indicates
+# a bug in find.
+###############################################################################
 
 # The output is supposed to look like this:
 
@@ -230,4 +227,41 @@ END {
 '
 rv=$?
 echo "Awk exit status was ${rv}"
-Exit "${rv}"
+if [ "${rv}" -ne 0 ]
+then
+    warn_ "${ME_}: one of the field values was incorrect (see above) so the test will eventually fail, but we will carry out the remaining test steps anyway"
+    fail=1
+fi
+
+
+###############################################################################
+# Checks on the output generated by -ls, including the spaces between
+# fields.  If these tests break, this may indicate a bug in find, or
+# alternatively a deliberate change to the spacing of the output
+# (e.g. a deliberate change to lib/listfile.c).  If you are
+# deliberately changing the output spacing, it is OK to update the
+# tests below to reflect this.  If not, this is likely an
+# unintentional change which you should investigate.
+###############################################################################
+
+# Generate "by hand" in the file printf-output.txt some output which
+# should match the output of -ls.  Take care when updating the format
+# string, because it is interpreted both by the shell (as it uses
+# double-quotes) then also by find -printf.
+rm -f -- printf-output.txt
+if ! find "${symlink}" \
+    -printf "%9i %6b %M %3n %-8u %-8g %8s %3Tb %2Td %5TY ${symlink} -> ${symlink_target}\n" \
+    > printf-output.txt
+then
+    framework_failure_ "unable to create printf-output.txt"
+fi
+
+if ! compare printf-output.txt output.txt
+then
+    # The detailed nature of the problem should already be visible in
+    # the diff output we just emitted into the log.
+    fail=1
+    warn_ "${ME_}: the output of the -ls action seems to be incorrect"
+fi
+
+Exit "${fail}"
-- 
2.47.3

Reply via email to