Files
glibc/include/dirent.h
T
Adhemerval Zanella 99303f3871 io: Use gnulib fts implementation (BZ 22944, BZ 20331)
This patch synchronizes the glibc fts implementation with the latest
version from gnulib (as of 2026-02-16).

The primary motivation is to address limitations in the legacy glibc
implementation, most notably BZ 22944, where fts fails with an
ENAMETOOLONG error when traversing very long paths or deeply nested
directory trees.  The gnulib implementation dynamically reallocates
path buffers and uses openat/fchdir optimizations, effectively
lifting the MAXPATHLEN limitation.

The gnulib implementation also added extra features, which are
used by different GNU projects (coreutils, diffutils):

 * FTS_TIGHT_CYCLE_CHECK: used to enable a strict, immediate
   cycle-detection algorithm during a file system traversal.  This is
   done internally using a hash table: every time the traversal enters
   a directory, it records the directory's device and inode (dev/ino)
   pair in the hash table, and before entering any directory, fts
   checks the hash table.

 * FTS_CWDFD: instead of actually changing the process's current
   working directory, it maintains a virtual current working directory
   using file descriptors.  The file descriptor is store at the
   fts_cwd_fd field and all subsequent file operations are performed
   relative to this file descriptor using *at functions.

 * FTS_DEFER_STAT: performance-oriented flag that instructs the file
   tree traversal engine to delay fetching file metadata.  When the
   flag is used, fts skips the immediate stat call.  Instead, it marks
   the entry with a special internal state (FTS_NSOK and
   FTS_STAT_REQUIRED).  The actual stat call is pushed down the line
   and executed by fts_read right before the application actually
   accesses the entry.

 * FTS_VERBATIM: fts_open accept and use the path strings exactly as
   they were provided in the arguments array without slash trimming.

 * FTS_MOUNT: it restrict the file tree walk to a single file system.

Hopefully,it would allow some GNU projects to use the glibc
implementation instead of pulling the gnulib one.

It requires some changes to keep compatibility, compared to gnulib:

 * The new required fields are added at the end of FTS structure, and
   the new FTS flags are adjusted to avoid change FTS_NAMEONLY/FTS_STOP
   (even though they are marked as private).

 * The FTSENT uses a flexible array (fts_name), so two adjustments are
   required: the two new members (fts_fts and fts_dirp) are place
   *before* the struct and the fts_statp is now always allocated and
   accounted (the gnulib implementation uses an alwyas allocated member).

Checked on x86_64-linux-gnu and i686-linux-gnu.
2026-04-03 07:50:18 -03:00

91 lines
2.9 KiB
C

#ifndef _DIRENT_H
# ifndef _ISOMAC
# include <dirstream.h>
# endif
# include <dirent/dirent.h>
# ifndef _ISOMAC
# include <sys/stat.h>
# include <stdbool.h>
struct scandir_cancel_struct
{
DIR *dp;
void *v;
size_t cnt;
};
/* Now define the internal interfaces. */
extern DIR *__opendir (const char *__name) attribute_hidden;
extern DIR *__opendirat (int dfd, const char *__nam, int extra_flags,
int *pnew_fd) attribute_hidden;
extern DIR *__fdopendir (int __fd) attribute_hidden;
extern int __closedir (DIR *__dirp) attribute_hidden;
extern struct dirent *__readdir (DIR *__dirp) attribute_hidden;
extern struct dirent *__readdir_unlocked (DIR *__dirp) attribute_hidden;
extern struct dirent64 *__readdir64 (DIR *__dirp);
libc_hidden_proto (__readdir64)
extern int __readdir_r (DIR *__dirp, struct dirent *__entry,
struct dirent **__result);
extern int __readdir64_r (DIR *__dirp, struct dirent64 *__entry,
struct dirent64 **__result);
extern int __scandir64 (const char * __dir,
struct dirent64 *** __namelist,
int (*__selector) (const struct dirent64 *),
int (*__cmp) (const struct dirent64 **,
const struct dirent64 **));
extern __ssize_t __getdirentries (int __fd, char *__restrict __buf,
size_t __nbytes,
__off_t *__restrict __basep)
__THROW __nonnull ((2, 4));
/* These functions are only implemented on Linux. */
extern __ssize_t __getdents (int __fd, void *__buf, size_t __nbytes)
attribute_hidden;
extern __ssize_t __getdents64 (int __fd, void *__buf, size_t __nbytes);
libc_hidden_proto (__getdents64)
extern int __alphasort64 (const struct dirent64 **a, const struct dirent64 **b)
__attribute_pure__;
extern int __versionsort64 (const struct dirent64 **a,
const struct dirent64 **b)
__attribute_pure__;
extern DIR *__alloc_dir (int fd, bool close_fd, int flags,
const struct __stat64_t64 *statp)
__nonnull (4) attribute_hidden;
extern __typeof (rewinddir) __rewinddir;
extern __typeof (seekdir) __seekdir;
extern __typeof (dirfd) __dirfd;
libc_hidden_proto (dirfd);
extern void __scandir_cancel_handler (void *arg) attribute_hidden;
extern int __scandir_tail (DIR *dp,
struct dirent ***namelist,
int (*select) (const struct dirent *),
int (*cmp) (const struct dirent **,
const struct dirent **))
attribute_hidden;
# if !_DIRENT_MATCHES_DIRENT64
extern int __scandir_tail (DIR *dp,
struct dirent ***namelist,
int (*select) (const struct dirent *),
int (*cmp) (const struct dirent **,
const struct dirent **))
attribute_hidden;
# endif
extern int __scandir64_tail (DIR *dp,
struct dirent64 ***namelist,
int (*select) (const struct dirent64 *),
int (*cmp) (const struct dirent64 **,
const struct dirent64 **))
attribute_hidden;
libc_hidden_proto (__rewinddir)
extern __typeof (scandirat) __scandirat;
# if IS_IN (rtld)
extern __typeof (__rewinddir) __rewinddir attribute_hidden;
# endif
# endif
#endif