On 2026-04-13 09:15, Collin Funk wrote:
Also worth noting that if dracut only needs the file type it can
continue to use FTS_NOSTAT. In the Gnulib implementation
fts_statp->st_mode will be set to a file type based on the d_type from
readdir or set to 0 if unknown.

Yes, but that should be documented, otherwise callers can't rely on it. glibc document this stuff in in the public include headers, and these headers need better comments.

I noticed that Gnulib's fts.h documents this behavior for the new FTS_DEFER_STAT flag, but not for the existing FTS_NOSTAT flag that you mentioned, so I installed the attached patches into Gnulib. The first patch fixes FTS_DEFER_STAT to behave as per documentation even for roots after the first one (this matters for unlikely situations where the comparison function looks at a later root's file type); the second fixes the documentation to say that FTS_STAT acts like FTS_DEFER_STAT in the situation you're describing.

I think these patches should be propagated into glibc.

cc'ing bug-gnulib since it's a Gnulib change.

PS. This stuff should also be documented in the glibc manual, but that's a bigger change that we can do at our convenience.
From f5ee21eacc5be459a7d08b344196f2245a5de801 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Wed, 15 Apr 2026 14:45:53 -0700
Subject: [PATCH 1/2] fts: match doc for FTS_DEFER_STAT mode
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* lib/fts.c (fts_open): Clear fts_statp->fts_mode for the
FTS_DEFER_STAT case too, since it’s documented to work since 2008.
---
 ChangeLog | 6 ++++++
 lib/fts.c | 1 +
 2 files changed, 7 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 761d1edc0c..1145ad4fe2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2026-04-15  Paul Eggert  <[email protected]>
+
+	fts: match doc for FTS_DEFER_STAT mode
+	* lib/fts.c (fts_open): Clear fts_statp->fts_mode for the
+	FTS_DEFER_STAT case too, since it’s documented to work since 2008.
+
 2026-04-15  Bruno Haible  <[email protected]>
 
 	sigdelay: Add tests.
diff --git a/lib/fts.c b/lib/fts.c
index c61e8d89d8..daaa7d3e3c 100644
--- a/lib/fts.c
+++ b/lib/fts.c
@@ -485,6 +485,7 @@ fts_open (char * const *argv,
                    FTS_XDEV) requires that.  */
                 if (defer_stat && root != NULL) {
                         p->fts_info = FTS_NSOK;
+                        p->fts_statp->st_mode = 0;
                         fts_set_stat_required(p, true);
                 } else {
                         p->fts_info = fts_stat(sp, p, false);
-- 
2.53.0

From 9ab4bbed73172085c57b38a337d3dc279b1043b0 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Wed, 15 Apr 2026 14:47:55 -0700
Subject: [PATCH 2/2] doc: doc FTS_NOSTAT similarity to FTS_DEFER_STAT

* lib/fts.in.h (FTS_NOSTAT, FTS_DEFER_STAT):
Document that FTS_NOSTAT updates fts_statp->st_mode
similarly with FTS_DEFER_STAT.
---
 ChangeLog    |  5 +++++
 lib/fts.in.h | 14 ++++++++++----
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 1145ad4fe2..e3a2961cd1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2026-04-15  Paul Eggert  <[email protected]>
 
+	doc: doc FTS_NOSTAT similarity to FTS_DEFER_STAT
+	* lib/fts.in.h (FTS_NOSTAT, FTS_DEFER_STAT):
+	Document that FTS_NOSTAT updates fts_statp->st_mode
+	similarly with FTS_DEFER_STAT.
+
 	fts: match doc for FTS_DEFER_STAT mode
 	* lib/fts.c (fts_open): Clear fts_statp->fts_mode for the
 	FTS_DEFER_STAT case too, since it’s documented to work since 2008.
diff --git a/lib/fts.in.h b/lib/fts.in.h
index 9233111d57..c45cd63b0b 100644
--- a/lib/fts.in.h
+++ b/lib/fts.in.h
@@ -128,7 +128,15 @@ typedef struct {
 # define FTS_COMFOLLOW  0x0001          /* follow command line symlinks */
 # define FTS_LOGICAL    0x0002          /* logical walk */
 # define FTS_NOCHDIR    0x0004          /* don't change directories */
+
+  /* For efficiency do not set *fts_statp except for fts_statp->st_mode,
+     which is set to zero if the file type is unknown,
+     and which otherwise has at least its S_IFMT type bits set.
+     When fts_info == FTS_NSOK this supports expressions like
+     (fts_statp->st_mode ? !!S_ISDIR (fts_statp->st_mode): -1), which yields
+     1 for a directory, 0 for a non-directory, and -1 for unknown.  */
 # define FTS_NOSTAT     0x0008          /* don't get stat info */
+
 # define FTS_PHYSICAL   0x0010          /* physical walk */
 # define FTS_SEEDOT     0x0020          /* return dot and dot-dot */
 # define FTS_XDEV       0x0040          /* don't cross devices */
@@ -177,10 +185,8 @@ typedef struct {
      Use this flag to make fts_open and fts_read defer the stat/lstat/fststat
      of each entry until it is actually processed.  However, note that if you
      use this option and also specify a comparison function, that function may
-     not examine any data via fts_statp.  However, when fts_statp->st_mode is
-     nonzero, the S_IFMT type bits are valid, with mapped dirent.d_type data.
-     Of course, that happens only on file systems that provide useful
-     dirent.d_type data.  */
+     not examine any data via fts_statp, other than fts_statp->st_mode
+     which is set similarly to how FTS_NOSTAT behaves.  */
 # define FTS_DEFER_STAT         0x0400
 
   /* Use this flag to disable stripping of trailing slashes
-- 
2.53.0

Reply via email to